Skip to content

Latest commit

 

History

History
230 lines (144 loc) · 21.2 KB

4.Nix-Package-Manager.md

File metadata and controls

230 lines (144 loc) · 21.2 KB

Nix Paket Yöneticisi (Nix Öğreniyoruz 4)

Bir önceki makalemizde yalın olarak Nix dilinin temel yapılarını ve syntax'ını öğrendik. Bu makalemizde ise Nix'in varsayılan paket repo'su ve kaynak kolaksiyonu olan nixpkgs'yi ve bu paket sistemi ile birlikte gelen lib fonksiyonlarını öğreneceğiz. Bunları öğrenebilmek için de nix paket yöneticisini detaylı bir şekilde inceleyeceğiz.

  1. NixOS: İşletim Sistemlerine Fonksiyonel Yaklaşım
  2. Nix Dili ve Özellikleri
  3. Nix Dili ile ilgili Alıştırmalar
  4. Nix Dilinde Builtins Fonksiyonlar
  5. Nix Paket Yöneticisi
  6. Nix Paket Yöneticisi Shell, Profile Kavram ve Komutları
  7. Nix Flake Nedir?
  8. Birden Çok Paketi Aynı Repo Üzeriden Yayınlamak
  9. Override ve Overlay Kavramları
  10. Nix Paket Yöneticisi ile Developer ve Profile Ortamları Oluşturmak
  11. Nix ile NixOs Konfigürasyonu
  12. NixOs Module ve Option Kullanımı
  13. NixOs Kurulumu ve Konfigürasyonu
  14. NixOs'u Cloud ve Uzak Ortamlara Deploy Etmek

Nix dilinde builtins ve Nixpkgs içindeki lib modülü, temelde farklı amaçlara hizmet eden fonskiyonlar içerirler. İşlev ve kullanım açısından temel farklar şunlardır:

  1. builtins: Bu, Nix dilinin temel modülüdür ve bir dizi genel amaçlı fonksiyon içerir. Bu fonksiyonlar, temel veri türleri üzerinde çalışmak, hata kontrolü yapmak, liste işlemleri gerçekleştirmek ve benzeri temel işlemleri gerçekleştirmek için kullanılır. Örnekler arasında length, elem, attrNames, concatLists gibi fonksiyonlar yer alır. Daha önce zaten çok detaylı incelemiştik.

    Örnek:

    let
      myList = [1 2 3];
      listLength = builtins.length myList;
    in
      listLength  # 3
  2. lib (Nixpkgs içinde): Nixpkgs, geniş bir Nix paket koleksiyonunu içeren bir depodur ve lib modülü, paket geliştirme ve oluşturma süreçlerini kolaylaştırmak için bir dizi yardımcı fonksiyon içerir. Bu fonksiyonlar, genellikle paket oluştururken veya paketler arasında ortak işlemleri gerçekleştirirken kullanılır. Örnekler arasında fetchurl, buildInputs, stdenv.mkDerivation gibi fonksiyonlar yer alır.

    Örnek:

    { lib, fetchurl }:
    
    lib.mkDerivation rec {
      pname = "example";
      version = "1.0";
      src = fetchurl {
        url = "https://example.com/source.tar.gz";
        sha256 = "...";
      };
    }

Genel olarak, builtins daha genel amaçlı ve temel işlemler için kullanılırken, lib fonksiyonları genellikle Nix paket oluşturma süreçlerinde ve daha karmaşık senaryolarda kullanılmaktadır.

Öncelikle Nix dilinde module, package, channel ve derivation kavramlarına teorik olarak değinip ardından uygulamalarımıza geçelim.

Nix Dilinde Package ve Derivation Kavramı

