Peut-on créer une ISO NixOS plus petite ?
(natkr.com)- NixOS permet de créer facilement des VM ou des ISO à partir de la configuration, mais même une image live presque minimale est générée à 458 MiB au départ, soit bien plus qu’une ISO de VM Alpine d’environ 66 MiB
- L’essentiel de la taille provenait de nix-store.squashfs, qui contenait Python 3.13.13, les modules Linux, systemd, Perl, GRUB, la documentation et des dépendances liées à Nix
- En passant par
nix.enable = false,documentation.enable = false, puis la suppression deregister-nix-paths, l’ISO est passée de 458 MiB → 384 MiB → 360 MiB, et la dépendance à Boost a aussi disparu - En retirant en plus le client OpenSSH, les paquets par défaut, les outils d’installation de GRUB, les modules du noyau chargés à l’exécution et le chemin d’activation basé sur Perl, la taille finale est descendue à 183 MiB
- Cela peut servir de référence pour une petite image de démarrage expérimentale, mais comme beaucoup de fonctions nécessaires sont supprimées, il est difficile de l’utiliser telle quelle pour un poste de travail ou un environnement important
Créer une ISO à partir d’une configuration NixOS
- NixOS permet de créer facilement une VM à partir d’une configuration
nixos-rebuild build-vmgénère une VM à partir de la configuration système actuelle- avec
pkgs.nixos, on peut aussi créer une VM depuis une configuration arbitraire, même si ce n’est pas la configuration du système
- L’exemple de base crée une VM minimale avec seulement
system.stateVersion = "26.05"etservices.getty.autologinUser = "root" - Cette VM fonctionne comme une thin VM
- l’image disque ne contient que les fichiers créés directement dans la VM
- le reste, comme
/nix/store, est monté depuis l’OS hôte
- Si l’hôte n’a pas Nix, ou s’il faut exécuter l’image sur un hôte distant ou un hyperviseur classique, il faut une ISO autonome
- On peut construire une ISO en important le module
iso-image.nixde NixOSimage.baseName = lib.mkForce "nixos"permet de définir le nom du fichier ISO produit- exemple d’exécution :
qemu-system-x86_64 --cdrom .../nixos.iso -m 1G --accel kvm - hors environnement Linux moderne amd64, il peut être nécessaire d’adapter l’architecture ou le mode d’accélération
Point de départ : une ISO de 458 MiB
- Le résultat de la construction de l’ISO de base faisait 458 MiB
- Cette image ne contenait même pas encore
vim- après démarrage, lancer
vimrenvoyaitcommand not found
- après démarrage, lancer
- À titre de comparaison, l’ISO VM d’Alpine mentionnée fait environ 66 MiB
- Damn Small Linux est cité comme exemple d’une distribution ayant proposé un environnement de bureau abouti avec une taille bien plus réduite
- L’objectif n’est pas d’atteindre le niveau de Damn Small Linux, mais de voir jusqu’où il est possible de réduire une ISO NixOS
Analyse de la taille à l’intérieur de l’ISO
- Après montage de l’ISO et vérification avec
du, la taille se répartissait ainsinix-store.squashfs: 416 MiB- initrd : 26 MiB
- noyau : 13 MiB
- ISO complète : 458 MiB
- Le principal facteur de taille était donc nix-store.squashfs, qui constitue l’essentiel de l’espace utilisateur
- Une fois le squashfs monté, on y trouvait des chemins ressemblant à ceux du Nix store
python3-3.13.13: 128 MiBlinux-6.18.35-modules: 144 MiBsystemd-260.1: 60 MiBperl-5.42.0: 56 MiBgrub-2.12: environ 62 MiB au total sur plusieurs éléments- de la documentation comme
nix-manual-2.34.7etnixos-manual-htmlétait aussi incluse
- Comme l’ISO est construite depuis l’hôte, les chemins du store présents dans l’ISO peuvent aussi être retracés dans le
/nix/storede l’hôte nix why-dependsa été utilisé pour identifier l’origine des dépendances- Boost arrivait via le chemin du démon Nix
- en passant par
nix-daemon.conf,nix, puislibnixutil.so, on atteignaitboost-1.89.0
Retirer Nix et la documentation
- Une première tentative a consisté à enlever Nix de l’image avec
nix.enable = false - La documentation a aussi été désactivée avec
documentation.enable = false - Le premier résultat a été 458 MiB → 384 MiB
- Mais Boost était toujours présent
register-nix-paths.serviceessayait d’enregistrer au démarrage le contenu du store de l’ISO- ce chemin réintroduisait Nix et Boost
- Le service a été vidé puis supprimé avec
systemd.services.register-nix-paths = lib.mkForce {} - L’ISO est alors descendue à 360 MiB, et
nix why-dependsa confirmé l’absence de dépendance à Boost
Suppression d’OpenSSH et des paquets par défaut
- De la même manière, il a aussi été possible de vider
environment.defaultPackages - La suppression de
ssha été plus délicatemodules/programs/ssh.nixajoute OpenSSH àenvironment.corePackages- il n’a pas été possible de trouver une option comme
programs.ssh.enablepour le contrôler services.openssh.enableconcerne la configuration du serveur, pas la suppression du client
- Il était possible d’exclure
programs/ssh.nixavecdisabledModules, mais d’autres modules supposaient ensuite l’existence des optionsprograms.ssh, ce qui provoquait des erreurs en cascade - La solution a été de fournir un stub d’option dans un module séparé, sans utiliser les options
programs.sshoptions.programs.ssh = lib.mkOption {};- puis exclusion du vrai module SSH avec
disabledModules = [ "programs/ssh.nix" ];
- Dans ce processus, les réglages suivants ont aussi été appliqués
documentation.man.enable = falsenetworking.firewall.enable = falseenvironment.defaultPackages = lib.mkForce []
Notes sur la structure des modules NixOS
- Un module NixOS comporte globalement trois parties
- les éléments au niveau du module :
imports,disabledModules - la définition des options :
options.* - l’implémentation :
config.*
- les éléments au niveau du module :
- Les modules qui ne définissent pas d’options peuvent utiliser une forme abrégée avec des propriétés d’implémentation écrites sans préfixe
config. - Pour conserver cette forme abrégée dans le reste de la configuration, le stub d’option
programs.ssha été placé dans un module importé séparément
Retirer les outils d’installation de GRUB
- Parmi les gros éléments restants figuraient environ 62 MiB de fichiers liés à GRUB
- Le chargeur d’amorçage lui-même reste nécessaire, mais il n’était pas jugé utile d’inclure tous les outils d’installation
- Le preset ISO de NixOS embarque à la fois les versions UEFI et BIOS de GRUB
- Faute d’option claire pour les désactiver, une méthode plus brutale a été utilisée en réinitialisant les valeurs suivantes
system.extraDependencies = lib.mkForce []environment.systemPackages = lib.mkForce config.environment.corePackages
environment.systemPackagesn’a pas été vidé complètement- sans
bash,gettypeut entrer dans une boucle de crash, donccorePackagesa été conservé pour garder un shell minimalement fonctionnel
- sans
Suppression des modules du noyau
linux-6.18.35-modulespesait 144 MiB, soit environ un quart de la taille totale- NixOS ne semblait pas offrir de bon point d’accroche pour limiter les modules du noyau utilisés à l’exécution
- À la place, le dossier
kernel-modulesa été supprimé de la sortie systèmesystem.systemBuilderCommands = lib.mkAfter "rm $out/kernel-modules";
- Cette méthode désactive en pratique le chargement dynamique des modules à l’exécution
- les modules nécessaires doivent être placés dans
boot.initrd.kernelModulesouavailableKernelModules
- les modules nécessaires doivent être placés dans
- Après ce changement, il n’était plus possible de passer à une résolution d’affichage plus confortable, mais le démarrage restait possible
- La taille de l’ISO est alors tombée à 197 MiB
Retirer Perl et recourir à des fonctions de remplacement expérimentales
- Il restait encore 56 MiB de Perl
- Avec
nix why-depends, il a été constaté que Perl était utilisé pendant l’activation du système pour configurer les utilisateurs et/etc - Il n’était pas possible d’abandonner complètement la gestion des utilisateurs et de
/etc - À la place, un chemin alternatif expérimental a été utilisé
- gestion de
/etcvia un mécanisme d’overlay - gestion des utilisateurs via userborn en natif
- gestion de
- La configuration appliquée était la suivante
system.etc.overlay.enable = truesystem.etc.overlay.mutable = falseservices.userborn.enable = true
- La taille finale de l’ISO est ainsi descendue à 183 MiB
Résultat final et limites
- Le point de départ de 458 MiB a été ramené à 183 MiB, soit presque un tiers de la taille initiale
- Malgré cela, le résultat n’est pas considéré comme véritablement satisfaisant
- Il ne convient pas à un poste de travail réel ni à un environnement important
- toutes les fonctions supprimées avaient une raison d’être
- En revanche, cela peut servir de référence si l’on a besoin d’une petite image de démarrage expérimentale ne réalisant que des tâches très limitées
- Copier tel quel la configuration finale peut laisser de côté des fonctions nécessaires à l’usage visé
Pistes pour réduire encore
- Ce travail s’est concentré sur des éléments « simplement supprimables » ou pour lesquels il existait un remplacement relativement clair
- Des zones demandant un travail plus profond restent ouvertes
- actuellement,
systemdMinimaletsystemdsont tous deux embarqués - essayer d’en retirer un cassait d’autres chemins de build
- actuellement,
- D’autres petits éléments peuvent encore être supprimés, et leur somme pourrait devenir significative
- Une optimisation supplémentaire demandera davantage d’enquête et d’expérimentation
1 commentaires
Avis sur Lobste.rs
Il existe un module conçu exactement pour ce genre d’usage. Il demande pas mal de compilation, mais il permet de produire un initrd entièrement autonome, incluant tout l’espace utilisateur de NixOS, pour environ 80 MiB une fois compressé avec zstd
Ce travail ne se limite pas aux initrd autonomes et peut servir à réduire la taille de n’importe quel système NixOS. Cela devrait probablement aussi s’appliquer à l’ISO d’installation
https://github.com/wucke13/minimal-nixos/
Le système de base de TinyCore Linux est Core, à 17 MB
Si vous voulez aussi X et FLTK/FLWM, il y a TinyCore à 23 MB, et si vous voulez davantage de gestionnaires de fenêtres et d’applications, il y a CorePlus à 248 MB
http://www.tinycorelinux.net/downloads.html
Je recommande cette présentation de la NixCon sur une réduction de NixOS pour en faire une alternative à Yocto : https://youtu.be/AsXY61laNb8
Ce n’était pas aussi détaillé que je l’espérais, mais ce que j’ai entendu directement d’Óli et Matthew à la conférence était impressionnant. Je me demande s’il existe un billet récapitulatif
J’ai toujours trouvé un peu frustrant de créer une petite empreinte d’installation sur NixOS
On peut probablement réduire la partie SSH avec la configuration suivante
On peut aussi importer
"${nixpkgs}/nixos/modules/profiles/minimal.nix". Il contient une partie des optimisations mentionnées dans l’articleCela dit, dans la plupart des cas, cette approche a sans doute plus de sens
"${nixpkgs}/nixos/modules/profiles/minimal.nix", je l’avais déjà vu auparavant et je l’avais trouvé moins convaincant que prévu, donc je n’ai pas pensé à l’inclure au début de mon enquête. Quand j’y ai repensé plus tard, j’étais déjà arrivé à mi-parcours, et l’ajouter à ce stade, alors qu’il aurait dû figurer dès le début, m’a semblé un peu malhonnêteC’est étrange de voir à quel point Perl est souvent embarqué dans les systèmes de nos jours. Même pour une petite ISO, on se retrouve avec Perl, et si on essaie de compiler quelque chose de sérieux depuis zéro, on tombe sur openssl -> Perl
Avant même de lire, je me suis dit que ce serait sûrement à cause d’un script Perl idiot que personne n’a réécrit en C
Édit : c’était bien ça
À partir de la version 26.05, NixOS utilise systemd dans l’initrd par défaut. En raison du grand nombre de cas d’usage de l’initrd qu’un système d’exploitation moderne doit prendre en charge
systemdMinimalest un binaire systemd compilé avec moins de drapeaux et de dépendances, ce qui aide à garder un initrd plus petitCela dit, si l’objectif est une ISO minimale, il semble possible de faire en sorte que les deux dépendent du même binaire