Nix : Package manager et gestionnaire de configuration
Posté le 12/10/2024 dans Linux
Bon, c'est parti pour un article pas du tout prévu, mais c'est tellement un banger que je me dois d'en parler.
Je viens de découvrir le package manager Nix, et quelle claque !
À une époque, j'avais jeté un œil à GNU Guix et à son langage Guile, qui semblaient intéressants. Mais j'ai laissé tomber car la doc était imbuvable et ça ne semblait pas encore au point.
Puis j'ai appris récemment que Guix venait en fait de Nix et que, pour le coup, Nix était à nouveau en vogue à cause de NixOS. Un collègue m'a poussé à creuser et je n'ai pas été déçu.
Pour faire simple, Nix est un gestionnaire de paquets qui peut s'installer sur n'importe quelle distro et permet d'installer des paquets récents indépendamment de la distro. Tu peux donc rester sur Debian stable et utiliser la dernière version de Neovim grâce à Nix, par exemple.
Tout est géré dans un répertoire indépendant, /nix, et son fonctionnement peut faire penser à Git dans le sens où tout est versionné. Tu peux donc faire des rollbacks si l'installation d'un paquet s'est mal passée.
Nix
Pour commencer, tu peux installer Nix sur ta machine avec la commande suivante :
sh <(curl -L https://nixos.org/nix/install) --daemon
nix --version
On va y aller étape par étape en prenant des cas d'usage intéressants en allant du plus simple au plus compliqué.
Pour tester que tout marche bien, on va commencer par utiliser un environnement shell de nix pour installer et utiliser des paquets.
nix-shell -p cowsay lolcat
Après avoir exécuter cette commande, tu te retrouves dans un shell avec cowsay et lolcat d'installés. Tu peux les tester via :
[nix-shell:~]$ cowsay Hello, Nix! | lolcat
Tu devrais voir un joli Hello, Nix! en couleur. Une fois que tu quittes le shell, les paquets sont désinstallés. On est ici dans un cas d'environnement shell temporaire.
Il y a énormément de paquets disponibles, tu peux les chercher via le lien https://search.nixos.org/.
Script
Place aux cas d'usage.
Premier cas : tu veux balancer un script en prod, mais tu n'as pas les droits d'installer des paquets car tu n'es pas root. Ce genre de cas arrive très souvent en entreprise, surtout lorsque l'on est dev et pas admin sys ou devops.
Avec Nix, il y a moyen d'installer temporairement des paquets juste le temps d'exécution du script, de cette manière, dans un fichier type monscript.sh :
#!/usr/bin/env nix-shell
#! nix-shell -i bash --pure
#! nix-shell -p bash cacert curl jq python3Packages.xmljson
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/2a601aafdc5605a5133a2ca506a34a3a73377247.tar.gz
curl https://github.com/NixOS/nixpkgs/releases.atom | xml2json | jq .
Tu vas utiliser ici les shebangs pour préciser les paquets nécessaires à l'exécution du script et tu pointes vers une version précise de Nix pour être sûr de pouvoir reproduire le script à l'identique, peut importe la machine sur laquelle tu l'installes.
Et voilà, la magie va opérer. Tu vas pouvoir bénéficier de curl, xml2json et jq.
Une fois le script exécuté, les paquets installés et nix seront supprimés.
C'est beaucoup plus simple que de gérer des Dockerfile !
Devenv
En parlant de Docker, tu peux utiliser la librairie Devenv pour gérer des environnements de dev avec Nix directement, en te passant de Docker Compose !
Pour l'installer, rien de plus simple.
nix-env -iA devenv -f https://github.com/NixOS/nixpkgs/tarball/nixpkgs-unstable
Voici un cas simple pour un environnement Angular dans un fichier devenv.nix :
{ pkgs, lib, config, inputs, ... }:
{
# https://devenv.sh/basics/
env.GREET = "devenv";
# https://devenv.sh/packages/
packages = [
pkgs.git
pkgs.nodejs_20
];
# https://devenv.sh/languages/
# languages.rust.enable = true;
# https://devenv.sh/processes/
processes.angular.exec = "npm run start";
# https://devenv.sh/services/
# services.postgres.enable = true;
# https://devenv.sh/scripts/
scripts.install-angular-cli.exec = ''
mkdir -p ~/.npm-global
npm config set prefix '~/.npm-global'
export PATH=~/.npm-global/bin:$PATH
if ! npm list -g @angular/cli | grep @angular/cli@17; then
npm install -g @angular/cli@17
fi
'';
scripts.build-api.exec = ''
./gradlew assemble
'';
scripts.install-app.exec = ''
npm install
'';
enterShell = ''
install-angular-cli
build-api
install-app
'';
# https://devenv.sh/tests/
enterTest = ''
echo "Running tests"
git --version | grep --color=auto "${pkgs.git.version}"
node --version | grep --color=auto "${pkgs.nodejs_20.version}"
ng version | grep "17"
./gradlew --version | grep "Gradle 7.4.2"
'';
# https://devenv.sh/pre-commit-hooks/
# pre-commit.hooks.shellcheck.enable = true;
# See full reference at https://devenv.sh/reference/options/
}
Tu peux ici gérer ta version de node, de npm et de angular et lancer des commandes d'installation et de build à l'entrée dans le shell, comme des npm install ou des ./gradlew assemble.
Il y a même une petite partie permettant de faire des tests pour être sûr que tout est bien configuré.
Tu peux ensuite lancer ton environnement avec la commande :
devenv up
Il va alors tout installer, tout builder et lancer automatiquement la commande npm run start.
Tu peux aussi faire un devenv shell pour entrer directement dans l'environnement shell.
Mais il est également possible de gérer tes services de base de données et autres, comme pour Docker Compose ! Sauf que tu n'es pas dans un container, mais dans un sous-shell directement. Tu peux voir la partie services qui est commenté dans mon fichier.
Attention, ça signifie que ce sont donc bien les fichiers de ton système que tu manipules lorsque tu lances des commandes.
Home Manager
Alors là, c'est mon préféré, la cerise sur le gâteau.
Tu vas pouvoir gérer tout ton home et en faire une description précise dans un fichier Nix pour le rendre reproductible.
Tu peux installer des paquets et gérer tes dotfiles au même endroit !
Je m'en sers ici pour installer mon terminal, VS Code, Neovim et toute la configuration qui va avec.
Commence par installer home-manager :
nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
nix-channel --update
nix-shell '<home-manager>' -A install
. "$HOME/.nix-profile/etc/profile.d/hm-session-vars.sh"
Puis tu créés un fichier ~/.config/home-manager/home.nix pour y décrire toute ta configuration :
{ config, pkgs, ... }:
let
secrets =
if builtins.pathExists "/home/morgan/.config/home-manager/secrets.nix"
then import /home/morgan/.config/home-manager/secrets.nix
else { };
in
{
nixpkgs = {
config = {
allowUnfree = true;
allowUnfreePredicate = (_: true);
};
};
programs.home-manager.enable = true;
home.username = "morgan";
home.homeDirectory = "/home/morgan";
home.stateVersion = "24.05";
home.packages = with pkgs; [
devenv
# Fonts
fira-code
fira-code-symbols
(nerdfonts.override { fonts = [ "FiraCode" ]; })
# Terminal
guake
tdrop
wmctrl
st
atuin
starship
# Programming languages
nodejs_20
go
python312
pipx
poetry
ruff
black
pyright
rustc
rustfmt
cargo
rust-analyzer
clippy
zig
lua
# Tools
httpie
wget
jq
curl
ffmpeg
htop
xclip
bats
ripgrep
tmux
eza
bat
fd
tree
peek
rsync
gh
zip
unzip
unrar
transmission
# Network
traceroute
tcpdump
];
home.file = { };
home.sessionVariables = {
# User configuration
EDITOR = "nvim";
LANG = "fr_FR.UTF-8";
# Chrome
CHROME_BIN = "/usr/bin/chromium";
CHROME_EXECUTABLE = "/usr/bin/chromium";
# Node.js
NODE_OPTIONS = "--max-old-space-size=4096";
# Rust
RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
# Jenkins
JENKINS_URL = "${secrets.JENKINS_URL}";
JENKINS_USER_ID = "${secrets.JENKINS_USER_ID}";
JENKINS_API_TOKEN = "${secrets.JENKINS_API_TOKEN}";
};
home.sessionPath = [
"$HOME/.local/bin"
];
programs = {
git = (import ./git.nix { inherit pkgs; });
neovim = (import ./neovim.nix { inherit pkgs; });
fish = (import ./fish.nix { inherit pkgs; });
vscode = (import ./vscode.nix { inherit pkgs; });
zoxide = {
enable = true;
enableFishIntegration= true;
options = [
"--cmd cd"
];
};
zellij = {
enable = true;
settings = {
copy_command = "xclip -selection clipboard";
paste_command = "xclip -selection clipboard -o";
};
};
};
fonts.fontconfig.enable = true;
}
Ici j'utilise nix pour installer mes paquets via home.packages, gérer mes variables d'environnement via home.sessionVariables et mes dotfiles via programs. Tu peux noter que j'utiliser une fichier /home/morgan/.config/home-manager/secrets.nix pour y mettre mes mots de passe et autres secrets.
Pour les programmes qui nécessitent une configuration spécifique, j'utilise des fichiers .nix que j'importe dans mon fichier principal :
- git.nix pour gérer ton username, ton mail ou tes alias.
- neovim.nix pour gérer tes plugins et ta configuration.
- fish.nix qui est mon shell par défaut.
- vscode.nix pour gérer tes extensions et ta configuration.
Tu peux ensuite appliquer ta configuration avec la commande :
home-manager switch
Et voilà, tu as tout ton home configuré à ta sauce, et tu peux le reproduire à l'identique sur n'importe quelle machine.
Note qu'il y a pas mal de nouveaux outils écrit en Rust que j'utilise. Ça pourra faire de futurs petits articles dessus si ça t'intéresse !
NixGL
On utilise principalement le home-manager pour gérer son terminal. Mais il est également possible de l'utiliser pour des applications qui utilise openGL. Par défaut, sans utiliser NixOS mais Debian par exemple, les applications openGL ne fonctionnent pas directement avec Nix.
Il existe alors un petit wrapper openGL appelé NixGL qui permet de faire fonctionner les applications comme alacritty par exemple.
Tu l'installes via :
nix-channel --add https://github.com/nix-community/nixGL/archive/main.tar.gz nixgl && nix-channel --update
nix-env -iA nixgl.auto.nixGLDefault
Tu utilises alors ce wrapper pour exécuter alacritty si tu l'as installé via home-manager :
nixGL alacritty
C'est un petit point gênant qui me donne envie de réellement migrer sur NixOS.
NixOS
Pour finir, la dernière étape serait de virer ma Debian et de migrer intégralement sur NixOS, la distro intégralement gérée par Nix. Pour le moment, j'ai encore certains besoins de Debian à cause de mon taf, mais dès que possible, je migrerai sûrement dessus.
Jette un œil sur la partie NixOS : the Linux distribution du site officiel.
Tu peux alors avoir l'intégralité de ton système géré par un fichier de configuration Nix, que ça soit pour les paquets, les services, la configuration réseau ou les utilisateurs.
Voilà, j'espère t'avoir donné envie de découvrir Nix ! Il y a beaucoup de choses, et le piège est de ne pas savoir par quel bout commencer ! Je te conseille vraiment de faire comme moi, étape par étape, petit à petit.
Un fois pris au jeu, tu verras, tu ne pourras plus t'en passer !