Nix dilinde "package" ve "derivation" terimleri farklı kavramları ifade eder. İşte bu iki terim arasındaki temel farklar:

  1. Package (Paket):

    • "Package", genellikle bir yazılım veya kütüphanenin kullanılabilir ve yüklenilebilir bir formunu ifade eder.
    • Bir paket, belirli bir sürümü ve yapılandırmayı temsil eder. Örneğin, bir dilin belirli bir sürümü, bir kütüphanenin belirli bir sürümü veya bir uygulamanın belirli bir yapılandırması bir paket olabilir.
    • Paketler, genellikle Nixpkgs deposunda tanımlanan paket tarifleri (package expressions) kullanılarak oluşturulur. Bu tarifler, paketin nasıl derleneceği, yapılandırılacağı ve yükleneceği gibi bilgileri içerir.
  2. Derivation (Türetim):

    • "Derivation", bir paketin nasıl inşa edileceğini ve yükleneceğini tanımlayan bir Nix ifadesidir.
    • Bir derivation, bir paket tarifini içerir ve bu tarife dayanarak belirli bir sürümü, belirli bağımlılıkları ve derleme yönergelerini içeren bir inşa sürecini tanımlar.
    • Derivations, genellikle stdenv.mkDerivation fonksiyonu kullanılarak oluşturulur. Bu fonksiyon, paketin derleme, kurulum ve diğer aşamalarda kullanılacak talimatları belirtmek için kullanılır.
    • Derivations, genellikle nix-build veya nix-shell gibi Nix araçları kullanılarak inşa edilir ve paketin oluşturulmuş halini sağlarlar.

Özetle, "package" bir kullanılabilir yazılım veya kütüphane bütününü temsil ederken, "derivation" bu paketin nasıl inşa edileceğini ve yükleneceğini tanımlayan bir Nix ifadesidir. Bir "package" genellikle bir "derivation" ile oluşturulur. Build aldığımızda drv (derivation) uzantılı bir dosya oluşur. Ancak, bu .drv dosyası, derlenmiş paketin kendisi değildir, sadece paketin derlenmesi için gerekli talimatları içerir. Gerçek derlenmiş dosyalar ve kütüphaneler, türetim (paket oluşturma) sona erdiğinde nix-store'da belirli bir benzersiz klasöre yerleştirilir. /nix/store dizininde bir çok drv uzantılı dosya görebilirsiniz. İçlerine bakacak olursanız tamda bahsedildiği gibi bazı dosya ve klasör isimleri ile birlikte konfigürasyonlar görebilirsiniz.

Kafanızın karıştığını tahmin edebiliyorum. Daha önce duymadığımız kavramlar, kütüphane ve fonksiyon isimleri duyduk ancak merak etmeyin hepsini bu makalede anlayacağız.

Biz kurulum yaptığımızda da aslında bu drv uzantılı dosya okunarak program ilgili dizinlere kurulur.

Bu süreç şu adımlardan meydana gelir.

  1. Paket Tarifinin Alınması (fetch): Nix, paketin tarifini almak için Nixpkgs deposundan (import <nixpkgs> {} kullanılarak) veya bir URL, Git deposu gibi kaynaklardan paket tarifini çeker.

  2. Derivation Oluşturma (nix-build veya benzeri araçlar kullanılarak): Alınan paket tarifi, bir "derivation"ı (türetim) temsil eder. Bu türetim, belirli bir sürümü, bağımlılıkları, derleme talimatlarını ve diğer gerekli bilgileri içerir. nix-build veya benzeri araçlar kullanılarak bu türetim inşa edilir.

  3. Derivation'ın Oluşturduğu .drv Dosyası: Derleme süreci tamamlandığında, bu süreç .drv uzantılı bir dosya oluşturur. Bu dosya, derlenmiş paketin inşa edildiği talimatları içerir. Ancak, bu dosya hala derlenmiş paketin kendisi değildir; sadece türetim talimatlarını içerir.

  4. Derleme Sonucu (realize/instantiation): Derleme sonucunda, .drv dosyasının içerdiği talimatlar kullanılarak /nix/store dizininde bir benzersiz klasöre derlenmiş dosyalar, kütüphaneler ve diğer çıktılar yerleştirilir. Bu süreç, "realize" veya "instantiation" adını alır.

  5. Paketin Kullanılabilir Hale Getirilmesi (nix profile, nix shell vs.): Derlenmiş paketin bulunduğu klasör, Nix araçları (örneğin, nix profile veya nix shell) kullanılarak sistemde kullanılabilir hale getirilir. Bu, paketi sistem genelinde kullanılabilir kılar veya bir özel ortam içinde kullanılmasını sağlar.

