
2026/06/20 6:55
NixOS イソファイルをもう少し小さくしたい?
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
このテキストの主な目的は、特定の
nix-build 構成と pkgs.nixos を用いて、標準的な NixOS ISO イメージのサイズを 458MB から約 183MB に劇的に縮小する方法を示すことにあります。初期的な比較では、標準的な最小限の VM ISO が Damn Small Linux(約 50MB)や Alpine の VM ISO(約 66MB)といった代替手段よりもはるかに大きいことが示されています。元の 458MB のイメージには、iso/nix-store.squashfs に格納された 416MB のユーザー空間に加え、カーネルと initrd が含まれています。Nix そのもの、ドキュメント、SSH、ファイアウォール、マニュアルページといった不要なサービスを無効にすると、イメージのサイズは段階的に縮小し、register-nix-paths サービスを無効にしパッケージリストをクリアして Boost 依存関係を削除することで約 360MB にまで小さくなります。さらに、オーバーレイ機構を使用して GRUB、カーネルモジュール、Perl 依存関係を削除することで最終的に 183MB に到達します。得られるイメージは非常に特殊化されており、事前の Nix ストアを必要とせず起動し、UEFI および BIOS の両方をサポートしますが、本格的な日常使用に必要なデスクトップコンポーネントを欠いています。したがって、このイメージは遠隔ホストでの実験用としての軽量テストツールとしてのみ利用でき、実用的な生産システムとしては適しません。本文
Linux ライブイメージから機能を引き出し、惜しげなく削ぎ落とす方法
NixOS の設定を仮想マシン (VM) として実行するのはクールですが、必要以上に巨大な ISO イメージになっていることがあります。この記事では、NixOS の設定を「ただの Damn ISO」(最小限のライブメディア)にするための方法を解説します。
1. 最小限の VM からスタートする
まずは
nixos-rebuild build-vm コマンドでシステム構成に基づいて VM を生成する方法から始めます。これは任意の構成に対応し、最小限のディスクイメージを作成できますが、内部には作成者用のファイルしか含まれません(他のストアはホストからマウントされます)。
let pkgs = import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/567a49d1913ce81ac6e9582e3553dd90a955875f.tar.gz"; sha256 = "1vq77hlx8mi3z03pw2nf6r5h7473r1p9yxyf58ym3fh01zppmfln"; }) {}; in pkgs.nixos { system.stateVersion = "26.05"; services.getty.autologinUser = "root"; }
この設定を独立した ISO イメージとして出力するには、以下のコマンドを実行します。
$(nix-build basic-vm.nix --attr vm --log-format bar --no-out-link)/bin/run-nixos-vm
2. QEMU で自前で VM を実行する
libvirt や物理ホストにインストールされていない環境でも動作させるために、QEMU を直接使用して ISO を作成します。
qemu-system-x86_64 \ --cdrom $(nix-build basic-iso.nix --attr isoImage --log-format bar --no-out-link)/iso/nixos.iso \ -m 1G \ --accel kvm
これで「パラダイスのトラブル」が発生しました。ISO サイズは 458 MiB と巨大です。また、基本的なコマンド (
vim など) が動作しません。比較のために、Alpine Linux の VM ISO は約 66 MiB です。
3. メモリの使用状況の分析
ISO の内容を確認するためにマウントし、各コンポーネントのサイズを計測します。
# ISO をマウント sudo mount $(nix-build basic-iso.nix --attr isoImage --log-format bar --no-out-link)/iso/nixos.iso iso --mkdir # サイズ別ソート表示 du iso --all --block-size=1M | sort -n | tail -n10
構成要素のサイズ内訳
- ユーザースペース (
): 416 MiB/nix-store.squashfs - 早期ブート環境 (initrd など): 26 MiB
- カーネル本体: 13 MiB
最大の無駄は squash ファイル です。これを
/nix/store で置き換えて依存関係を調べることで、例えば Boost ライブラリが Nix デモンから導入されていることが分かりました。
4. 削ぎ落としの開始
a) Nix とドキュメントを無効化する
まず、Nix ストア全体の配信とドキュメント生成を無効化します。これですぐにサイズが減少しますが、Boost の依存関係は完全に消えませんでした(起動時処理が残っていたため)。
let pkgs = import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/567a49d1913ce81ac6e9582e3553dd90a955875f.tar.gz"; sha256 = "1vq77hlx8mi3z03pw2nf6r5h7473r1p9yxyf58ym3fh01zppmfln"; }) {}; in pkgs.nixos ({ lib, ... }: { system.stateVersion = "26.05"; services.getty.autologinUser = "root"; imports = [ "${pkgs.path}/nixos/modules/installer/cd-dvd/iso-image.nix" ]; image.baseName = lib.mkForce "nixos"; nix.enable = false; documentation.enable = false; })
サイズは 384 MiB にまで減りましたが、依存関係のクリーンアップが必要です。
b) 起動時の Nix レジストリ登録を無効化
Nix デモンが Boost を呼び出しているのを防ぎます。
systemd.services.register-nix-paths を強制的に空設定します。
in pkgs.nixos ({ lib, ... }: { # ... (上記の共通設定) nix.enable = false; systemd.services.register-nix-paths = lib.mkForce {}; documentation.enable = false; })
これで Boost への依存関係はなくなりました。サイズは 360 MiB。
5. SSH とその他のモジュールの最適化
a) SSH の扱い
environment.defaultPackages から SSH を削除しようとすると、他のモジュール(例:Plasma)でエラーになります。これを解決するには、存在しないオプションへの参照を回避するダミー定義と、SSH モジュール自体を無効化します。また、ファイアウォールも不要なためオフにします。
let pkgs = import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/567a49d1913ce81ac6e9582e3553dd90a955875f.tar.gz"; sha256 = "1vq77hlx8mi3z03pw2nf6r5h7473r1p9yxyf58ym3fh01zppmfln"; }) {}; in pkgs.nixos ({ lib, config, ... }: { system.stateVersion = "26.05"; services.getty.autologinUser = "root"; imports = [ "${pkgs.path}/nixos/modules/installer/cd-dvd/iso-image.nix" # オプション参照の回避用ダミー { options.programs.ssh = lib.mkOption {}; } ]; image.baseName = lib.mkForce "nixos"; nix.enable = false; systemd.services.register-nix-paths = lib.mkForce {}; documentation.enable = false; documentation.man.enable = false; networking.firewall.enable = false; disabledModules = [ # openssh をコアパッケージとしてインジェクトするためのもので、明確なオフスイッチがない "programs/ssh.nix" ]; environment.defaultPackages = lib.mkForce []; })
b) システムパッケージのリセット
インストールツート全体(GRUB など)も削減します。
system.systemPackages を空にしつつ、シェルを使うために corePackages は維持します。また、BIOS と UEFI の両方のブートローダーをバンドルするのを防ぎます。
let pkgs = import (fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/567a49d1913ce81ac6e9582e3553dd90a955875f.tar.gz"; sha256 = "1vq77hlx8mi3z03pw2nf6r5h7473r1p9yxyf58ym3fh01zppmfln"; }) {}; in pkgs.nixos ({ lib, config, ... }: { # ... (共通設定) environment.systemPackages = lib.mkForce config.environment.corePackages; system.extraDependencies = lib.mkForce []; })
c) カーネルモジュールの削除
自動読み込みされるカーネルモジュールは不要なものが多く、144 MiB も消費しています。これらは
boot.initrd.kernelModules に明示的に配置するしかありませんが、単純に system.systemBuilderCommands で /kernel-modules を削除することで大幅に縮減できます(リアルタイムサポートを失います)。
system.systemBuilderCommands = lib.mkAfter "rm $out/kernel-modules";
これでサイズはさらに 197 MiB 削減されます。
d) Perl と /etc の管理
Perl はユーザー設定用として残っていますが、実験的な
/etc オーバーレイ機能と userborn を活用することで、さらに最適化できます。
system.etc.overlay.enable = true; system.etc.overlay.mutable = false; services.userborn.enable = true;
最終的なサイズは 183 MiB です。
6. まとめと展望
結果比較
| ステージ | サイズ (MiB) | 特徴 |
|---|---|---|
| 初期 NixOS VM ISO | 458 | 巨大、機能過多 |
| Nix/Doku off / SSH off | 183 | 約 3 分の 1 に削減 |
注意点
- この構成は「実験用」または「小さなタスク専用」としての用途に限られます。
- デスクトップ環境や重要な業務用途には向きません。
- カーネルモジュールを削除すると、リアルタイム機能など特定のハードウェア利用ができなくなります。
残された課題 (ホムワーク)
とsystemdMinimal
の両方をバンドルしている(現在)。どちらか一方の廃止に成功している者がいれば共有したいです。systemd- その他にも細かな部分でストライプできる可能性がありますが、検証の手間がかかります。
フットノート・補足
- プレビューモードとして機能します。
- ログファイルなども含まれています。
- libvirt XML への直接書き込みは「非常な悪例」ですが、カーネル起動トリックは有効です。
- 物理的なハードウェアが存在するのが事実です(Bezos 氏 notwithstanding)。
- アーキテクチャ (
) やアクセラレータ (-x86_64
) は環境に合わせて調整してください (YMMV)。--accel kvm - 再ビルドに伴うストレージコストは、
を実行して管理してください。nix-collect-garbage - SSH が無いため、エラーメッセージを手動で入力しなければならないことがあります(古代人のような作業)。
- スクワッシュファイルのサイズがマウント後のコンテンツより大きいのは、圧縮されているためです。
- ISO 内にはランタイム依存関係は含まれておらず、ビルド時間に関する依存関係のみを考慮する必要があります。
はサーバー向けであり、クライアントとは関係ありません。services.openssh.enable- NixOS モジュールの多くの場合はインポートされていますが、無効化されている場合でも存在と仮定されます。
- バッジバッチ... (名前を忘れる現象)
- bash が欠如すると getty はクラッシュループに陥る可能性があります。
- 境界線は曖昧ですが、「小さな川が大きな海を作る」ように、小さな変更も積み重なります。