genpack — Gentoo ベースの不変システムイメージビルドツールチェーン

English version

はじめに

genpack は、Gentoo Linux をベースとして用途特化型の不変 (immutable) システムイメージを宣言的に生成・配布・起動するための一連のツール群です。従来の「OS をインストールしてからカスタマイズする」アプローチとは異なり、設計図 (JSON5) から OS イメージ全体をビルドするというイメージファクトリの考え方に基づいています。

Docker がアプリケーションコンテナの世界で実現したことを、OS 全体のレベルで、しかもベアメタル・仮想マシン・組み込み機器を横断して実現することを目指しています。

ツールチェーンの構成

genpack-overlayGentoo オーバーレイ:
プロファイル・ebuild
genpackイメージビルダー
genpack-installディスク書込 / ISO /
セルフアップデート
.squashfs / .img ↓
genpack-artifacts各イメージの設定定義集
genpack-init毎回起動時の
プロビジョニング
vmQEMU/KVM で
仮想マシンとして実行

各コンポーネント一覧

コンポーネント言語役割リポジトリ
genpackPython + C++JSON5 設定から SquashFS イメージを生成wbrxcorp/genpack
genpack-overlayGentoo ebuild/profileパッケージ定義・プロファイル階層・初期化スクリプト群wbrxcorp/genpack-overlay
genpack-initC++ + Python (pybind11)毎回起動時に system.ini に基づきシステムを構成wbrxcorp/genpack-init
genpack-installC++イメージをディスク/ISO/ZIP にデプロイ、セルフアップデートwbrxcorp/genpack-install
vmC++genpack イメージを QEMU/KVM 上で実行・管理shimarin/vm
genpack-artifactsJSON5 + シェルスクリプト具体的なイメージ定義の集合genpack-artifacts (GitHub Org)

genpack — イメージビルダー

GitHub: wbrxcorp/genpack

genpack はツールチェーンの中核をなすビルドエンジンです。genpack.json5 という宣言的な設定ファイルを入力として受け取り、Gentoo Linux の stage3 + Portage を使って最適化された SquashFS イメージを生成します。

ビルドの仕組み: レイヤードアーキテクチャ

genpack は lower/upper の 2 層構造 でビルドを行います。

  1. Lower 層: Gentoo stage3 をベースに、全パッケージを systemd-nspawn コンテナ内でコンパイル・インストールする完全なビルド環境
  2. Upper 層: Lower 層から実行時に必要なファイルだけを選択的にコピーし、ユーザー作成・サービス有効化・カスタムファイル配置などの仕上げを実行
  3. パック: Upper 層を SquashFS に圧縮して最終イメージを生成

この設計により、コンパイラやヘッダファイルなどビルド時にしか使わないファイルは Lower 層に残り、最終イメージには含まれません。最小限のランタイムイメージが自然に得られます。

宣言的な設定

{
  name: "nextcloud",
  profile: "paravirt",
  packages: [
    "www-apps/nextcloud",
    "dev-db/mysql",
    "dev-lang/php",
    "net-misc/redis"
  ],
  services: ["apache2", "mysqld", "redis"],
  users: [{ name: "nextcloud", uid: 1000 }],
  use: {
    "dev-lang/php": "+mysql +curl +gd +xml +zip"
  },
  compression: "xz"
}

パッケージリスト、有効にするサービス、ユーザー定義、USE フラグ、カーネル設定まで、全てがこの 1 ファイルに集約されます。これにより手作業によるシステム構築を排除し、完全に再現可能なビルドを実現しています。

主要コマンド

コマンド機能
genpack buildフルビルド (lower → upper → pack)
genpack lowerLower 層のビルド/リビルド
genpack upperUpper 層のビルド/リビルド
genpack packSquashFS イメージの生成
genpack bashLower 層内の対話シェル
genpack archive設定の tar.gz アーカイブを作成

対応アーキテクチャ

x86_64, aarch64 (ARM64), i686, riscv64 に対応しています。アーキテクチャ固有の設定は genpack.json5arch セクションで管理できます。


genpack-overlay — Gentoo オーバーレイ

GitHub: wbrxcorp/genpack-overlay

genpack-overlay は Gentoo のパッケージ管理システム (Portage) を拡張するオーバーレイです。genpack でビルドするイメージの「部品」となるメタパッケージ群と、デプロイ先の違いを吸収するプロファイル階層を提供します。

プロファイル階層

genpack/base (全環境共通: カーネル, init, 基本ツール)
  ├── genpack/systemimg (ベアメタル: ハードウェア検出, ストレージツール)
  │     └── systemimg/baremetal (BIOS/UEFI, デバイスドライバ)
  ├── genpack/paravirt (仮想化: QEMU ゲストエージェント, virtio)
  ├── genpack/gnome (GNOME デスクトップ)
  └── genpack/weston (Wayland コンポジタ)