Bu süreç, Nix'in fonksiyonel ve deklaratif paket yönetim modelini temsil eder. Paket tarifleri (package expressions) deklaratif bir şekilde paketin nasıl oluşturulacağını ifade eder, ve bu ifadeleri kullanarak sistemdeki paketleri oluşturmak ve yönetmek mümkün olur.

Sonuç olarak Nix için paket demek aslında bir programın kurulabilmesi için gerekli derleme talimatlarının olduğu bir dosyadır. Bu dosya ile programın kurulumu yapılır.

Flakes Kavramı

Nix Flake, Nix paket yöneticisinde bir dizi gelişmiş özellik sunan bir özelliktir. Flake, Nix dilindeki paketleri, modülleri ve konfigürasyonları daha etkili bir şekilde yönetmek için tasarlanmıştır. Flake, özellikle projeleri ve paketleri tanımlamak, paylaşmak ve bir arada tutmak için tasarlanmış bir yapı sunar. Flake'lar kullanılarak paket oluşturma, bağımlılıkları yönetme ve dağıtma işlemleri standart hale getirilmiş oluyor. Flake'leri tam karşılığı olmasa da NodeJs'deki gibi package.json dosyası veya dotnet'deki csproj dosyasına benzetebiliriz. Flake biraz daha geniş kapsamlı bir kavram bir nevi hem proje dosyamız hem de çalıştırılabilir kodlarımızın olduğu bir yapıdır.

İlerleyen başlıklarda sadece flake kavramı ile ilgili bir yazımız olacak zaten. Şimdilik bu konuya bu kadar değineceğiz. Amacımız sadece uygulamalara geçtiğimizde ne neydi, ne işe yarardı bunu anlayacak kadar öğrenmek.

Nixpkgs tam olarak nedir?

Öncelikle NixOs'u incelerken dokümanlarda sıklıkla karşılaşacağınız Channel kavramından bahsedelim. Farklı repo kaynaklarına channel diyoruz. Diğer Linux distro'larındaki repo kavramına benzer bir yapısı var diyebiliriz. Channel'ları yönetmek için nix-channel komutu kullanılır. Channel'ın diğer Linux dağıtımlarındaki repo kavramından farkı channel'ın aslında aynı repo olsa dahi farklı versiyon veya branch'i işaret ediyor olmasıdır. Ancak mantık olarak yine de aynıdır diyebiliriz. Channel web sayfasına https://channels.nixos.org/ adresinden ulaşabilirsiniz. Ayrıca channel'ların durumunu görmek için de şu linki kullnabilirsiniz: https://status.nixos.org/

Ancak channel sistemindeki problemler nedeniyle artık nix registry kullanılıyor. Bunun temelini de flake yapısı oluşturuyor. Flake'ler lock dosyası kullanarak bağımlılıkları ve versiyonları daha iyi yönetiyor. Örnek nix dosyalarında nixpkgs adıyla import ettiğimiz modul aslında bir flake'dir. Flake web sayfası ise bildiğimiz bir GitHub reposudur. Sayfaya https://github.com/NixOS/nixpkgs adresinden ulaşabilirsiniz. Bu yapıda aynı reponun klonlarına veya farklı branch'lerine erişmemiz artık mümkün. Ne kadar esnek bir yapı sunduğunu anlayabiliyoruz.

Bu arada tekrar hatırlatmak istiyorum. Bu makaleyi yazarken baskın bir şekilde her yerde nix-* ile başlayan komutlar göreceksiniz. Bunlardan biri de nix-channel olacak. Neredeyse makalede kullandığım komut ve anlatımlar için özel çaba sarfetmeniz gerekebilir. Ancak şuan unstable/experimental bile olsa verdiğim komutlar öyle görünüyor ki Nix'in geleceği olacak.

Biz path olarak nixpkgs'i verdiğimizde aslında sistem bu GitHub repo'sunu import ediyor ve root dizininde bulunan flake.nix ile nested bir şekilde yani iç içe geçen bütün flake'lari sisteme tanıtıyor.

