Nix est un gestionnaire de paquets fonctionnel dont la version 2.0 est sortie récemment. Parmi les nouveautés, on peut noter qu’une commande nix
a été introduite pour uniformiser les différentes sous‐commandes (nix-build
, nix-env
, etc.) et avoir de meilleures options par défaut (pour la recherche de paquets notamment). Une bonne partie du reste du travail concerne des couches moins visibles mais néanmoins importantes : prise en charge de HTTP/2, amélioration de sécurité, etc.
Nix peut être utilisé sur n’importe quelle distribution GNU/Linux en complément du gestionnaire de paquets habituel. Il existe également une distribution GNU/Linux articulée autour de Nix : NixOS. La version 18.03 de NixOS, prévue pour sortir très prochainement, inclura Nix 2.0.
Mise à jour : Nix 18.03 est sorti.
Sommaire
- Qu’est‐ce que Nix ?
- Quels sont les cas d’usages ?
- Quelles sont les faiblesses ?
- Nouveautés de Nix 2.0
- Exemple pour développer en C++ avec Nix
Qu’est‐ce que Nix ?
Nix est un gestionnaire de paquets. Contrairement à de nombreux autres gestionnaires, qui sont le plus souvent liés à une distribution particulière, celui‐ci peut être installé sur n’importe quelle distribution.
Nix permet de créer des environnements de développement reproductibles. Au lieu d’installer globalement une version particulière d’une bibliothèque, Nix l’installe dans un dossier spécifique. Ceci permet de faire cohabiter différentes versions d’une même bibliothèque et de définir des profils utilisateur ou par projet (c’est‐à‐dire des ensembles de liens vers les bibliothèques, aux versions voulues).
Quels sont les cas d’usages ?
Nix peut être utile à des utilisateurs non développeurs :
- cela peut être un moyen efficace d’installer des paquets qui ne sont pas disponibles via le gestionnaire de paquets de sa distribution ;
- cela permet de tester l’installation de programmes ou bibliothèques sans polluer son système ; Nix conserve même l’historique des installations et permet de revenir aux états antérieurs ;
- Nix gère les paquets efficacement en calculant une somme de contrôle du paquet ; ainsi, quand deux utilisateurs installent une même version d’un paquet, c’est le même dossier d’installation qui est utilisé, ce partage est sans risque car le dossier est en lecture seule et ne sera jamais supprimé tant qu’un utilisateur y fait référence ;
- ce n’est pas un système de conteneurs ni de machines virtuelles, les logiciels installés par Nix sont exécutés directement par le système.
Pour des développeurs, Nix est particulièrement avantageux :
- c’est pratique pour les développeurs qui jonglent avec plusieurs projets, avec des dépendances dans différentes versions ; par exemple, on peut facilement ouvrir un shell avec Python 2 par défaut et un autre avec Python 3 par défaut ;
- Nix permet de définir explicitement un environnement, par exemple pour un projet de développement ; pour cela, il suffit d’ajouter un fichier
.nix
et d’y indiquer les dépendances (bibliothèques nécessaires…) et le système de compilation à utiliser (autotools, cmake, ant, go…) ; on peut alors compiler et installer le projet ou lancer un shell contenant toutes les dépendances nécessaires ; - c’est un gain de temps important pour commencer à travailler sur un projet : il suffit de cloner le dépôt et de faire
nix-shell
pour obtenir un environnement de travail complet ; - l’environnement étant utilisé par les développeurs eux‐mêmes, il est donc constamment testé et à jour ; il peut également servir de point de départ pour construire le projet dans un autre contexte, par exemple pour en faire un paquet RPM, Deb, etc. ;
- enfin, cela peut simplifier les scripts de construction : il n’y a plus besoin de rechercher les chemins vers les bonnes versions des différents outils, tout est pris en charge par Nix.
Quelles sont les faiblesses ?
- Le gestionnaire de paquets Nix utilise son propre langage, également appelé Nix, qu’il faut donc apprendre si l’on veut créer ses propres paquets ;
- l’aspect fonctionnel de Nix est très puissant mais peut être déroutant au début : on ne peut notamment pas aller bidouiller dans un dossier d’installation pour corriger un problème, il faut le faire en amont dans l’empaquetage du logiciel ;
- Nix est conçu pour fonctionner dans son écosystème et non comme un outil pour distribuer un programme dans d’autres écosystèmes ; il existe cependant des approches comme nix-bundle ou dockerTools pour cela ;
- OpenGL (et à peu près tous les outils qui dépendent d’un pilote) est complexe à utiliser ; en effet, on ne peut pas compiler un programme en incluant toutes les versions possibles du pilote OpenGL. Sous NixOS, le problème n’existe pas, mais les utilisateurs de Nix sur d’autres systèmes se retrouvent face à des programmes OpenGL qui ne tournent pas directement. Le problème se contourne avec des outils comme nixGL ou avec des petites bidouilles.
Nouveautés de Nix 2.0
Nouvelle commande nix
La nouvelle commande nix
simplifie et uniformise certaines commandes nix-*
, et devrait à terme toutes les remplacer :
- aide en ligne avec
nix --help
; - sortie écran moins verbeuse, apparition d’une barre de progression ;
- possibilité de formater la sortie en JSON ;
-
nix build
remplacenix-build
(construit un paquet) ; -
nix run
remplacenix-shell -p
(exécute une commande avec les dépendances spécifiées) et ne charge plus un nouveau shell ; -
nix search
remplacenix-env -qa
(recherche de paquets) et utilise désormais un système de cache pour accélérer les recherches ; - etc.
Extension des types de store
- stores locaux : LocalStore, LocalBinaryCacheStore
- stores http, ssh ou amazon S3 : HttpBinaryCacheStore, SSHStore, S3BinaryCacheStore
- etc.
Améliorations de sécurité
- ajout de signatures pour les stores locaux ;
- commande
nix verify
pour vérifier les paquets ; - ajout d’une vérification par signature lors des basculements sur des paquets binaires ;
- etc.
Autres
- prise en charge de HTTP/2 ;
- nettoyage automatique lors des constructions s’il y a un manque d’espace disque ;
- prise en charge des nombres flottants dans le langage Nix ;
- nouvelles fonctions prédéfinies : builtins.fetchGit (récupère un dépôt Git à l’évaluation d’une expression nix), builtins.split (découpe un texte selon une expression rationnelle POSIX), etc. ;
- suppression de Perl et de tous ses composants dans le code de base de nix ;
- etc.
Exemple pour développer en C++ avec Nix
Code source
Nous allons démontrer l’utilisation de nix sur un programme C++ complet :
#include <experimental/filesystem>
#include <boost/process.hpp>
#include <iostream>
#include <OpenImageIO/imageio.h>
int main() {
for(auto &&p: std::experimental::filesystem::directory_iterator(".")) {
OIIO::ImageInput *im = OIIO::ImageInput::open (p.path().c_str());
if(!im) continue;
std::string s;
std::cout << "Editer le fichier: " << p << " (o/N) ? ";
std::cin >> s;
if(s == "o") {
boost::process::system(boost::process::search_path("gimp"), p.path().c_str());
break;
}
}
}
Ce programme semble simple à première vue, il liste tous les fichiers d’un répertoire (grâce à directory_iterator
) puis, pour chaque fichier, il tente d’ouvrir celui‐ci grâce à la bibliothèque OpenImageIO OIIO
. Si l’ouverture est réussie, il propose à l’utilisateur d’éditer le fichier et si celui‐ci accepte, il sera ouvert dans GIMP grâce à un appel à la bibliothèque boost::process
.
Gestion des dépendances
Le programme précédent a cependant des dépendances complexes :
- une version d’un compilateur C++ suffisamment récent pour prendre en charge le C++11 et au moins
std::experimental::filesystem
; -
boost
; -
openimageio
.
Nous pouvons commencer par créer un shell contenant les dépendances nécessaires à notre travail :
$ nix-shell -p openimageio -p gcc -p openexr -p boost
[nix-shell] $ g++ nix_test.cpp -std=c++14 -lstdc++fs -lOpenImageIO -lboost_filesystem -lboost_system
[nix-shell] $ ./a.out
Editer le fichier: "./passport2016.jpg" (o/N) ? o
... lancement de gimp
Comme vous pouvez l’observer, nix-shell
prend en charge le approvisionnement de l’environnement de développement et il n’est pas nécessaire de spécifier de répertoire de recherche de fichiers d’en‐tête (includes) -I
ni de recherche de bibliothèque -L
.
Environnement de développement et empaquetage
La création d’un shell est une solution rapide pour l’exécution d’une tâche ponctuelle, mais il est souvent pratique de passer par un fichier default.nix
, qui indique les directives de compilation en plus des dépendances :
with import <nixpkgs> {};
stdenv.mkDerivation {
name = "linuxfr_depeche_nix_20";
buildInputs = [openimageio gcc openexr boost];
src = ./.;
buildPhase = ''
g++ nix_test.cpp -std=c++14 -lstdc++fs -lOpenImageIO -lboost_filesystem -lboost_system
'';
installPhase = ''
mkdir -p $out/bin;
cp a.out $out/bin/linuxfr_depeche_nix_2.0
'';
}
with import <nixpkgs> {}
décrit la version de nixpkgs à utiliser, nous y reviendrons. La suite décrit le nom name
du paquet, sa liste de dépendances buildInputs
, le répertoire où sont les sources src
, ainsi que les commandes à effectuer pour construire le paquet buildPhase
et installer celui‐ci avec installPhase
.
La commande nix build
construit le paquet et le stocke dans ./result
:
$ ls -R ./result
./result:
bin
./result/bin:
linuxfr_depeche_nix_2.0
Le binaire est exécutable directement par le biais de ./result bin/linuxfr_depeche_nix_2.0
, mais peut aussi être installé :
$ nix-env -i ./result
installing 'linuxfr_depeche_nix_20'
building '/nix/store/45l04x4nqidap70skizmvvmi7p48dgmz-user-environment.drv'...
created 4407 symlinks in user environment
$ linuxfr_depeche_nix_2.0
Editer le fichier: "./passport2016.jpg" (o/N) ? n
Editer le fichier: "./IMG_20170521_174328.jpg" (o/N) ? o
... lancement de gimp
Personnalisation des dépendances
Supposons que nous soyons dans un cas de dépendances bien plus complexes, avec les contraintes suivantes :
- seul
gcc6
peut être utilisé ; - seul
boost-1.63
peut être utilisé ; -
openimageio
dépend aussi deboost
et malheureusement la dérivation (i.e. « paquet » nix) par défaut est compilée avecboost-1.66
, ce qui pose un conflit avecboost-1.63
.
Ce scénario peut sembler dingue, mais c’est malheureusement une constante souvent rencontrée dans le développement logiciel. Traditionnellement, ce genre de situation est réglé par la compilation à la main de toutes les dépendances, impliquant un processus long et fragile.
Nix permet de surcharger tout cela très facilement. Éditons notre fichier default.nix
:
with import <nixpkgs> {};
stdenv.mkDerivation rec {
name = "linuxfr_depeche_nix_20";
openimageioWithBoost163 = openimageio.override {
boost = boost163;
};
buildInputs = [openimageioWithBoost163 gcc6 openexr boost163];
src = ./.;
buildPhase = ''
g++ nix_test.cpp -std=c++14 -lstdc++fs -lOpenImageIO -lboost_filesystem -lboost_system
'';
installPhase = ''
mkdir -p $out/bin;
cp a.out $out/bin/linuxfr_depeche_nix_2.0
'';
}
On note l’utilisation des paquets gcc6
et boost163
, fournis de base par nix. Cependant, il faut surcharger openimageio
pour changer sa version de boost
. Le prochain appel à nix build
se chargera de créer la nouvelle version d’openimageio
compilée avec la bonne version de boost
.
On note toutefois que ce processus de compilation ne sera effectué qu’une seule fois, le résultat étant stocké dans le cache local de nix.
Reproductibilité parfaite en bloquant la version
Par défaut, notre fichier default.nix
utilise with import <nixpkgs> {}
, c’est‐à‐dire la définition de paquets actuellement configurés sur le système. Cette approche est souple mais fragile car, en cas de mise à jour de cette liste, notre projet peut ne plus fonctionner.
Il est toutefois possible de fixer cette version en se limitant à un commit précis du dépôt GitHub nixpkgs
, par exemple avec :
with import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/1bc5bf4beb759e563ffc7a8a3067f10a00b45a7d.tar.gz") {};
Cette approche garantit une construction parfaitement reproductible. Couplée à la précision sur les versions des dépendances, nix permet d’obtenir un processus de construction de paquet très robuste. Il est maintenant possible de construire n’importe quel projet de façon robuste en deux commandes :
$ (git|hg|svn|darcs|pujil|cvs) clone
$ nix build
Autres fonctionnalités
L’exemple précédent montre l’intérêt de Nix pour développer un projet C++. Nix apporte également de nombreuses fonctionnalités pour développer dans d’autres langages et même pour utiliser plusieurs langages dans un même projet.
Enfin, Nix apporte également d’autres fonctionnalités comme la gestion de services (nixos), la création et le déploiement d’environnements logiciels légers (nixops), etc.
Aller plus loin
- Site officiel de Nix (390 clics)
- NixOS, la distribution GNU/Linux autour de Nix (239 clics)
- Les notes de version pour Nix 2.0 (80 clics)
- [LinuxFr.org] Vidéos d’introduction à Nix et NixOS, par nokomprendo (145 clics)
- [LinuxFr.org] L’heure du test — épisode 1 — NixOS (110 clics)
- [LinuxFr.org] Nix pour les développeurs (89 clics)
# petite coquille
Posté par nokomprendo (site web personnel) . Évalué à 2.
La prochaine version de Nixos est la 18.03 et non la 18.04 (même s'ils ne sont pas en avance pour la sortir…).
Et sinon, le logo n'est pas un peu gros ?
[^] # Re: petite coquille
Posté par Davy Defaud . Évalué à 2. Dernière modification le 03 avril 2018 à 19:42.
Corrigé.
Tout à fait d’accord. Mais il est impossible de redimensionner une image, cette fonction est incompatible avec les titres (https://linuxfr.org/wiki/aide-edition#images). Et il n’y a pas plus petit sur https://nixos.org/logo/.
# voir aussi… GNU Guix
Posté par dzecniv . Évalué à 7.
Merci pour la dépêche !
Faut vraiment que je m'y mette. J'invite qui veut à comparer avec Docker.
Petite mention de GNU Guix quand même: https://www.gnu.org/software/guix/ + GuixSD, issu des idées de Nix, donc même objectif mais tout avec un vrai language de programmation, en l'occurence Guile Scheme. Peut être que Nix est plus simple à installer.
[^] # Docker [was: voir aussi… GNU Guix]
Posté par Sébastien Maccagnoni (site web personnel) . Évalué à 4.
Même si dans l'esprit ça part de la même logique (déclaratif, tout ça tout ça), à mon sens en terme d'usage ce n'est pas vraiment comparable avec Docker car ça ne fait pas de container : on reste sur une seule machine, un seul système…
[^] # Re: Docker [was: voir aussi… GNU Guix]
Posté par galbolle . Évalué à 4. Dernière modification le 24 août 2019 à 16:43.
nixos sait faire des containers.
[^] # Re: Docker [was: voir aussi… GNU Guix]
Posté par Sébastien Maccagnoni (site web personnel) . Évalué à 5. Dernière modification le 04 avril 2018 à 08:50.
Oui, mais ce n'est pas l'usage de base de NixOS, de plus ces containers ne sont pas aussi bien isolés du reste du système.
J'admets avoir certainement trop simplifié ma réponse :)
Une fois NixOS bien maîtrisé, on peut faire des containers et obtenir une logique pas trop éloignée de Docker…
Allez, comme punition je m'imposerai d'essayer ça concrètement :)
[^] # Re: voir aussi… GNU Guix
Posté par Guillaum (site web personnel) . Évalué à 3.
Pour moi les deux sont totalement indépendant. Docker ne gere pas les programmes / librairies installées. Il n'y a rien de choquant d'avoir un nix dans NixOS (ou n'importe quelle autre distrib) dans un docker.
Par contre, pour le dev tous les jours, nix est suffisant pour ne pas avoir besoin de docker.
# Nix et NixOS sont top
Posté par Damien Cassou . Évalué à 3.
Super article. Je recommande chaudement Nix et NixOS (ou GuixSD que je n'ai pas essayé mais qui utilise Nix). GNU/Linux Mag leur avait consacré un article dans le numéro 203.
# Quid des mises à jour de sécurité ?
Posté par djano . Évalué à 5.
Je trouve l'idée de Nix absolument géniale.
Quand on parle des alternatives existantes (ce que Nix vise à palier), on nous vante à raison la facilité avec laquelle on peut faire les mises à jour de sécurité: on met à jour la librairie partagée et hop c'est sécurisé. D'après la description du fonctionnement, on dirait qu'il faut mettre à jour toutes les dépendances une par une, comme avec la compilation statique.
Est-ce que c'est la seule manière de faire, ou bien est-ce qu'il existe une sorte d'override global?
[^] # Re: Quid des mises à jour de sécurité ?
Posté par Bruno Michel (site web personnel) . Évalué à 9.
Je suis loin d'être un expert Nix mais, de ce que j'en ai compris, les mainteneurs n'ont pas besoin de déclarer explicitement la mise à jour sur tous les paquets qui dépendent de la bibliothèque à mettre à jour. Et les utilisateurs peuvent mettre à jour tous les paquets avec un
nix-channel --update && nix-env -u
(l'équivalent d'unapt update && apt upgrade
). Ça va reconstruire tous les paquets qui dépendent de la bibliothèque mise à jour (sauf si le paquet avait indiqué une version particulière de la bibliothèque).Pour les utilisateurs de NixOS, il peut y avoir beaucoup de paquets et ça risque d'être long. Les développeurs ont mis en place un truc pour contourner ça : https://theshortlog.com/2016/10/01/Nix-security-updates-update/
[^] # Re: Quid des mises à jour de sécurité ?
Posté par djano . Évalué à 4.
Merci Bruno!
[^] # Re: Quid des mises à jour de sécurité ?
Posté par Guillaum (site web personnel) . Évalué à 5.
Petite remarque, il faut faire
nix-env -u --always
pour mettre à jour tout. Sinon par défaut il ne met pas à jour les paquets qui ne changent pas de numéro de version.# Et par utilisateur
Posté par Katyucha (site web personnel) . Évalué à 3.
Un des avantages aussi, c'est que chaque utilisateur peut installer les paquets qu'il a besoin, les mettre à jour sans impacter les collègues
L'inconvénient, c'est évidemment la place sur le disque dur
[^] # Re: Et par utilisateur
Posté par freem . Évalué à 3.
Mais du coup, ça doit être possible d'avoir un outil qui vérifie périodiquement quels outils sont majoritairement installés et le signale à l'administrateur du système, qui pourrait lui, si il considère l'outil fiable, l'installer sur le système?
Autre piste: les systèmes de fichiers avec déduplication?
[^] # Re: Et par utilisateur
Posté par Guillaum (site web personnel) . Évalué à 3.
En fait l'installation est partagée entre chaque utilisateur ET nix gère la déduplication entre fichiers du store. C'est pratique si par exemple tu as plusieurs version d'un même programme.
[^] # Re: Et par utilisateur
Posté par freem . Évalué à 3.
Hum… donc, tous les utilisateurs ont la possibilité d'écrire dans un dossier système, d'altérer le comportement du système pour les autres utilisateurs?
[^] # Re: Et par utilisateur
Posté par Bruno Michel (site web personnel) . Évalué à 5.
Non, ils ont juste le droit de lancer des commandes nix via sudo. Et nix fait en sorte que les commandes d'un utilisateur n'ait pas d'effets de bord pour les autres utilisateurs.
[^] # Re: Et par utilisateur
Posté par freem . Évalué à 3.
D'accord, donc il y a un mécanisme de base de données derrière qui lie les utilisateurs à leurs programmes. À la base je pensais que ça installait juste dans le dossier utilisateur, par exemple dans $HOME/.local/bin (ce qui aurait évité de passer par sudo, pour le coup).
[^] # Re: Et par utilisateur
Posté par nokomprendo (site web personnel) . Évalué à 4.
Justement non. Les utilisateurs peuvent installer sans sudo. Tout est stocké (sans duplication) dans le /nix/store en lecture seule donc pas de conflit possible. Le seul danger est qu'un utilisateur peut remplir le disque en installant plein de paquets différents.
[^] # Re: Et par utilisateur
Posté par Guillaum (site web personnel) . Évalué à 3.
Techniquement les commandes nix communiquent avec le "store" par le biais d'un daemon. Le demon est le seul à pouvoir écrire dans la store. Il est par contre tout à fait possible de lui faire écrire ce que l'on veut mais sans pouvoir écraser un autre répertoire. Par contre il est vrai que tu peux mettre un truc dangereux dans le store et demander à un utilisateur de l'exécuter. Mais c'est la même chose que lui demander d'exécuter un ficher reçu par mail…
# Commande nix
Posté par MCMic (site web personnel) . Évalué à 4.
Le changelog annonce une commande nix unifiée ce qui semble une bonne idée, et en dessous aucun exemple de la dépêche ne s’en sert.
Est-ce parce que ces choses là ne sont pas encore faisables avec la commande nix ou c’est une coquille ?
[^] # Re: Commande nix
Posté par nokomprendo (site web personnel) . Évalué à 3.
Normalement tout fonctionne avec Nix 2 mais comme c'est assez nouveau, on a préféré mettre les commandes Nix 1 (les principes sont les mêmes).
Ceci dit NixOS 18.03 vient juste de sortir (https://nixos.org/nixos/manual/release-notes.html#sec-release-18.03), avec Nix 2. On va pouvoir testé tout ça à fond…
[^] # Re: Commande nix
Posté par Guillaum (site web personnel) . Évalué à 3.
nix-shell
etnix-env
n'existent pas encore dans les nouvelles commandes.# Merci
Posté par 41px . Évalué à 1.
Super, merci pour la dépêche
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.