¿Se puede crear una ISO de NixOS más pequeña?
(natkr.com)- NixOS facilita crear VMs o ISOs solo con configuración, pero incluso una imagen live casi mínima se generó desde el inicio con 458 MiB, una gran diferencia frente a la ISO de VM de Alpine de unos 66 MiB
- La mayor parte del tamaño la ocupaba nix-store.squashfs, que incluía Python 3.13.13, módulos de Linux, systemd, Perl, GRUB, documentación y dependencias relacionadas con Nix
- Tras pasar por
nix.enable = false,documentation.enable = falsey eliminarregister-nix-paths, la ISO se redujo de 458 MiB → 384 MiB → 360 MiB, y también desapareció la dependencia de Boost - Al quitar el cliente de OpenSSH, los paquetes por defecto, las herramientas de instalación de GRUB, los módulos del kernel en tiempo de ejecución y la ruta de activación basada en Perl, el tamaño final bajó hasta 183 MiB
- Puede servir como referencia para imágenes de arranque pequeñas de prueba, pero como elimina muchas funciones necesarias, es difícil usarla tal cual en un escritorio o en entornos importantes
Crear una ISO desde la configuración de NixOS
- NixOS permite crear fácilmente una VM a partir de una configuración
nixos-rebuild build-vmgenera una VM con la configuración actual del sistema- Con
pkgs.nixostambién se puede crear una VM a partir de una configuración arbitraria, aunque no sea la del sistema
- El ejemplo básico crea una VM mínima dejando solo
system.stateVersion = "26.05"yservices.getty.autologinUser = "root" - Esta VM funciona como una thin VM
- La imagen de disco solo contiene los archivos creados directamente dentro de la VM
- El resto, como
/nix/store, se monta desde el sistema operativo anfitrión
- Si el host no tiene Nix, o se quiere ejecutar en un host remoto o en un hipervisor común, hace falta una ISO autocontenida
- Se puede construir una ISO importando el módulo
iso-image.nixde NixOSimage.baseName = lib.mkForce "nixos"define el nombre de la ISO de salida- Un ejemplo de ejecución sería
qemu-system-x86_64 --cdrom .../nixos.iso -m 1G --accel kvm - Si no se está en un entorno Linux moderno amd64, puede ser necesario cambiar la arquitectura o el método de aceleración
Punto de partida: ISO de 458 MiB
- El resultado de la compilación de la ISO base fue de 458 MiB
- Esta imagen todavía ni siquiera incluía
vim- Al arrancar, ejecutar
vimdevolvíacommand not found
- Al arrancar, ejecutar
- Como comparación, la ISO de VM de Alpine usada como referencia pesa unos 66 MiB
- También se menciona a Damn Small Linux como un caso que ofrecía un entorno de escritorio bastante completo con un tamaño mucho menor
- El objetivo no era llegar al nivel de Damn Small Linux, sino comprobar si era posible reducir aunque fuera un poco una ISO de NixOS
Análisis del tamaño dentro de la ISO
- Al montar la ISO y revisarla con
du, el tamaño se repartía asínix-store.squashfs: 416 MiB- initrd: 26 MiB
- kernel: 13 MiB
- ISO completa: 458 MiB
- El principal factor de tamaño era nix-store.squashfs, es decir, el espacio de usuario principal
- Al montar el squashfs aparecían rutas similares a las del 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: unos 62 MiB sumando varios elementos- También se incluían documentos como
nix-manual-2.34.7ynixos-manual-html
- Como la ISO se compila en el host, las rutas del store dentro de la ISO también se pueden rastrear desde el
/nix/storedel host - Con
nix why-dependsse identificó de dónde venían las dependencias- Boost entraba por la ruta del daemon de Nix
- La cadena llevaba por
nix-daemon.conf,nix,libnixutil.sohastaboost-1.89.0
Eliminar Nix y la documentación
- Se intentó quitar Nix de la imagen con
nix.enable = false - También se desactivó la documentación con
documentation.enable = false - El primer resultado fue 458 MiB → 384 MiB
- Pero Boost seguía presente
register-nix-paths.serviceintenta registrar al arrancar el contenido del store de la ISO- Esa ruta volvía a arrastrar Nix y Boost
- Se vació y eliminó ese servicio con
systemd.services.register-nix-paths = lib.mkForce {} - Con eso la ISO bajó a 360 MiB y
nix why-dependsconfirmó que ya no existía la dependencia de Boost
Eliminar OpenSSH y los paquetes por defecto
- De forma similar, también se pudo vaciar
environment.defaultPackages - Quitar
sshfue más complicadomodules/programs/ssh.nixagrega OpenSSH aenvironment.corePackages- No se encontró una opción como
programs.ssh.enablepara controlarlo services.openssh.enablees una opción del servidor, no para eliminar el cliente
- Era posible excluir
programs/ssh.nixusandodisabledModules, pero otros módulos esperaban que existieran las opciones deprograms.ssh, lo que generaba errores en cadena - La solución fue aportar en otro módulo una opción stub que no usara las opciones de
programs.sshoptions.programs.ssh = lib.mkOption {};- Después se excluyó el módulo SSH real con
disabledModules = [ "programs/ssh.nix" ];
- En este proceso también se aplicaron estas configuraciones
documentation.man.enable = falsenetworking.firewall.enable = falseenvironment.defaultPackages = lib.mkForce []
Nota sobre la estructura de módulos en NixOS
- Los módulos de NixOS tienen, en general, tres partes
- Elementos a nivel de módulo:
imports,disabledModules - Definición de opciones:
options.* - Implementación:
config.*
- Elementos a nivel de módulo:
- Los módulos que no definen opciones pueden usar una forma abreviada escribiendo propiedades de implementación sin el prefijo
config. - Para mantener esa forma abreviada en el resto de la configuración, la opción stub de
programs.sshse separó en un módulo importado aparte
Eliminar herramientas de instalación de GRUB
- Uno de los elementos grandes que quedaban eran unos 62 MiB de archivos relacionados con GRUB
- Se concluyó que el bootloader en sí era necesario, pero no hacía falta incluir todas las herramientas de instalación
- El preset de ISO de NixOS empaqueta versiones de GRUB tanto para UEFI como para BIOS
- Como no había una opción clara para desactivarlo, se recurrió a un método más brusco restableciendo estos valores
system.extraDependencies = lib.mkForce []environment.systemPackages = lib.mkForce config.environment.corePackages
environment.systemPackagesno se vació por completo- Sin
bash, getty puede entrar en un crashloop, así que se mantuvieroncorePackagespara que el shell siguiera funcionando al menos de forma básica
- Sin
Eliminar módulos del kernel
linux-6.18.35-modulesocupaba 144 MiB, aproximadamente una cuarta parte del tamaño total- No parecía haber en NixOS un buen gancho para limitar los módulos del kernel usados en tiempo de ejecución
- En su lugar, se eliminó la carpeta
kernel-modulesde la salida del sistemasystem.systemBuilderCommands = lib.mkAfter "rm $out/kernel-modules";
- En la práctica, este método desactiva casi por completo la carga de módulos en tiempo de ejecución
- Los módulos necesarios deben incluirse en
boot.initrd.kernelModuleso enavailableKernelModules
- Los módulos necesarios deben incluirse en
- Después de este cambio se perdió la capacidad de pasar a una resolución de pantalla más cómoda, pero el sistema seguía arrancando
- El tamaño de la ISO bajó hasta 197 MiB
Eliminar Perl y funciones experimentales alternativas
- Todavía seguían presentes 56 MiB de Perl
- Con
nix why-dependsse comprobó que Perl se usaba durante la activación del sistema para configurar usuarios y/etc - No era posible descartar por completo la configuración de usuarios ni de
/etc - En su lugar, se sustituyó la ruta existente por funciones experimentales
- La gestión de
/etcusa un método basado en overlay - La gestión de usuarios usa el userborn nativo
- La gestión de
- Las configuraciones aplicadas fueron estas
system.etc.overlay.enable = truesystem.etc.overlay.mutable = falseservices.userborn.enable = true
- El tamaño final de la ISO quedó en 183 MiB
Estado final y límites
- Se pasó de 458 MiB al inicio a 183 MiB al final, casi un tercio del original
- Aun así, no se considera que el resultado sea realmente “bueno”
- No es adecuado para un escritorio de uso real ni para entornos importantes
- Todas las funciones eliminadas estaban ahí por alguna razón
- Puede servir como referencia si se necesita una imagen de arranque pequeña para pruebas y solo va a realizar tareas muy limitadas
- Copiar la configuración final tal cual puede dejar fuera funciones necesarias para el objetivo real
Margen para reducir más
- Este trabajo se centró en elementos que simplemente podían eliminarse o que tenían sustitutos relativamente claros
- Aún quedan áreas que requerirían un trabajo más profundo
- Actualmente se empaquetan tanto
systemdMinimalcomosystemd - Al intentar quitar uno de los dos, se rompían otras rutas de compilación
- Actualmente se empaquetan tanto
- También quedan elementos pequeños que todavía podrían retirarse y que, sumados, podrían representar un tamaño relevante
- Seguir optimizando requeriría más investigación y experimentación
1 comentarios
Comentarios en Lobste.rs
Hay un módulo hecho justo para esto. Requiere bastante compilación, pero puede crear un initrd completamente autónomo con todo el espacio de usuario de NixOS en unos 80 MiB con compresión zstd
Esto no se limita solo al initrd autónomo; también puede servir para reducir el tamaño de cualquier NixOS. Probablemente también se pueda aplicar a una ISO de instalación
https://github.com/wucke13/minimal-nixos/
El sistema base de TinyCore Linux es Core, de 17 MB
Si además quieres X y FLTK/FLWM, está TinyCore, de 23 MB, y si quieres más gestores de ventanas y aplicaciones, está CorePlus, de 248 MB
http://www.tinycorelinux.net/downloads.html
Recomiendo una charla de NixCon sobre cómo reducir NixOS para usarlo como alternativa a Yocto: https://youtu.be/AsXY61laNb8
No fue tan detallada como esperaba, pero lo que escuché directamente de Óli y Matthew en la conferencia fue impresionante. Me pregunto si habrá algún texto de resumen
En NixOS, siempre resulta un poco frustrante crear una instalación pequeña
Parece que el tamaño de la parte de SSH se puede reducir con la siguiente configuración
También puedes importar
"${nixpkgs}/nixos/modules/profiles/minimal.nix". Ahí ya vienen algunas de las optimizaciones del artículoAun así, en la mayoría de los casos este enfoque probablemente sea más razonable
Ya había visto antes
"${nixpkgs}/nixos/modules/profiles/minimal.nix"y me había parecido menos útil de lo esperado, así que no pensé en incluirlo cuando empecé a investigar. Cuando me acordé después, ya iba por la mitad, y meterlo a la fuerza en una etapa temprana donde debió haber estado originalmente me pareció un poco poco honestoEs extraño la frecuencia con la que Perl termina metiéndose en sistemas actuales. Incluso en una ISO pequeña aparece Perl, y si intentas compilar algo serio desde cero, terminas en openssl -> Perl
Antes de leerlo, ya suponía que sería por algún script de Perl tonto que nadie reescribió en C
Edit: sí, así era
Desde la versión 26.05, NixOS usa systemd en el initrd predeterminado. Esto se debe a la gran cantidad de casos de uso de initrd que un sistema operativo moderno tiene que soportar
systemdMinimales un binario de systemd compilado con menos flags y dependencias, lo que ayuda a mantener más pequeño el initrdPero si el objetivo es una ISO mínima, parece posible hacer que ambos dependan del mismo binario