Hatırlarsanız ilk makalemizde path veri tipinden bahsetmiştik. Bu veri tipi ile bir dizindeki dosya ve klasörleri tanımlayabiliyorduk. Eğer import ederken path veri tipini kullanırsak, bu dizindeki dosya ve klasörlerin içeriğini import edebiliyoruz.

Bundan başka Nix dilinde birde lookup path adında bir tanımlayıcı var. Lookup (veya search) path belirtilen adresteki dosyalarda tarama yapma ve uygun olanları import etme imkanı sağlıyor. Eğer import <nixpkgs> {}; bir satır görecek olursak bu aslında nixpkgs burada /nix/var/nix/profiles/per-user/root/channels/nixpkgs adresini temsil eder. Eğer bu dizine gidecek olursanız all-packages.nix adında bir dosya göreceksiniz. Bu dosyada bütün paketlerin kategorilerini olduğu klasör adresleri vardır. Bu dosyaya bakacak olursak bir çok nix path'inin import edildiğini görebiliriz. Yani sistem bir ağaç gibi hep bir başka dalı (diğer bir nix dosyasını) import eder. import <nixpkgs> {} ifadesi, Nixpkgs deposundaki birçok şeyi içeri aktarır. Bu ifade, sadece varsayılan paketlerle sınırlı değildir; aynı zamanda builtins gibi temel Nix fonksiyonlarını ve lib gibi kütüphane modüllerini de içerir.

Bu arada /nix/var/nix/profiles/per-user/root/channels/nixpkgs dizini bile aslıda /nix/store dizinindeki bir klasörün symbolic linkidir. Bu disinin bir üst dini yani /nix/var/nix/profiles/per-user/root/channels dizinine gidecek olursanız birde manifest.ix dosyası var. Bu dosyayı inceleyecek olursak nixpkgs'nin hangi klasöre linklendiğini görebiliriz. Bu dizin aynı zamanda $HOME/.nix-defexpr/channels dizinine de linklenmişti. Aktif kullanıcının home dizinindeki .nix-defexpr dizini de nixpkgs'nin linklendiği dizinlerden biridir.

[ { 
  meta = { }; 
  name = "nixpkgs"; 
  out = { outPath = "/nix/store/64bdf02ly4azvh14x139g4k2ip2gciqy-nixpkgs"; }; 
  outPath = "/nix/store/64bdf02ly4azvh14x139g4k2ip2gciqy-nixpkgs"; 
  outputs = [ "out" ]; 
  system = "builtin"; 
  type = "derivation"; 
  } ]

Sonuç olarak biz import <nixpkgs> {}; satırını yazdığımızda sistem bahsettiğimiz dizinlerde arama yaparak bütün modülleri yükler. Moduller ile paket bilgilerini alırız, derivation'lar ile ile paketleri türetiriz ve bu paketleri de nix yardımıyla kurarız. Her modül de bir çalıştırabilir bir uygulama olmak durumunda değildir. nixpkgs içinde örneğin bir çok kullanışlı fonksiyon bulunur. Bizzat bu fonksiyonlar kullanılarak paketler oluşturulur. Hatta ileride göreceğimiz NixOs bile bu modüller sayesinde ayarlanır.

Bazı önemli dizinlere ve dosyalara bir göz atalım.

  • /etc/nix/nix.conf dosyasına bir bakalım. Bu dosya sistemin genelini ve bütün kullanıcıları etkileyecek ayarları içerir. Bu dosyada yapılabilecek ayarlar için şu sayfaya bakılabilir.

  • Diğer önemli path ise ~/.local/state/nix/profiles dizinidir. Burada ileride göreceğimiz nix profile (komutun eski adı nix-env) komutu ile kurduğumuz paketleri için oluşturulan profillerin listesini görebiliriz. Profiles klasörüne bakacak olursak /nix/store/ dizini altındaki klasörlere symbolic link atıldığını görebiliriz.

