L’écosystème Nix
- published
- reading time
- 8 minutes
Gestionnaire de paquets Nix
Une révolution dans la gestion des dépendances
- Gestionnaire de paquets purement fonctionnel développé par Eelco Dolstra
- Base sur la thèse: The Purely Functional Software Deployment Model
- Première version en 2003
- Approche révolutionnaire: immutabilité et reproductibilité
- Différent des gestionnaires traditionnels (
apt,yum,homebrew) - Stockage avec des chemins uniques basés sur des hashes
Le langage Nix
# Une exemple simple
let
pkgs = import <nixpkgs> {};
in
{
myPackage = pkgs.stdenv.mkDerivation {
name = "hello-world";
src = ./.;
buildPhase = ''
gcc -o hello hello.c
'';
installPhase = ''
mkdir -p $out/bin
cp hello $out/bin/
'';
};
}
Langage fonctionnel pure et lazy
Code non touché n’est pas évalué
No “side effects”
- Même input = même résultat
- Identique “bit for bit”
Syntaxe simple mais puissante
Similaire à
- Haskell (ex:
let) - JSON/Javascript (ex: attrsets
{ })
Bases du langage Nix
# Types de base
nix-repl> 42
42
nix-repl> "Hello, Nix!"
"Hello, Nix!"
nix-repl> true
true
# Listes
nix-repl> [ 1 2 3 "hello" ]
[ 1 2 3 "hello" ]
# Sets (objets)
nix-repl> { name = "John"; age = 30; }
{ age = 30; name = "John"; }
# Fonctions
nix-repl> add = x: y: x + y
«lambda @ (string):1:1»
nix-repl> add 5 3
8
# Let expressions
nix-repl> let greeting = "Hello"; name = "World"; in "${greeting}, ${name}!"
"Hello, World!"
Nix comme langage de programmation fonctionnelle
Contrairement aux formats de configuration statiques tels que YAML ou
JSON, Nix est un langage de programmation fonctionnel complet. Voici un
exemple utilisant la fonction map pour démontrer ses capacités de calcul
Exemple
nix-repl> pkgs = import <nixpkgs> {}
nix-repl> map (x: x * 2) [1 2 3 4 5]
[ 2 4 6 8 10 ]
nix-repl> map (name: pkgs.${name}) ["hello" "git" "vim"]
[ «derivation /nix/store/...» «derivation /nix/store/...» «derivation /nix/store/...» ]
nix-repl> map (pkg: pkg.name) (map (name: pkgs.${name}) ["hello" "git" "vim"])
[ "hello-2.12.1" "git-2.42.0" "vim-9.0.1677" ]
Utilisation du langage pour un packet
let
pkgs = import <nixpkgs> {};
in
myPackage = pkgs.stdenv.mkDerivation {
name = "hello-world";
src = ./.;
buildPhase = ''
gcc -o hello hello.c
'';
installPhase = ''
mkdir -p $out/bin
cp hello $out/bin/
'';
}
Utilisation de base et commandes
# Utiliser un paquet temporairement
nix-shell -p gcc python3
# Chercher des paquets
nix search nixpkgs vim
# Entrer dans un shell de développement
nix-shell
# Construire un paquet
nix-build
# Sort les poubelles!
nix-collect-garbage
Chemins dans le magasin Nix (nix-store)
Tout va dans /nix/store
Fichier simple
/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-hello.txt
Paquet (package) complet (Git)
/nix/store/bcdqax4p8xww4s7z4v7n2k8x9m5j6h2l-git-2.41.0
├── bin/git
├── lib/
├── share/man/
└── libexec/git-core/
Bibliothèques (OpenSSL)
/nix/store/f8k2h9x3m4p6n7q9r1s5t8v2w4y6z9b3-openssl-1.1.1u
├── lib/libssl.so.1.1
├── lib/libcrypto.so.1.1
├── include/openssl/
└── bin/openssl
Caractéristiques clés de Nix
- Builds reproductibles: même input = même output, toujours
- Rollbacks atomiques: retour en arrière sans casser le système
- Environnements isolés: pas de “dependency hell”
- Multi-utilisateur et multi-version: plusieurs versions du même paquet
- Garbage collection: nettoyage automatique des paquets/dérivations inutilisés
- Cross-platform: Linux, macOS, et même WSL
Avantages d’utiliser Nix
- Fini les “ça marche sur ma machine”
- Configuration déclarative : infrastructure as code
- Uniformité des builds entre projets
- Environnements de développement reproductibles
- Déploiements fiables et prévisibles
- Isolation complète entre projets
- Rollback instantané en cas de problème
- Partage facile d’environnements entre équipes
Inconvénients de Nix
Courbe d’apprentissage abrupte
Solution:
Commencer avec des cas d’utilisation simples. Documentation communautaire riche. Voir les configurations des gens sur GitHub!
Langage Nix parfois déroutant
Solution:
Nix Dev contient une série de tutoriels très bien fait et clair.
Consommation d’espace disque
Solution:
Garbage collection régulièrement avec nix-collect-garbage -d
Dans la configuration NixOS:
nix = {
gc = {
automatic = true;
dates = "weekly";
};
};
Sortie de nix-collect-garbage
[...]
deleting '/nix/store/pv760cyimzrs9lps2p37fg7cyyk0swp4-HTTP-Server-Simple-PSGI-0.16.tar.gz.drv'
deleting '/nix/store/p8nvy5qydxr5kxmil9hi3gpjjih8k0iz-source.drv'
deleting unused links...
note: currently hard linking saves 31583.58 MiB
84971 store paths deleted, 63118.27 MiB freed
Paquets pas toujours à jour
Relatif puisque nixpkgs contient le plus grand nombre de paquets (plus de 120 000).
Solution:
- “Fork” corporatif de nixpkgs.
- Contributions communautaires, overlays personnalisés:
Exemple d’un overlay:
nixpkgs.overlays = [
(final: prev: {
hyprpaper = prev.hyprpaper.overrideAttrs (old: rec {
version = "0.8.1";
src = prev.fetchFromGitHub {
owner = "hyprwm";
repo = "hyprpaper";
rev = "v${version}";
hash = "sha256-RDeDDRgmMnmEKJalIovpXKu9urHuCvH8tHP4RsplyXs=";
};
});
})
];
Builds initiaux lents
Solutions:
- Cache binaire Hydra, builds incrémentaux
- Utilisé une machine de build comme cache
- Utilisé d’autres stations de travail pour les builds locaux
Tooling
nix-shell : Environnements temporaires
Problème initial : pas de GCC installé
$ gcc --version
bash: gcc: command not found
$ which gcc
# Aucun résultat - gcc n'est pas disponible
Solution avec nix-shell
# Ouvrir un shell temporaire avec GCC
$ nix-shell -p gcc
[nix-shell]$ gcc --version
gcc (GCC) 12.3.0
Copyright (C) 2022 Free Software Foundation, Inc.
[nix-shell]$ which gcc
/nix/store/...-gcc-12.3.0/bin/gcc
# Quitter le shell
[nix-shell]$ exit
$ gcc --version
bash: gcc: command not found # Plus disponible !
Versions multiples concurrentes
# Terminal 1 : GCC 12
$ nix-shell -p gcc
[nix-shell]$ gcc --version
gcc (GCC) 12.3.0
# Terminal 2 : GCC 11 (version spécifique)
$ nix-shell -p gcc11
[nix-shell]$ gcc --version
gcc (GCC) 11.4.0
# Terminal 3 : GCC 13 (version récente)
$ nix-shell -p gcc13
[nix-shell]$ gcc --version
gcc (GCC) 13.2.0
Toutes les versions coexistent sans conflit
Environnements plus complexes
# Plusieurs outils simultanément
$ nix-shell -p gcc python3 nodejs go rust
[nix-shell]$ gcc --version && python --version && node --version
gcc (GCC) 12.3.0
Python 3.11.6
v18.18.2
# Versions spécifiques
$ nix-shell -p gcc11 python39 nodejs-16_x
[nix-shell]$ python --version && node --version
Python 3.9.18
v16.20.2
Exemples : Base de code C/C++
# shell.nix pour un projet C++
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
gcc
cmake
gdb
valgrind
boost
sqlite
openssl
pkg-config
];
shellHook = ''
echo "Environnement C++ prêt!"
echo "GCC version: $(gcc --version | head -1)"
'';
}
Utilisation: nix-shell dans le dossier du projet
Paquets Python, Rust et Go
Python
# Package Python avec des dépendances spécifiques
{ pkgs ? import <nixpkgs> {} }:
pkgs.python3Packages.buildPythonApplication {
pname = "mon-app-python";
version = "1.0.0";
propagatedBuildInputs = with pkgs.python3Packages; [
numpy
flask
requests
];
}
Rust
# Package Rust avec cargo
{ pkgs ? import <nixpkgs> {} }:
pkgs.rustPlatform.buildRustPackage {
pname = "mon-app-rust";
version = "1.0.0";
src = ./.;
cargoHash = "sha256-XYZ9876543210fedcba9876543210XYZ9876543210=";
}
Go
# Package Go
{ pkgs ? import <nixpkgs> {} }:
pkgs.buildGoModule {
pname = "mon-app-go";
version = "1.0.0";
src = ./.;
vendorHash = "sha256-ABC1234567890abcdef1234567890ABC1234567890=";
}
NixOS et sa relation avec Nix
- NixOS : distribution Linux basée sur Nix Package Manager
- Configuration déclarative complète du système d’exploitation
- Rollback du système entier possible de façon atomique
- Même philosophie : reproductibilité et immutabilité
- Configuration dans
/etc/nixos/configuration.nix - Rebuild du système :
nixos-rebuild switch
Exemple de configuration.nix avec services et paquets
{ config, pkgs, ... }: {
# Configuration réseau
networking.hostName = "mon-serveur";
networking.firewall.enable = true;
# Services système
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;
};
services.nginx = {
enable = true;
virtualHosts."localhost" = {
root = "/var/www";
};
};
# Packages installés globalement
environment.systemPackages = with pkgs; [
vim
git
curl
];
# Utilisateurs
users.users.alice = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
openssh.authorizedKeys.keys = [
"ssh-rsa AAAAB3NzaC1yc2E... alice@example.com"
];
};
system.stateVersion = "25.11";
}
nixpkgs : Le cœur de l’écosystème Nix
Qu’est-ce que nixpkgs ?
- Dépôt Git géant contenant plus de 100 000 paquets
- Définitions de paquets: comment construire chaque logiciel
- Modules NixOS: configuration des services système
- Entièrement sur GitHub: https://github.com/NixOS/nixpkgs
- Développement ouvert: n’importe qui peut contribuer
Contributions communautaires
Types de contributions courantes
- Ajout de nouveaux paquets
- Mise à jour de versions existantes
- Correction de bugs durant les builds
- Amélioration de modules NixOS
- Documentation
Plus de 5 000 contributeurs actifs!
Système de modules NixOS
- Modularité: découpage logique de la configuration
- Réutilisabilité: partage entre systèmes
- Options et services prédéfinis
- Composition facile de fonctionnalités
- Type safety: validation automatique
Exemple de configuration avec module
# Structure modulaire
{
imports = [
./hardware-configuration.nix
./modules/web-server.nix
./modules/monitoring.nix
];
# Configuration spécifique
networking.hostName = "mon-serveur";
}
Exemples de modules NixOS
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.presentation-server;
in {
options.services.presentation-server = {
enable = mkEnableOption "presentation server";
port = mkOption {
type = types.port;
default = 8080;
description = "Port for the presentation server";
};
domain = mkOption {
type = types.str;
default = "localhost";
description = "Domain name for the presentation";
};
};
config = mkIf cfg.enable {
services.nginx = {
enable = true;
virtualHosts."${cfg.domain}" = {
listen = [{ addr = "0.0.0.0"; port = cfg.port; }];
root = pkgs.writeTextDir "index.html" ''
<!DOCTYPE html>
<html>
<head>Présentation NixOS</head>
<body>
<h1>Bienvenue à la présentation NixOS</h1>
<p>Cette présentation est servie par un module personnalisé !</p>
</body>
</html>
'';
locations."/" = {
tryFiles = "$uri $uri/ /index.html";
};
};
};
networking.firewall.allowedTCPPorts = [ cfg.port ];
};
}
Utilisation du module
{ config, pkgs, ... }: {
services.presentation-server = {
enable = true;
port = 8080;
domain = "presentation.local";
};
}
Et beaucoup plus!
Plus de 1000 modules disponibles dans nixpkgs!
https://search.nixos.org/options
Trucs intéressant
L’appliance-controller doit pouvoir repartir des services
let
cfg = config.services.appliance-controller;
in
{
options.services.appliance-controller = {
enable = lib.mkEnableOption "Appliance Controller service";
user = lib.mkOption {
type = lib.types.str;
default = "appliance-controller";
description = "User account under which the appliance controller runs";
};
config = lib.mkIf cfg.enable {
security.polkit = {
enable = true;
extraConfig = ''
polkit.addRule(function(action, subject) {
var units = ["irxv-processor.service", "stats-aggregator.service", "promtail.service", "prometheus.service"];
if (action.id == "org.freedesktop.systemd1.manage-units" && subject.user == "${cfg.user}") {
var unit = action.lookup("unit");
for (var i = 0; i < units.length; i++) {
if (unit == units[i]) {
return polkit.Result.YES;
}
}
}
});
'';
};
};
};
}
Conclusion et ressources supplémentaires
Pourquoi adopter Nix?
- Résout définitivement les problèmes de reproductibilité
- Simplifie la gestion d’environnements complexes
- Améliore la collaboration en équipe
- Réduit les bugs liés à l’environnement
Ressources utiles
- Manuel officiel: https://nixos.org/manual/nix/
- Nix Dev: https://nix.dev/
- Nix Pills: https://nixos.org/guides/nix-pills/
- Communauté: https://discourse.nixos.org/
- Recherche de paquets: https://search.nixos.org/
Conseil: Commencez petit avec nix-shell pour vos projets!