Voici un apperçu de pourquoi j’ai été vite convaincu de passer définitivement à NixOs après plus de 20 ans de satisfaction avec Debian. Sans aucun regret.
Quand j’étais jeune le débat était: programmation spaghetti vs programmation structurée. Ça parait irréel mais quand on a 1ko de mémoire et 8ko de rom l’art du jonglage est plus prisé que l’art de la structure. Aujourd’hui le débat est programmation procédurale vs programmation fonctionnelle pure. Ce ne sera plus un débat dans quelques dizaines d’années et on se demandera comme les gens ne voyait pas cette évidence.
On vit la même chose pour les distributions: ça a commencé par pas grand chose de plus que le référencement de fichiers tar pour devenir de plus en plus conceptuel afin d’apporter de la cohérence, de la sécurité et de l’ergonomie. Un saut majeur est réalisé par NixOs. Le même saut que le passage de la programmation procédurale à la programmation fonctionnelle pure (qui est au cœur de NixOs).
NixOs a une représentation conceptuelle de la distribution: une installation est le résultat d’une fonction pure qui prend en argument la description de ce que vous désirez avoir. En pratique vous décrivez ce que vous désirez avoir dans des fichiers dans /etc/nixos et nixos fait le travail.
Par exemple:
- Pas de “apt-get install thunderbird”, vous écrivez “thunderbird” dans une liste dans un des fichiers dans /etc/nixos. Donc vous n’avez plus à mémoriser ce que vous avez installé ou configuré, tout est dans /etc/nixos. Gros SOULAGEMENT!
- Vous pouvez raisonner par fonctionnalité, par exemple vous pouvez créer un lib/httpd.nix qui s’occupera de configurer les packages qui doivent être installés, les règles firewalls, les services systemd supplémentaires personnels etc.
- Même si vous installez apache2, tout se fait dans /etc/nixos, mais vous pouvez reprendre des grandes parties de configuration apache, on peut voir NixOs comme, entre autres, une surcouche à toutes les configurations se trouvant dans etc.
- Fini les problèmes de configuration du type “il faut mettre ça avant ça” ou “ce flag est à true donc on ne peut pas définir ce paramètre”: Le langage Nix est mathématique et les incohérences sont détectées ou impossibles.
- NixOs fournit une archive de taille paramétrable des installations antérieures, donc si vous avez cassé quelque chose il suffit de booter sur une ancienne version (le menu du boot est mis à jour).
- D’un ordinateur on peut en configurer et gérer d’autres (ou des conteneurs), autant que l’on veut. Fini l’IP de la gateway ou le nom du réseau local dupliqué: vous pouvez l’écrire à un endroit unique.
- Dupliquer l’installation d’une mahine est super simple puisqu’elle est entièrement et précisément décrite.
- Quand la syntaxe de configuration d’un logiciel est archaïque (comme pour l’excellent rsnapshot), vous pouvez utiliser le langage Nix pour contourner les problèmes en générant des morcaux de la configuration par des fonctions nix.
- NixOs compartimente les paquets, cela évite les problèmes d’incompatibilité et permet d’installer plusieurs versions (par exemple plusieurs PosgreSQL ou plusieurs apache2). Fini les “je veux bien t’installer ceci mais il faudra déinstaller cela”. Pour optimiser l’espace pris il permet quand même de partager par liens hard des fichiers identiques entre paquets.
- Le côté très structuré favorise la sécurité. Par exemple créer un paquet est une description : url des sources, dépendances etc. Les possibilités d’introduire des vulnérabilités sont réduites. Par exemple pour apache2, ce fichier nix décrit la création du package (accessible par le lien “Source” sur https://search.nixos.org/packages). Il devient bien plus facile de vérifier que le mainteneur n’a pas introduit de vulnérabilité.
- NixOs pousse à bien faire les choses, mais sans exagérer. Jusqu’à présent cela m’a aidé sans me gêner. Par exemple :
- On est obligé d’utiliser git pour /etc/nixos
- Il détecte les impuretés (l’utilisation d’éléments hors /etc/nixos non déclarés)
- Il examine les parties de scripts bash dans la configuration nix et informe d’erreurs ou warnings.
Quelques concepts
Un fichier .nix
Votre répertoire /etc/nixos (le chemin est un standard mais il peut être ailleur) sera peuplé de fichiers “.nix” que vous organisez comme vous le souhaitez. Un “.nix” est simplement un bout de code en langage Nix même si souvent ça ressemble à un fichier de configuration. Et comme Nix est un langage fonctionnel le contenu d’un .nix sera une valeur (un nombre, un ensemble d’attributs etc) ou une fonction (retournant en général un ensemble d’attributs). Cela rend la description de vos machines très libre. Souvent un .nix est une fonction, par exemple:
{ host }: { boot_partition="BOOT_RESC"; root_partition="rescue"; pruneGenerations = host.zone.pruneGenerations; }
La partie “{ host }”: indique que c’est une fonction à un argument, cet argument est un semble d’attribut avec un seul attribut (host). Le reste “{ …. }” est la valeur retournée par la fonction, ici un ensemble d’attributs.
Vous verrez souvent des .nix commençant par “{pkgs,lib,…}”, cela signifie que l’argument est un ensemble d’attributs devant définir pkgs et lib mais pouvant contenir d’autres attributs (le “,…”).
Mais ce .nix est aussi valide “{x,y}:x+y”, cette fonction prend en argument une ensemble d’attributs et retourne la somme des attributs x et y. On peut fournir les arguments sans passer par un ensemble d’attributs, par exemple “x : y : x+y” est une fonction prenant deux argument (x et y) et retournant la somme.
/etc/nixos/flake.nix
Quand on utilise Flakes (c’est optionnel mais devient un standard), le fichier flake.nix (nom conventionnel) contient la description des différents ordinateurs. Pour que NixOs fournisse une fonction pure (sans effet de bord) alors que les paquets peuvent changer, il faut fournir en argument les paramètres décrivant “de quoi on part”. C’est pourquoi un flake.nix comporte deux parties: inputs et outputs. C’est à dire : de quoi ont part et ce que l’on obtient. Donc vous dites que vous partez de telle version de NixOs (inputs) et dans outputs vous décrivez les machines que vous désirez.
Dans ce petit exemple on part de la distribution instable de NixOs et de “nur” puis ont décrit les machines (une seule ici). “mysystem” est le nom de la machine, elle est décrite dans “configuration.nix” et pourra utiliser “inputs” comme argument dans ses fonctions.
Pour que ce flake.nix soit une fonction pure il manque une chose: en effet la distribution change et produirait donc des installations différentes. C’est pourquoi un /etc/nixos/flake.lock est créé automatiquement à la première interprétation pour fixer la release exacte. Donc si vous recopier votre /etc/nixos sur une autre machine cela produira la même installation aux mêmes versions de logiciels.
Le principe de Flakes sert aussi à tout ce qui “produit à partir de”. Par exemple on peut l’utiliser produire un package.
Le type “chemin”
Nix a un type “chemin”. C’est logique et très pratique mais un peu “tricky” au début, car:
- On peut ajouter un chemin plus une chaîne (pas l’inverse), par exemple ./. + “host” est le chemin ./host
- Un chemin relatif est relatif à l’endroit du fichier qui le définit et … le reste! C’est étrange au début car inhabituel. Par exemple si dans host/miami/host.nix on définit “host_base=./.;”, un code nix dans /lib utilisant host_base récupèrera le chemin relatif à lui de host/miami et non simplement “./.” comme ça le serait dans d’autres langages.
Organisation
Nous avons vu que nous pouvons organiser la configuration de manière très libre. Voici une base d’organisation que je trouve confortable et puissante. Imaginons la gestion de toutes les machines de GreenPeace:
- zone/<nom-zone>/host/<nom-machine>: le répertoire de configuration d’une machine. On découpe en zones, par exemple “paris” pour le siège à Paris ou “public” pour les serveurs publiques.
- lib/ : vos .nix partagés entre machines
- store/ : vos fichiers non .nix partagés
Chaque zone pourra aussi avoir un dossier lib, store etc si il y a des spécificités.
Vous avez aussi besoin de paramètres, au niveau du host, de la zone et globalement. Exemple de paramètres: l’email de l’administrateur principal ou des IPs de DNS. C’est une très bonne chose de séparer les paramètres du reste car ils peuvent être utilisés par vos librairies. On utilisera le même découpage:
- organisation.nix : le fichier principal de configuration de greenpeace (comme le nom, l’email de l’administrateur principal etc).
- zone/<nom-zone>/zone.nix : les paramètres de la zone.
- zone/<nom-zone>/host/<nom-machine>/host.nix : les paramètres de la machine.
Pour éviter que les librairies aient trois arguments (orga,zone,host) et pour rendre le système plus souple je trouve préférable que chaque host.nix reprenne les paramètres de la zone (par une variable “zone”) et la zone de l’organisation. Ainsi “host” contient tous les paramètres.