total 28K
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 14 Ara  8 23:54 profile -> profile-6-link
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 51 Ara  8 22:32 profile-1-link -> /nix/store/kmkkizwfx283fi3qd3hr2chng0vfciqj-profile
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 51 Ara  8 22:40 profile-2-link -> /nix/store/yjj04vvlp82mwc2k6gvn81p8d5kb6djb-profile
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 51 Ara  8 22:58 profile-3-link -> /nix/store/f62qw3gch5zn4fghxdanys6awc8qjbfl-profile
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 51 Ara  8 22:59 profile-4-link -> /nix/store/0cg7hc464p55cj7l9jgpr7x8314jq7hr-profile
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 51 Ara  8 23:04 profile-5-link -> /nix/store/kmkkizwfx283fi3qd3hr2chng0vfciqj-profile
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 51 Ara  8 23:54 profile-6-link -> /nix/store/0zdsafjgba7przfxl43vwq8pb9r9xkyb-profile

Her bir profil dizini altında manifest.json birde manifest.nix adında bir dosya bulunur. Json doyasını nix profile kullanırken nix dosyasını nix-env kullanır. Nix profile nix-env in yeni deneysel sürümüdür. Biz de profil üzerinden devam edeceğiz ilerleyen konularda.

json dosya içeriğine baktığımızda ilgili kurulum yapıldığında hangi paketlerin kurulduğunu görebiliriz. Bu aslında o profilin state (durum) bilgisidir.

cat profile-4-link/manifest.json

{"elements":[{"active":true,"attrPath":"legacyPackages.x86_64-linux.hello","originalUrl":"flake:nixpkgs","outputs":null,"priority":5,"storePaths":["/nix/store/sbldylj3clbkc0aqvjjzfa6slp4zdvlj-hello-2.12.1"],"url":"github:NixOS/nixpkgs/09ec6a0881e1a36c29d67497693a67a16f4da573"},{"active":true,"attrPath":"legacyPackages.x86_64-linux.mysql","originalUrl":"flake:nixpkgs","outputs":null,"priority":5,"storePaths":["/nix/store/jklrlmy6zwkp4426n33jz7px2s8aldvq-mariadb-server-10.11.6","/nix/store/zhl095f59vk97sbx3rcmw965zlr45zpy-mariadb-server-10.11.6-man"],"url":"github:NixOS/nixpkgs/09ec6a0881e1a36c29d67497693a67a16f4da573"},{"active":true,"attrPath":"legacyPackages.x86_64-linux.mysql","originalUrl":"github:nixos/nixpkgs/nixpkgs-unstable","outputs":null,"priority":5,"storePaths":["/nix/store/jklrlmy6zwkp4426n33jz7px2s8aldvq-mariadb-server-10.11.6","/nix/store/zhl095f59vk97sbx3rcmw965zlr45zpy-mariadb-server-10.11.6-man"],"url":"github:nixos/nixpkgs/09ec6a0881e1a36c29d67497693a67a16f4da573"},{"active":true,"attrPath":"legacyPackages.x86_64-linux.mysql","originalUrl":"github:nixos/nixpkgs/nixpkgs-unstable","outputs":null,"priority":5,"storePaths":["/nix/store/jklrlmy6zwkp4426n33jz7px2s8aldvq-mariadb-server-10.11.6","/nix/store/zhl095f59vk97sbx3rcmw965zlr45zpy-mariadb-server-10.11.6-man"],"url":"github:nixos/nixpkgs/09ec6a0881e1a36c29d67497693a67a16f4da573"}],"version":2}%   

#----------Kısaltıldı

Aktif profil ise ~/.nix-profile dizinindedir.

ls -la ~/ | grep nix-profile

lrwxrwxrwx 1 grop_adi kullanici_adi     50 Eki 16 18:56 .nix-profile -> /home/kullanici_adi/.local/state/nix/profiles/profile

User-environments

Ayrıca sistem çalimaya başladığında aktif kullanıcının default profil bilgisi /nix/var/nix/profiles dizinindeki default dosyasına yazılır.

ll /nix/var/nix/profiles
total 4,0K
lrwxrwxrwx 1 root root 43 Eki 16 16:31 default -> /nix/var/nix/profiles/per-user/root/profile
drwxr-xr-x 1 root root  8 Eki 16 16:31 per-user

Diğer kullanıcıların profile bilgileri de per-user dizinin de bulunabilir. Root için profile dizini de buradadır.

  • Diğer önemli path ise ~/.nix-defexpr dizinidir. Bu dizinin de içeriğine bakacak olursak kullandığımız paket listelerini (channels) burada bulabiliriz.
ll  ~/.nix-defexpr/

lrwxrwxrwx 1 kullanici_grubu kullanici_adi 51 Eki 21 23:04 channels -> /home/kullanici_adi/.local/state/nix/profiles/channels
lrwxrwxrwx 1 kullanici_grubu kullanici_adi 44 Eki 21 23:04 channels_root -> /nix/var/nix/profiles/per-user/root/channels

Ayrıca sistem ilk ayağa kalktığında burada yer alan nix dosyalarını okur ve çalıştırır. Genellikle açılış dosyası olarak default.nix adında dosya oluşturulur. Bu dosya kendi içinde diğer dosyaları da çağırabilir (import edebilir). Örneğnn ileride göreceğimiz overlay dosyalarını buraya ekleyipo default.nix dısyasına import edebiliriz.

  • Nix bu kadar profile ve birden fazla kullanıcıyı yönetebilmek için sqlite kullanır. Dosyaya /nix/var/nix/db/db.sqlite dizininden erişilebilir

Nix, paket yönetimi ve paket türetilmesi için kullanılan bir sistemdir ve bu sistemde SQLite, metadata (meta veri) ve derleme bilgilerini depolamak için kullanılan bir veritabanı olarak tercih edilir. SQLite, hafif, taşınabilir ve kullanımı kolay bir veritabanı motorudur. Nix, paket yönetimi ve türetilmiş ürünleri izlemek için bu tür bir veritabanına ihtiyaç duyar.

İşte Nix'in SQLite kullanımındaki bazı avantajlar:

  1. Hafif ve Taşınabilir: SQLite, hafif bir veritabanı motorudur ve tek bir dosya içinde depolanabilir. Bu, sistemde ek bir sunucu veya büyük bir yapılandırmaya ihtiyaç olmadan kullanımı kolay ve taşınabilir bir çözüm sunar.

  2. Yerel Depolama: SQLite, paket bilgilerini ve türetilmiş ürün bilgilerini yerel bir depoda (örneğin /nix/store) saklamak için kullanılır. Bu, paketlerin ve türetilmiş ürünlerin hızlı ve yerel bir şekilde erişilebilir olmasını sağlar.

  3. İzolasyon ve Güvenlik: Her Nix paketi, kendi özel /nix/store dizininde saklanır ve SQLite veritabanı bu paketlerin metadata ve derleme bilgilerini izler. Bu izolasyon, paketlerin birbirinden bağımsız olmasını ve bir paketin diğerine müdahale etmesini engeller.

  4. Hızlı Sorgular ve İndeksleme: SQLite, sorgular ve indeksleme konusunda iyi bir performans sergiler. Bu, Nix'in paket bilgilerini hızlı bir şekilde sorgulamasına ve türetilmiş ürünlerle ilgili bilgileri etkili bir şekilde yönetmesine olanak tanır.

Dİkkat ederseniz halen NixOs işlemi sistemine halen hiç değinmedik. Anlayebileceğiniz üzere Nix paket yöneticisinin temel derdi hakikaten paket yönetimi mevzusunu çözebilmek. Bütün Linux distro'larında kullanılabilecek, farklı ortamların izole bir iekilde oluturulabildiği ve deklaratif olarak tekrar tekrar kurulum yapabilen bir paket yöneticisi zannediyorum hepimizn hayalidir.

Evet bu yazımıda bu kadar. Nix paket yönetcisini teori ve consept olarak incelemiş olduk. Bir sonraki yazımızda shelli pofile ve develop gibi kavramları ve komutlarını göreceğiz. Artık Nix paket yöneticisinin bize sunduğu kolaylıkları deneyimleyebileceğiz.

Nix'in resmi paket reposu ve bu repo'yu Nix paket yöneticisinin nasıl yönettiğini daha detaylı anlamak isterseniz resmi readme dosyasını ve katkıda bulunmak isteyenler için hazırlanmış contributing dosyasını okumanızı tavsite ederim.

Kaynaklar