最終更新:
genpack で生成された SquashFS イメージは、ディスクにインストールされた実機環境と、vm コマンドによる QEMU/KVM 準仮想化環境の 2 つの方法で起動できます。いずれの場合も共通の initramfs(dracut-genpack)が overlayfs ルートを構成し、genpack-init が system.ini に基づいて初期設定を行った後に systemd へ制御を渡す、という流れは同じです。
本ドキュメントでは両方式の起動シーケンスを詳細に解説します。
genpack-install でディスクにインストールすると、以下のパーティション構成が作られます。
| パーティション | ファイルシステム | 内容 |
|---|---|---|
| 1: ブートパーティション | FAT32 | EFI ブートローダー、カーネル、initramfs、system.img(4GiB 未満の場合)、system.ini |
| 2: データパーティション | Btrfs | overlayfs upper 層、system(4GiB 以上の場合) |
ブートパーティションのサイズはイメージサイズから自動計算されます。--superfloppy オプションを指定すると、パーティションテーブルを作成せずディスク全体を FAT32 として使用します(データパーティションなし)。
MBR と GPT はディスクサイズに応じて自動選択されます(2TiB 以下かつ 512 バイトセクタなら MBR、それ以外は GPT)。
カーネルコマンドラインには root=systemimg:<UUID> または root=systemimg:auto が指定されます。
genpack-install は各アーキテクチャ向けの GRUB ブートローダーをビルドし、SquashFS イメージの /usr/lib/genpack-install/ に同梱します。
EFI ブートローダー:
grub-mkstandalone を使い、grub.cfg を内蔵した単体 EFI バイナリとして生成されます。ディスク上に外部の設定ファイルを必要としません。
| バイナリ | ターゲット |
|---|---|
bootx64.efi | x86_64 |
bootia32.efi | i386 |
bootaa64.efi | ARM64 |
bootriscv64.efi | RISC-V 64 |
BIOS ブートローダー:
boot.img(MBR ステージ 1)と core.img(grub-mkimage で生成)の組み合わせです。core.img にはプレフィックス (,msdos1)/boot/grub がハードコードされており [10]、ブートパーティションの /boot/grub/grub.cfg を読み込みます。BIOS の場合、grub.cfg はバイナリに内蔵されず、genpack-install がディスクインストール時にブートパーティションへ配置します。
EFI バイナリに内蔵された(BIOS の場合はブートパーティション上の)grub.cfg は以下の処理を行います。
$cmdpath(ブートローダーの起動元パス)からブートパーティションを推定probe -u で UUID を取得system.img を検索system を検索(ラベル data-<UUID> → d-<UUID> → パーティション番号によるフォールバック)loopback コマンドで SquashFS をループバックマウントし set root=loop でルートを切り替え/boot/grub/grub.cfg があれば configfile で委譲 [7]system.cfg があれば source で読み込み [8]LINUX_ARGS 変数でカーネルコマンドラインをカスタマイズ可能panic=30 をデフォルトで付与(明示的な指定がない場合)console=ttyS0,115200n8r console=tty0 を追加(明示的な指定がない場合)linux /boot/kernel root=systemimg:<UUID> $LINUX_ARGS systemd.firstboot=0genpack.transient=1 を追加/boot/kernel と /boot/initramfs を使用(ループバックマウント済み)上記の処理でシステムイメージが見つからなかった場合、データパーティション上の grub.cfg やカーネルでの直接起動を試みるフォールバックパスも存在します [9]。
dracut-genpack は 2 つのフックで構成されます。
cmdline フック(check-systemimg-root.sh):
カーネルコマンドラインの root= パラメータを確認します。root=systemimg:... 形式であれば、genpack のブートシーケンスを開始します。
mount フック(mount-genpack.sh):
root=systemimg:<UUID>: 指定 UUID のパーティションをマウントroot=systemimg:auto: 全 FAT パーティションを走査し system.img を含むものを検出fsck.fat -aw で自動修復後にマウント/run/initramfs/boot/run/initramfs/boot/system.img を検索/run/initramfs/rw/system を使用/run/initramfs/ro にマウント/run/initramfs/ro/usr/libexec/genpack-shutdown を /run/initramfs/shutdown にコピーdracut の initramfs 処理が完了すると、$NEWROOT にルートが切り替わり、/usr/bin/genpack-init が PID 1 として起動します(init=/usr/bin/genpack-init が dracut モジュールにより cmdline に追加される)。
genpack-init は C++ + pybind11 で実装されており、以下の処理を行います。
/run/initramfs/boot/system.ini(ブートパーティション経由)または /run/initramfs/rw/system.ini(データパーティション経由)を読み込む/usr/lib/genpack-init/*.py 内の全 Python モジュールをファイル名順にロードconfigure(ini) 関数を実行(タイムゾーン、ロケール、バナー表示、マシン ID 生成など)exec /sbin/init で systemd に制御を引き渡すvm コマンドは genpack イメージを QEMU/KVM で直接起動するためのツールです。ディスクへのインストールは不要で、SquashFS ファイルをそのまま指定して起動できます。
vm コマンドは squashfuse ライブラリを使用して、SquashFS イメージの /boot/ ディレクトリからカーネルと initramfs を直接読み出します。ディスクに展開する必要はなく、memfd_create で作成したメモリ上のファイルディスクリプタに書き出して QEMU に渡します。
検索順序:
boot/kernel または boot/vmlinuz(固定名)boot/kernel-* または boot/vmlinuz-*(タイムスタンプが最新のもの)initramfs も同様に boot/initramfs, boot/initramfs.img, boot/initrd.img の順で検索されます。
カーネルバイナリの ELF ヘッダまたは PE ヘッダからアーキテクチャ(x86_64, aarch64, riscv64 等)を自動判定し、対応する qemu-system-<arch> を起動します。
vm コマンドは QEMU のダイレクトカーネルブート(-kernel, -initrd, -append)を使用します。ブートローダーは介在しません。
カーネルコマンドライン:
root=/dev/vda ro net.ifnames=0 systemd.firstboot=0 systemd.hostname=<vmname> console=...
root=/dev/vda: SquashFS イメージが virtio-blk デバイスとして提供されるroot=fs rootfstype=virtiofs rwディスクの提供:
| virtio デバイス | シリアル | 内容 |
|---|---|---|
| vda | system | SquashFS イメージ(読み取り専用) |
| vdb | data | データディスク(あれば) |
| vdc | swap | スワップファイル(あれば) |
SquashFS イメージは virtio-blk-pci デバイスとして read-only で接続されます。initramfs の mount-genpack.sh は root=block:* ではなくカーネルコマンドラインの root=/dev/vda を参照し、/dev/vda を直接 SquashFS として /run/initramfs/ro にマウントします。
virtiofs モード:
vm コマンドは virtiofs もサポートしています。virtiofsd を起動してホストのディレクトリをゲストに共有し、overlayfs の upper 層として使用できます。virtiofs 使用時、initramfs は root=fs rootfstype=virtiofs rw に基づいて virtiofs をルートとしてマウントします。
vm コマンドには vm.ini ファイルを読み取るサービスモードがあります。各 VM のディレクトリ構成は以下の通りです。
vm.ini の type=genpack(デフォルト)でダイレクトカーネルブートが使用されます。
| 項目 | system.img 方式 | パラバーチャル方式 |
|---|---|---|
| ブートローダー | GRUB (EFI/BIOS) | なし(ダイレクトカーネルブート) |
| カーネル格納場所 | ブートパーティション上のファイル | SquashFS 内から memfd に抽出 |
| root= パラメータ | systemimg:<UUID> or systemimg:auto | /dev/vda |
| SquashFS の提供 | ブート/データパーティション上のファイル | virtio-blk デバイス |
| データ永続化 | Btrfs パーティション | data ディスクファイルまたは virtiofs |
| トランジェントモード | genpack.transient カーネルパラメータ | data ディスクを指定しなければ自動 |
| system.ini | FAT32 パーティション上 | virtiofs 経由または fw_cfg |
| initramfs の動作 | 共通(dracut-genpack) | 共通(dracut-genpack) |
| genpack-init の動作 | 共通 | 共通 |
genpack イメージのシャットダウンは通常の systemd シャットダウンプロセスの後、dracut の initramfs に制御が戻り、/run/initramfs/shutdown(genpack-shutdown)が実行されます。genpack-shutdown は以下を行います。
/oldroot 以下の全マウントポイントを逆順にアンマウント/run/initramfs/rw(データパーティション)と /run/initramfs/boot(ブートパーティション)を安全に移動・アンマウントboottime.txt を削除 [1]reboot(2) または poweroff を実行d-<UUID> が現在の正式なラベルフォーマットです(Btrfs のラベル長制限のため短縮形を使用)。data-<UUID> および wbdata-<UUID> は Walbrix(genpack の前身)時代の互換性のために残されています。 ↩/usr のタイムスタンプを参照して ld.so.cache の再生成が必要かを判定します。overlayfs では upper 層が存在すると lower 層のタイムスタンプが隠されるため、lower 層の /usr タイムスタンプを明示的に upper 層に伝播させる必要があります。 ↩rw/rw/root という冗長なパスでした。rw/root に簡略化されましたが、既存環境との互換性のため initramfs は旧パス rw/rw/root も引き続き認識します。 ↩BOOT_PARTITION と BOOT_PARTITION_UUID がエクスポートされるため、委譲先の grub.cfg からもブートパーティション情報を参照できます。 ↩このドキュメントは以下のリポジトリのスナップショットに基づいて作成されました: