Dá para criar uma ISO menor do NixOS?
(natkr.com)- O NixOS facilita criar VMs ou ISOs apenas com configuração, mas até uma imagem live quase mínima já é gerada com 458MiB desde o início, uma diferença grande em relação à ISO de VM do Alpine com cerca de 66MiB
- A maior parte do tamanho vinha de nix-store.squashfs, que incluía Python 3.13.13, módulos do Linux, systemd, Perl, GRUB, documentação e dependências relacionadas ao Nix
- Ao passar por
nix.enable = false,documentation.enable = falsee removerregister-nix-paths, a ISO caiu de 458MiB → 384MiB → 360MiB, e a dependência de Boost também saiu - Removendo também o cliente OpenSSH, pacotes padrão, ferramentas de instalação do GRUB, módulos de kernel em tempo de execução e o caminho de ativação baseado em Perl, o tamanho final caiu para 183MiB
- Pode servir como referência para imagens de boot pequenas e experimentais, mas como remove muitos recursos necessários, é difícil usar isso como está em desktops ou ambientes importantes
Criando uma ISO a partir da configuração do NixOS
- O NixOS permite criar VMs facilmente com base em configuração
nixos-rebuild build-vmgera uma VM da configuração atual do sistema- Usando
pkgs.nixos, também é possível criar uma VM a partir de uma configuração arbitrária, mesmo que não seja a do sistema
- O exemplo básico gera uma VM mínima deixando apenas
system.stateVersion = "26.05"eservices.getty.autologinUser = "root" - Essa VM funciona como uma thin VM
- A imagem de disco inclui apenas os arquivos criados diretamente dentro da VM
- O restante, como
/nix/store, é montado a partir do sistema operacional hospedeiro
- Para executar em um host sem Nix, em um host remoto ou em um hipervisor comum, é necessária uma ISO autossuficiente
- É possível construir uma ISO importando o módulo
iso-image.nixdo NixOSimage.baseName = lib.mkForce "nixos"define o nome da ISO gerada- Um exemplo de execução tem a forma
qemu-system-x86_64 --cdrom .../nixos.iso -m 1G --accel kvm - Se o ambiente não for um Linux moderno em amd64, talvez seja necessário mudar a arquitetura ou a forma de aceleração
Ponto de partida: ISO de 458MiB
- O resultado da build da ISO padrão foi de 458MiB
- Essa imagem ainda nem incluía
vim- Depois do boot, ao executar
vim, apareciacommand not found
- Depois do boot, ao executar
- Como comparação, a ISO de VM do Alpine usada como referência tinha cerca de 66MiB
- O Damn Small Linux aparece como exemplo de um sistema que oferecia um ambiente de desktop bem acabado em um tamanho muito menor
- O objetivo não era chegar ao nível do Damn Small Linux, e sim verificar se dava para reduzir a ISO do NixOS ao menos um pouco
Análise do tamanho dentro da ISO
- Ao montar a ISO e verificar com
du, o tamanho estava dividido assimnix-store.squashfs: 416MiB- initrd: 26MiB
- kernel: 13MiB
- ISO inteira: 458MiB
- O principal fator de tamanho era o espaço de usuário principal,
nix-store.squashfs - Ao montar o squashfs, apareciam caminhos parecidos com o Nix store
python3-3.13.13: 128MiBlinux-6.18.35-modules: 144MiBsystemd-260.1: 60MiBperl-5.42.0: 56MiBgrub-2.12: cerca de 62MiB somando vários itens- Também havia documentação como
nix-manual-2.34.7enixos-manual-html
- Como a ISO é construída no host, os caminhos do store dentro da ISO também podem ser rastreados no
/nix/storedo host nix why-dependsfoi usado para descobrir de onde vinham as dependências- O Boost entrava pelo caminho do daemon do Nix
- Passando por
nix-daemon.conf,nixelibnixutil.so, chegava-se aboost-1.89.0
Removendo Nix e documentação
- Foi feita uma tentativa de remover o próprio Nix da imagem com
nix.enable = false - A documentação também foi desativada com
documentation.enable = false - O primeiro resultado foi 458MiB → 384MiB
- Mas o Boost ainda continuava presente
register-nix-paths.servicetentava registrar no boot o conteúdo do store da ISO- Esse caminho acabava puxando Nix e Boost de volta
- Com
systemd.services.register-nix-paths = lib.mkForce {}o serviço foi esvaziado e removido - Com isso, a ISO passou a 360MiB, e
nix why-dependsconfirmou que a dependência de Boost havia sumido
Removendo OpenSSH e pacotes padrão
- De forma parecida, também foi possível esvaziar
environment.defaultPackages - Remover
sshfoi mais complicadomodules/programs/ssh.nixadiciona o OpenSSH aenvironment.corePackages- Não foi encontrada uma opção como
programs.ssh.enablepara controlar isso services.openssh.enableé configuração de servidor, não uma opção para remover o cliente
- Era possível excluir
programs/ssh.nixcomdisabledModules, mas outros módulos esperavam a existência das opçõesprograms.ssh, o que gerava erros em cascata - A solução foi fornecer em um módulo separado uma opção stub que não usa
programs.sshoptions.programs.ssh = lib.mkOption {};- Depois disso, o módulo real de SSH foi excluído com
disabledModules = [ "programs/ssh.nix" ];
- Nesse processo, também foram aplicadas as configurações abaixo
documentation.man.enable = falsenetworking.firewall.enable = falseenvironment.defaultPackages = lib.mkForce []
Nota sobre a estrutura de módulos do NixOS
- Os módulos do NixOS têm, em geral, três partes
- Itens no nível do módulo:
imports,disabledModules - Definição de opções:
options.* - Implementação:
config.*
- Itens no nível do módulo:
- Módulos que não definem opções podem usar uma forma abreviada e escrever propriedades de implementação sem o prefixo
config. - Para manter a forma abreviada no restante da configuração, a opção stub
programs.sshfoi separada em um módulo importado à parte
Removendo ferramentas de instalação do GRUB
- Um dos grandes itens restantes era o conjunto de arquivos do GRUB, com cerca de 62MiB
- A conclusão foi que o bootloader em si é necessário, mas não é preciso incluir todas as ferramentas de instalação
- O preset de ISO do NixOS empacota tanto a versão UEFI quanto a versão BIOS do GRUB
- Como não havia uma opção clara para desligar isso, foi usado um método mais bruto para redefinir os seguintes valores
system.extraDependencies = lib.mkForce []environment.systemPackages = lib.mkForce config.environment.corePackages
environment.systemPackagesnão foi totalmente esvaziado- Sem
bash, o getty pode entrar em crashloop constante, entãocorePackagesfoi mantido para garantir que o shell continue funcionando minimamente
- Sem
Removendo módulos do kernel
linux-6.18.35-modulestinha 144MiB, cerca de um quarto do tamanho total- Não parecia existir no NixOS um bom hook para limitar os módulos de kernel usados em tempo de execução
- Em vez disso, a pasta
kernel-modulesfoi removida do output do sistemasystem.systemBuilderCommands = lib.mkAfter "rm $out/kernel-modules";
- Na prática, isso desativa quase totalmente o carregamento de módulos em tempo de execução
- Os módulos necessários precisam estar em
boot.initrd.kernelModulesouavailableKernelModules
- Os módulos necessários precisam estar em
- Depois dessa mudança, perdeu-se a capacidade de trocar para uma resolução de tela mais confortável, mas o sistema ainda inicializava
- O tamanho da ISO caiu para 197MiB
Removendo Perl e recursos alternativos experimentais
- Ainda restavam 56MiB de Perl
- Com
nix why-depends, foi verificado que o Perl era usado durante a ativação do sistema para configurar usuários e/etc - Não era possível simplesmente abandonar por completo a configuração de usuários e
/etc - Em vez disso, o caminho existente foi substituído por recursos experimentais
- O gerenciamento de
/etcpassou a usar o modo overlay - O gerenciamento de usuários passou a usar o userborn nativo
- O gerenciamento de
- As configurações aplicadas foram as seguintes
system.etc.overlay.enable = truesystem.etc.overlay.mutable = falseservices.userborn.enable = true
- O tamanho final da ISO chegou a 183MiB
Estado final e limitações
- O tamanho caiu do ponto de partida de 458MiB para 183MiB, ficando em algo próximo de um terço do original
- Ainda assim, o resultado não foi considerado exatamente “bom”
- Não é adequado para desktops de uso real nem para ambientes importantes
- Todos os recursos removidos existiam por algum motivo
- Pode servir de referência quando for preciso uma imagem de boot pequena e experimental, capaz de executar apenas tarefas bem limitadas
- Copiar a configuração final tal como está pode deixar de fora recursos necessários para o objetivo desejado
Espaço para reduzir ainda mais
- Este trabalho focou em itens que podiam ser “simplesmente removidos” ou que tinham alternativas relativamente claras
- Ainda existem áreas que exigem trabalho mais profundo
- Atualmente,
systemdMinimalesystemdsão empacotados juntos - Ao tentar remover um dos dois, outros caminhos de build quebravam
- Atualmente,
- Também há itens menores que ainda poderiam ser eliminados, e somados podem representar uma redução relevante
- Otimizações adicionais exigem mais investigação e experimentação
1 comentários
Opiniões no Lobste.rs
Existe um módulo feito exatamente para esse tipo de uso. Exige bastante compilação, mas dá para criar um initrd totalmente autônomo com todo o espaço de usuário do NixOS em cerca de 80 MiB com compressão zstd
Isso não se limita só a initrds autônomos; também pode ser usado para reduzir o tamanho de qualquer NixOS. Provavelmente também dá para aplicar a ISOs de instalação
https://github.com/wucke13/minimal-nixos/
O sistema base do TinyCore Linux é o Core, com 17 MB
Se você quiser X e FLTK/FLWM, existe o TinyCore, com 23 MB; e se quiser mais gerenciadores de janelas e aplicativos, existe o CorePlus, com 248 MB
http://www.tinycorelinux.net/downloads.html
Recomendo a apresentação da NixCon sobre reduzir o NixOS para servir como alternativa ao Yocto: https://youtu.be/AsXY61laNb8
Não foi tão detalhada quanto eu esperava, mas o que ouvi diretamente do Óli e do Matthew na conferência foi impressionante. Fico curioso se existe algum texto resumindo isso
No NixOS, sempre é meio frustrante tentar montar uma instalação pequena
Acho que dá para reduzir o tamanho da parte de SSH com as configurações abaixo
Você também pode importar
"${nixpkgs}/nixos/modules/profiles/minimal.nix". Ele já inclui parte das otimizações feitas no textoMesmo assim, na maioria dos casos essa abordagem provavelmente é mais sensata
Eu já tinha visto
"${nixpkgs}/nixos/modules/profiles/minimal.nix"antes e achado menos útil do que esperava, então nem pensei em incluí-lo quando comecei a investigar. Quando lembrei dele depois, eu já estava com o trabalho pela metade, e enfiá-lo de volta no começo, onde deveria ter entrado, pareceu um pouco desonestoHoje em dia é estranho como Perl acaba sendo puxado para tantos sistemas. Até em uma ISO pequena tem Perl, e se você tenta compilar algo minimamente sério do zero, acaba caindo em openssl -> Perl
Antes mesmo de ler, eu já imaginava que seria culpa de algum script em Perl idiota que ninguém reescreveu em C
Edit: era isso mesmo
A partir do NixOS 26.05, o initrd padrão usa systemd, por causa do grande número de casos de uso de initrd que um sistema operacional moderno precisa suportar
systemdMinimalé um binário do systemd compilado com menos flags e dependências, o que ajuda a manter o initrd menorMas, se o objetivo for uma ISO mínima, talvez dê para fazer os dois dependerem do mesmo binário