Podklady z mého Nix & NixOS workshopu na InstallFestu 2024.
Základy práce s Nixem
Instalace
- Oficiální instalátor: https://nixos.org/download/#download-nix
- Determinate Nix installer:
https://zero-to-nix.com/start/install
- Robustnější
- Nastaví rozumně
nix.conf
(flakes, trusted user) - Telemetrie :-(
Základní příkazy
- Starý nix:
nix-build
,nix-shell
,nix-env
- (-) částečně nekonzistentní přepínače u různých příkazů
- (+) stabilní, dostupná široká funkcionalita
- Experimentální příkaz:
nix
nix build
,nix develop
,nix profile
- (-) je potřeba explicitně povolit:
nix --experimental-features 'nix-command flake'
- konfigurační soubor:
~/.config/nix/nix.conf
- (-) nestabilní, na stabilizaci se pracuje
- (+) konzistentnější přepínače
- (+) TAB-doplňování názvů attributů
Nixpkgs
- Největší repozitář open-source software
- 90 tisíc balíků
- https://github.com/NixOS/nixpkgs/
- https://search.nixos.org/packages
Použití balíku z nixpkgs:
which htop nix-shell -p htop nix shell nixpkgs#htop which htop
Jak použít libovolnou verzi SW?
Použít starší větev nixpkgs:
nix shell nixpkgs/nixos-23.05#htop htop --version exit
- Použít libovolný commit z nixpkgs:
https://lazamar.co.uk/nix-versions/ – zkusíme verzi 3.0.5:
nix-shell -p htop -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/f8f124009497b3f9908f395d2533a990feee1de8.tar.gz nix shell nixpkgs/f8f124009497b3f9908f395d2533a990feee1de8#htop htop --version exit
- Použít aktuální nixpkgs, ale zkompilovat proti tomu starší verzi htopu
- Musí se upravit atribut
src
v “definici” balíku
- Musí se upravit atribut
”Override” atributů v definici balíku
Je lepší si na to vytvořit soubor
shell.nix
:with import <nixpkgs> {}; mkShell { packages = [ bashInteractive (htop.overrideAttrs (old: { src = fetchFromGitHub { owner = "htop-dev"; repo = old.pname; rev = "3.1.0"; hash = ""; # smazat hash!!! }; })) ]; }
- Spustit
nix-shell
a doplnit hash podle chybové hlášky Otestujeme:
nix-shell htop --version which htop
- Aby i název cesty v
/nix/store
obsahoval správnou verzi, je potřeba změnit i atributversion
Změna více atributů
Přidání
version
(nezapomenout narec
)with import <nixpkgs> {}; mkShell { packages = [ bashInteractive (htop.overrideAttrs (old: rec { version = "3.1.0"; src = fetchFromGitHub { owner = "htop-dev"; repo = old.pname; rev = version; hash = "sha256-/48Ca7JPzhPS4eYsPbwbSVcx9aS1f0LHcqsbNVWL+9k="; }; })) ]; }
- Občas je potřeba změnit i jiné atributy (závislosti, configure flags, …)
Jak vytvořit balíček?
- Použít nástroj
nix-init
pro vytvoření kostry balíku.- Výstup předpokládá, že tvoříme balík pro nixpkgs, což je funkce,
která bude zavolána v rámci
callPackage
z nixpkgs. - Pokud chceme balík mimo nixpkgs, můžeme nahradit parametr funkce
(
{...}:
) zawith import <nixpkgs> {};
- Výstup předpokládá, že tvoříme balík pro nixpkgs, což je funkce,
která bude zavolána v rámci
Zkusíme balík přeložit (pravděpodobně to nepůjde bez úprav):
nix-build
Výsledek uvidíme za symlinkem
result
:ls -l ./result/
- Typické úpravy
default.nix
:- Přidání závislostí (
buildInputs
,nativeBuildInputs
,propagatedBuildInputs
, …) - Nastavení parametrů pro
./configure
,make
,cmake
,meson
apod. - Instalace do
$out
- Patchování nekompatibilit s Nixem
- Přidání závislostí (
- Neocenitelný pomocník:
nix-shell
(bez -p) nebonix develop
:
Ladění pomocí nix-shell/nix develop
nix-shell # Všechny atributy derivation dostupné jako proměnné prostředí echo $version echo $src # Vlastní sestavení balíku je (v nixpkgs) realizováno funkcí genericBuild type genericBuild type buildPhase genericBuild # interaktivní řešení problémů
Příklad
Vygenerujeme kostru pomocí
nix-init
$ nix-init --url https://pypi.org/project/pynostr/ Enter tag or revision (defaults to 0.6.2) ❯ 0.6.2 Enter version ❯ 0.6.2 Enter pname ❯ pynostr How should this package be built? ❯ 1 - buildPythonPackage Enter output path (leave as empty for the current directory) ❯ .
Vytvoříme
shell.nix
, kam balík natáhneme volánímcallPackage
:with import <nixpkgs> {}; mkShell { packages = [ bashInteractive (python3Packages.callPackage ./default.nix {}) ]; }
Otestujeme (a zjistíme, že kostru v
default.nix
už není potřeba upravovat):$ nix-shell $ python from pynostr.key import PrivateKey private_key = PrivateKey() public_key = private_key.public_key print(f"Private key: {private_key.bech32()}") print(f"Public key: {public_key.bech32()}")
Vlastní distribuce založená na NixOS
- Myšlenka NixOSu
- Linuxová distribuce = balík, který závisí na jiných balících + konfigurační soubory, aby spolu balíky dobře fungovaly
- Nix je dobrý v kompilaci balíků a řešení závislostí, abychom měli Linuxovou distribuci, potřebujeme vyřešit konfiguraci
- NixOS = Nix kód pro automatické generování konfiguračních souborů
Vlastní distribuce
Vytvoříme soubor
configuration.nix
{ config, pkgs, ... }: { boot.loader.systemd-boot.enable = true; networking.hostName = "InstallFest"; time.timeZone = "Europe/Prague"; services.openssh.enable = true; services.xserver.enable = true; services.xserver.displayManager.lightdm.enable = true; services.xserver.desktopManager.xfce.enable = true; environment.systemPackages = with pkgs; [ emacs wget ]; users.users.alice = { isNormalUser = true; extraGroups = [ "wheel" ]; # secret hashedPassword = "$6$UeUi3mis.Na253Zz$l3RlyTEn8ZI0eFUgyJAwjvxr.TMx8rZc1sP/2qbKke1p4fxbSLx2iQ1mV5Qot3p9mofxWcPLxSnH/ciOYo3Pu0"; packages = with pkgs; [ firefox thunderbird ]; }; documentation.nixos.enable = false; system.stateVersion = "23.11"; }
nix-shell -p nixos-rebuild # Test the system in a VM nixos-rebuild build-vm --no-flake -I nixos-config=$PWD/configuration.nix ./result/bin/run-InstallFest-vm # Deploy to a remote NixOS computer nixos-rebuild switch --no-flake -I nixos-config=$PWD/configuration.nix --target-host example.com
Testování s nixos-shell
- Nástroj
nixos-shell
(neplést snix-shell
) vytvoří VM dle NixOS konfigurace v souboru./vm.nix
(default), nabootuje jí v qmeu vm.nix
{ config, pkgs, ... }: { networking.hostName = "InstallFest"; environment.systemPackages = with pkgs; [ htop ]; documentation.nixos.enable = false; system.stateVersion = "23.11"; }
nix-shell -p nixos-shell nixos-shell
Kontejnery bez zbytečného balastu
- Kontejnery se často generují z Alpine Linuxu – používá malou musl libc
S Nixem můžete snadno docílit toho samého:
nix-build --expr 'with (import <nixpkgs> {}); ministat' nix-tree ./result/ # 30 MB nix-build --expr 'with (import <nixpkgs> {}).pkgsMusl; ministat' nix-tree ./result/ # 3 MB nix-build --expr 'with (import <nixpkgs> {}).pkgsStatic; ministat' nix-tree ./result/ # 80 kB
Tvorba Docker kontejneru z libovolných Nix balíků
Vytvoříme soubor
default.nix
s následujícím obsahem:{ pkgs ? import <nixpkgs> {} }: pkgs.dockerTools.buildImage { name = "ministat"; tag = "latest"; config = { Cmd = [ "${pkgs.ministat}/bin/ministat" ]; }; }
${pkgs.ministat}
můžeme nahradit${pkgs.pkgsStatic.ministat}
Spuštění v kontejneru
nix-build docker load < result docker run -it ministat
Layered image
- Místo
dockerTools.buildImage
lze použítdockerTools.buildLayeredImage
, který dá každý Nix balík do samostatné vrstvy (pokud jich není víc než 256). - Zlepší upload časy změněného obrazu
Binární kompatibilita s FHS distribucemi
- buildFHSEnv
- nix-ld
- envfs
- buildFHSEnv – binárky použitelné jinde
patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 a.out
- build proti staré glibc
- Použít starší nixpkgs
- Zkusit https://github.com/wheybags/glibc_version_header