イメージ定義側は profile: "paravirt"profile: "gnome/baremetal" を指定するだけで、適切なベース環境が自動的に選択されます。

パッケージスクリプト

各パッケージは /usr/lib/genpack/package-scripts/ 以下に初期化スクリプトを配置できます。MySQL のデータディレクトリ初期化、Docker のストレージ設定、SSH ホスト鍵の生成など、パッケージ固有の構成処理がここに定義されています。


genpack-init — 起動時プロビジョニングシステム

GitHub: wbrxcorp/genpack-init

genpack-init は C++ と Python (pybind11) のハイブリッドで構成された初期化システムです。PID 1 として起動し、毎回の起動時に ブートパーティション上の system.ini を読み取って Python スクリプト群を実行し、システムを構成します。

動作の流れ

  1. PID 1 として起動
  2. /run/initramfs/boot/system.ini (FAT パーティション上) を読み込み
  3. /usr/lib/genpack-init/*.py の各モジュールの configure(ini) 関数を実行
  4. ホスト名、ネットワーク、ストレージ、サービス構成などを適用
  5. 実際の init (/sbin/init = systemd) に exec で移行

Python に公開されるネイティブ機能

genpack-init は pybind11 を通じて以下のような低レベル操作を Python スクリプトに公開します:

system.ini 駆動アーキテクチャ

genpack-init の最も重要な設計上の特徴は、FAT パーティション上の system.ini だけでシステム全体の動作をカスタマイズできる点にあります。

パーティション 1: FAT32 (ブート)
EFI/ — ブートローダー
system.img — SquashFS OS イメージ
system.ini ← ユーザーが編集する唯一のファイル
パーティション 2: データ [任意]

ルートファイルシステムの構成: overlayfs による柔軟な永続性制御

genpack イメージの initramfs は、起動時にブートストレージ上のデータパーティション(QEMU の場合はデータ用仮想ディスク)の有無を検出し、overlayfs ルートファイルシステムの upper layer を動的に決定します:

この仕組みにより、同一イメージでありながらデプロイ構成によって動作特性を使い分けることができます。データパーティションを設けない構成ではキオスク端末やデモ環境のような「毎回リセットされる」運用が、データパーティションを設ける構成ではサーバーのような永続的な運用がそれぞれ可能です。いずれの場合も、genpack-init は毎回起動時に system.ini を読んでシステムを構成するため、system.ini の変更は常に次回起動時に反映されます。

system.ini がもたらす利点


genpack-install — イメージデプロイツール

GitHub: wbrxcorp/genpack-install

genpack-install は生成されたシステムイメージを物理ストレージに書き込み、ブート可能な状態にするツールです。

動作モード

モード用途
--disk=<device>物理ディスクへのインストール (パーティショニング + ブートローダー設置)
セルフアップデート稼働中のシステムのイメージをアトミックに入れ替え
--cdrom=<file>ブータブル ISO 9660 イメージの作成
--zip=<file>ZIP アーカイブの作成

マルチアーキテクチャブート対応

BIOS / UEFI (x86_64, i386, ARM64, RISC-V) / Raspberry Pi の各ブート方式に対応した GRUB ブートローダーを生成・配置します。El Torito による CD/ISO ブートもサポートしています。

アトミックなセルフアップデート

稼働中のシステムのイメージ更新は、以下のアトミックなリネーム操作で実現されます:

system     → system.cur  (現在のイメージを退避)
system.new → system      (新しいイメージを有効化)
system.cur → system.old  (前世代を保持 = ロールバック可能)

vm — 仮想マシン管理ツール

GitHub: shimarin/vm

vm は genpack で生成したシステムイメージを QEMU/KVM 上で仮想マシンとして実行・管理するためのコマンドラインツールです。

主要コマンド

コマンド機能
vm run <image>システムイメージから VM を起動
vm servicevm.ini に基づいて VM をサービスとして実行
vm console <name>VM のシリアルコンソールに接続
vm stop <name>QMP プロトコルによるグレースフルシャットダウン
vm list実行中の VM を一覧表示
vm ssh user@vmvsock 経由で VM に SSH 接続
vm usbUSB デバイスの列挙 (XPath クエリ対応)

主な機能


genpack-artifacts — イメージ定義集

GitHub Organization: genpack-artifacts

genpack-artifacts は、genpack ツールチェーンを使って構築する具体的なシステムイメージの定義集です。各アーティファクトは個別のリポジトリとして管理されています。

アーティファクトの構造

artifact-name/
├── genpack.json5          # 宣言的イメージ定義
├── files/                 # ルートファイルシステムにマージされるファイル
│   ├── build.d/           # ビルド時実行スクリプト
│   ├── etc/               # 設定ファイル
│   └── boot/              # ブート設定 (grub.cfg 等)
├── kernel/                # カーネルカスタマイズ (任意)
│   └── config.d/          # カーネル設定フラグメント
└── savedconfig/           # Portage savedconfig (アーキテクチャ別)

アーティファクトの例

カテゴリアーティファクト用途
デスクトップgnome, streamerGNOME デスクトップ、OBS 配信ワークステーション
ML/AItorchPyTorch + ROCm/CUDA 機械学習環境
クラウドnextcloud, owncloudセルフホストクラウドストレージ
プロジェクト管理redmineRedmine プロジェクト管理
ネットワークvpnhub, walbrixVPN ゲートウェイ、ネットワークアプライアンス
セキュリティsuricata, borgIDS、バックアップサーバー
組み込みcameraモーション検知カメラシステム
ユーティリティrescue, stubシステムリカバリ、マルチディストリビューション VM プロビジョニング

最小構成 (rescue: 十数パッケージ) からフルデスクトップ (gnome: 数百パッケージ) まで、全て同じ genpack.json5 + files/ のパターンで定義されています。


設計思想

1. 宣言的イメージ定義 (Infrastructure as Code)

全てのイメージは genpack.json5 で宣言的に定義されます。パッケージ、USE フラグ、ユーザー、サービス、カーネル設定まで 1 ファイルに集約されており、手作業を排除した再現可能なビルドを実現しています。

2. 不変イメージと柔軟な永続性 (Immutable Image, Flexible Persistence)

最終成果物は読み取り専用の SquashFS です。システムの更新は既存環境の変更ではなく新しいイメージのビルドとアトミックな入れ替えで行われます。実行時のルートファイルシステムは overlayfs で構成され、データパーティションの有無により upper layer が永続ストレージか tmpfs かが自動的に決まります。データパーティションがない場合は毎回クリーンな状態から起動するため構成ドリフトが原理的に発生せず、データパーティションがある場合はサーバー用途に適した永続的な運用が可能です。

3. OS とユーザー設定の完全な分離

OS イメージ (SquashFS) は不変、ユーザー設定 (system.ini) は FAT パーティション上のテキストファイル。この 2 つが完全に分離されているため、OS の更新で設定が失われることがなく、設定変更に Linux の専門知識も不要です。

4. 毎回起動時の構成適用

genpack-init は初回だけでなく毎回の起動時に system.ini を読んでシステムを構成します。これにより、system.ini への変更は常に次回起動時に反映されます。さらに、データパーティションを設けないトランジェントモードでは overlayfs の upper layer が tmpfs となるため、実行中の変更は再起動で自動的に消失し、毎回クリーンな状態 + system.ini の設定で起動します。

5. レイヤードビルドによる最小イメージ

Lower 層 (ビルド環境) と Upper 層 (ランタイム) を分離し、実行時に不要なコンパイラやヘッダを自然に除外します。

6. Gentoo の選択

ベースに Gentoo を採用することで:

7. マルチアーキテクチャ・マルチターゲット

x86_64 / aarch64 / i686 / riscv64 のアーキテクチャと、BIOS / UEFI / Raspberry Pi のブート方式をツールチェーン全体で横断的にサポートしています。


ワークフロー全体像

  1. 設計: genpack.json5 を記述
  2. ビルド: genpack build
  3. デプロイ (いずれかを選択)
  4. 起動時: genpack-init が system.ini を読んでシステムを構成
  5. 運用: system.ini を編集して再起動 = 設定変更 / 新イメージでセルフアップデート = OS 更新

genpack の独自性について

同様の目的を持つツールは数多く存在し、その多くは genpack より成熟しています。

ツールアプローチベース
NixOS宣言的 OS 構成、ハッシュベースの再現性Nix パッケージマネージャ
Yocto / OpenEmbeddedソースからの組み込み Linux イメージ生成BitBake 独自ビルドシステム
Buildrootシンプルな組み込み Linux ビルダー独自 Kconfig ベース
mkosisystemd 公式のイメージビルダーDebian/Fedora/Arch 等のバイナリパッケージ
OSTree (Silverblue 等)不変 OS + アトミック差分更新Fedora/RHEL
Ignition (CoreOS/Flatcar)初回起動時のプロビジョニングContainer Linux
cloud-initクラウド向け初回構成各種ディストリビューション

genpack は NixOS の理論的厳密さも、Yocto のエンタープライズ対応も、OSTree の差分更新効率も持っていません。しかし、以下の点で固有のポジションを占めています。

「FAT32 + INI」という意図的に原始的なインターフェース

ツール構成インターフェース編集に必要な環境
NixOSconfiguration.nix (Nix 言語)Nix の理解 + テキストエディタ
IgnitionJSON (machine-readable)通常は別ツールで生成
cloud-initYAMLテキストエディタ + YAML 知識
Kairos / TalosYAML API専用 CLI / API
genpackINI on FAT32Windows のメモ帳

多くの不変 OS は構成の受け渡しに YAML や JSON を使いますが、これらは技術者が技術者のために設計したインターフェースです。cloud-init は強力ですが YAML のインデントミスは初心者を容赦なく突き放し、Ignition に至っては人間が直接書くことを想定していません。

genpack は構成インターフェースを意図的に技術的洗練から遠ざけています。FAT32 は「どの OS でもマウントできる」唯一のファイルシステムであり、INI は「メモ帳で壊さずに編集できる」最もシンプルな構造化フォーマットです。この組み合わせは、高度に最適化された Linux システムの操作権限を非技術者に渡すための意識的な設計です。

毎回起動時実行 + ハードウェア検出による永続性の自動決定

Ignition は初回起動時のみ実行される設計で、「プロビジョニングは一度行えば十分」というクラウドネイティブの前提に立っています。cloud-init も基本的に同様です。

genpack-init は毎回の起動時に実行されます。さらに、overlayfs の upper layer を永続ストレージにするか tmpfs にするかを、データパーティション(または仮想ディスク)の物理的な存在の有無から自動決定します。

この動作モードの切り替えに設定変更は一切不要で、ハードウェア構成だけで決まります。「データ用ディスクを抜く」という物理的操作だけでサーバーをキオスクに変えられます。これは Ignition や cloud-init にはない発想です。

Gentoo を不変イメージのベースに使うという逆転

Gentoo は「自分で全てをカスタマイズし続ける」ディストリビューション——典型的な可変 (mutable) システムの代表として知られています。genpack はこの Gentoo を不変イメージの素材として使います。

Yocto も「ソースからビルドして不変イメージを作る」点では同じですが、BitBake という独自のビルドシステムとレシピ形式の学習コストが非常に高くなります。genpack は Gentoo の既存エコシステム (Portage, ebuild, プロファイル, USE フラグ) をそのまま活用し、新しいパッケージ形式もビルドシステムも発明しません。これにより、Gentoo の持つ「ソースレベルの最適化制御」「USE フラグによる依存の精密な削減」「豊大なパッケージリポジトリ」という利点を、不変イメージの文脈でそのまま享受できます。

ビルド時の lower/upper 分離による暗黙的な最小化

Docker の multi-stage build は「ビルドステージと実行ステージを分ける」という明示的な操作を必要とします。Nix は closure 解析でランタイム依存を自動追跡しますが、Nix の高度な仕組みに依存しています。

genpack の lower/upper 分離は、より素朴ですが効果的な手法です。Lower 層で全パッケージ(ビルド依存含む)をインストールしてファイルリストを記録し、Upper 層ではランタイムパッケージに属するファイルだけを選択的にコピーします。buildtime_packages に指定したパッケージのファイルは upper 層にコピーされないため、GCC やヘッダファイルが最終イメージに混入しません。Gentoo の Portage が持つパッケージ単位のファイル追跡機能を活用した、genpack 固有の最小化メカニズムです。

genpack-init の pybind11 プラグインアーキテクチャ

cloud-init は Python で書かれていますがモジュールの拡張には cloud-init 自体の理解が必要で、Ignition は Go のモノリシックなバイナリで拡張を基本的に想定していません。多くの組み込み init システムはシェルスクリプトベースです。

genpack-init は C++ で実装した低レベル操作(ディスク操作、coldplug、mount)を pybind11 で Python に公開し、プロビジョニングロジック自体は configure(ini) 関数を持つ Python スクリプトとして /usr/lib/genpack-init/ に配置するプラグイン方式を採っています。新しい構成機能の追加は Python ファイルを 1 つ書いて所定ディレクトリに置くだけで、C++ の再コンパイルは不要です。ハードウェア操作のパフォーマンスと構成ロジックの記述の容易さを両立しています。

まとめ

genpack の固有性は個々の技術的優位ではなく、「高度に最適化された Linux イメージを、非技術者でも運用できるアプライアンスとして配布する」 という目的に対して、「FAT32 上の INI ファイル」「ハードウェア構成による動作モード自動決定」「Gentoo エコシステムの不変イメージへの転用」「pybind11 によるプラグイン型 init」といったアイディアが一貫した設計思想のもとに組み合わされている点にあります。技術的に尖っているのではなく、「誰がこのシステムを実際に触るのか」への配慮が一貫していることが本質的な独自性です。