# NixOSデプロイメントの課題と改善案 ## 概要 このドキュメントは、PhotonCloudプロジェクトにおけるNixOSベースのベアメタルデプロイメントに関する現状分析、課題、および改善案をまとめたものです。 ## 目次 1. [現状の実装状況](#現状の実装状況) 2. [課題の分析](#課題の分析) 3. [他のシステムとの比較](#他のシステムとの比較) 4. [スケーリングの課題](#スケーリングの課題) 5. [改善案](#改善案) 6. [優先度とロードマップ](#優先度とロードマップ) --- ## 現状の実装状況 ### 実装済みの機能 #### A. Netboot → nixos-anywhere でのインストール経路 - **netbootイメージ**: `nix/images/*` と `baremetal/image-builder/build-images.sh` で生成可能 - **PXEサーバー**: `chainfire/baremetal/pxe-server/assets` へのコピーまで想定済み - **VMクラスタ検証**: `baremetal/vm-cluster/` にスクリプトが揃っている - **デプロイフロー**: PXE起動 → SSH接続 → disko + nixos-install(=nixos-anywhere)の流れが確立 **評価**: deploy-rs/colmena系よりベアメタル寄りの王道路線として成立している。 **ただし**: 速度は**バイナリキャッシュの有無**と**再ビルドの頻度**に大きく依存する。 #### B. Bootstrap ISO(phone-home → 自動パーティション → nixos-install)経路 - **ISO生成**: `nix/iso/plasmacloud-iso.nix` に実装済み - **自動化フロー**: - Deployerへの `POST /api/v1/phone-home` - `disko` 実行 - `nixos-install --flake ...` - **Deployer API**: `deployer/` にHTTP API実装あり(`/api/v1/phone-home`) **評価**: 形は整っているが、**本番でのゼロタッチ運用**には未成熟。 #### C. 構成管理(NixOSモジュール + クラスタ設定生成) - **サービスモジュール**: `nix/modules/` に各サービスがモジュール化済み - **cluster-config.json生成**: `plasmacloud.cluster`(`nix/modules/plasmacloud-cluster.nix`)で `/etc/nixos/secrets/cluster-config.json` を生成 ### 実装済み機能 ✅ #### (1) トポロジ→cluster-config→first-bootの一貫したルート - ✅ `plasmacloud-cluster.nix` でクラスタトポロジから `cluster-config.json` を自動生成 - ✅ `environment.etc."nixos/secrets/cluster-config.json"` でファイルが自動配置される - ✅ `first-boot-automation.nix` がcluster-config.jsonを読み込んでサービス間の接続を自動化 #### (2) Deployerの実運用要件 - ✅ SSH host key 生成: `LocalStorage.get_or_generate_ssh_host_key()` で ED25519 鍵を生成・永続化 - ✅ TLS証明書配布: `LocalStorage.get_or_generate_tls_cert()` で自己署名証明書を生成・永続化 - ✅ machine-id → node割当: pre_register API + in-memory fallback 実装済み - ✅ ChainFire非依存: `local_state_path` がデフォルトで設定され、LocalStorage を優先使用 #### (3) netbootイメージの最適化 - ✅ `netboot-base.nix`: 超軽量インストーラ専用イメージ(サービスバイナリなし) - ✅ `netboot-worker.nix`: netboot-base.nix をベースに使用 - ✅ `netboot-control-plane.nix`: netboot-base.nix をベースに使用 - ✅ サービスバイナリは nixos-anywhere でインストール時に追加(netboot には含めない) ### 残りの改善点 #### ISOの最適化(Phase 2以降) - ISOは `isoImage.contents = [ { source = ../../.; ... } ]` で **リポジトリ丸ごとISOに埋め込み**になっており、変更のたびに再パック&評価対象が増えやすい - 将来的には必要なファイルのみを含めるように最適化する --- ## 課題の分析 ### 「途方もない時間がかかる」問題の根本原因 #### 最大のボトルネック: Rustパッケージの `src = ./.` が重すぎる `flake.nix` のRustビルドは `src = repoSrc = ./.;` になっており、これにより: - `docs/` や `baremetal/` など **ビルドに無関係な変更でも全Rustパッケージが再ビルド**され得る - さらに最悪なのは、`deployer/target/` のような **巨大で変動する成果物ディレクトリが混入している場合、毎回ソースハッシュが変わってキャッシュが死ぬ**こと - 結果:毎回「初回ビルド」に近い時間が発生 **ここが直るだけで「体感の遅さ」が一段落ちる可能性が高い。** #### その他のボトルネック 1. **netbootイメージが肥大化** - サービスバイナリや重いツールをnetbootに含めている - initrd配布もビルドも遅くなる 2. **ISOにリポジトリ全体を埋め込み** - 変更のたびにISO再ビルドが必要 - 評価対象が増える **注意**: - **リモートバイナリキャッシュ(Cachix/Attic)は後回し**(Phase 3で実装) - Deployer[Bootstrapper]では**ローカルNixストアのキャッシュ**を活用する前提 --- ## 他のシステムとの比較 ### cloud-init との比較 **cloud-initの得意領域**: 既に焼いたOSイメージ(主にクラウドVM)に対して、初回起動時にユーザデータ/メタデータで「最後のひと押し」をする **このプロジェクトの得意領域**: そもそもOSとサービス構成をNixで宣言し、**同一の入力から同一のシステム**を作る(= cloud-initより上流) **評価**: - **置き換え関係というより補完**。cloud-initは「既存OSに後付けで整える」方向、NixOSは「最初からそれがOSの本体」。 - 速度面は、**バイナリキャッシュがあるなら** NixOSでも十分実用レンジに寄るが、**キャッシュ無しだとcloud-init(既成イメージ前提)の圧勝**になりがち。 ### Ansible との比較 **Ansibleの強み**: 既存の多様なOSに対して、成熟したエコシステムで「変更差分を適用」しやすい **NixOSの強み**: 変更適用が「宣言→生成→スイッチ」で、**ドリフト/雪片化を構造的に起こしにくい** **評価**: - **同じ「構成管理」領域ではかなり戦える**。特にクラスタ基盤(あなたのプロジェクトのコア)みたいに「全ノード同質で、更新頻度も高く、止められない」世界はNixが刺さりやすい。 - ただし現状だと、Ansibleが当たり前に持っている **実運用の周辺機能**(インベントリ、秘密情報配布の標準手、実行ログ/監査、段階ロールアウト、失敗時の自動復旧/再試行設計)が、Nix側では自作領域になりがち。ここをDeployerで埋める設計。 ### OpenStack(Ironic等のベアメタル)との比較 **Ironicの強み(Day0の王者)**: - IPMI/Redfish等のBMCで電源制御 - PXE/iPXE、インスペクション(ハードウェア自動検出) - クリーニング(ディスク消去)、RAID/BIOS設定 - 大規模・マルチテナント前提の運用(権限、クオータ、ネットワーク統合) **このプロジェクトの現状**: - PXE/Netboot・ISO・disko・nixos-install・first-boot は揃っている - でも **BMC連携/インスペクション/クリーニング/多数ノードの状態機械**は薄い(Deployerがその芽) **評価**: - **Ironicの「同じ土俵」ではまだ厳しい**(特に「台数が増えた時に壊れない運用」)。 - 逆に言うと、Ironicが重い/過剰な環境(単一DC・少〜中規模・同一HW寄り・「クラウド基盤自体をNixOSでガチガチに固めたい」)では、**NixOS方式は運用コストと一貫性で勝ち筋がある**。 **実務的な勝ち筋**: - **小〜中規模はNixOS主導で十分戦える**(ただしキャッシュ導入と、ビルド入力の安定化が必須)。 - **大規模/多拠点/多機種/マルチテナントのDay0は、Ironic相当の機能をどこかで用意する必要がある**。 - 現実解は「**Day0はIronicや既存のプロビジョナに寄せて、Day1/Day2をNixOSで統一**」が強い。 --- ## スケーリングの課題 ### 10,000台規模での問題点 #### 1. Deployerサーバーが単一インスタンス前提 - `axum::serve(listener, app)` で単一HTTPサーバーとして動作 - 10,000台が同時にPhone Homeすると、**単一プロセスが全リクエストを処理**する必要がある - CPU/メモリ/ネットワークI/Oがボトルネック #### 2. 状態管理はChainFireで分散可能だが、Deployer側の調整がない - ChainFireはRaftベースで分散可能 - しかし、**Deployerインスタンス間の調整**(リーダー選出、ジョブ分散、ロック)がない - 複数Deployerを起動しても、**同じジョブを重複実行**する可能性 #### 3. デプロイジョブの管理がない - Phone Homeはあるが、**「nixos-anywhereを実行する」ジョブの管理**がない - 10,000台を順次デプロイする場合、**キューイング/並列制御/リトライ**が必要 ### 他のシステムとの比較(スケーリング設計) #### OpenStack Ironic ``` API層: 複数インスタンス + ロードバランサー ワーカー層: 複数conductorで並列処理 状態管理: PostgreSQL(共有DB) ジョブキュー: RabbitMQ(分散キュー) ``` #### Ansible Tower ``` Web層: 複数インスタンス ワーカー層: Celery workers(スケーラブル) 状態管理: PostgreSQL ジョブキュー: Redis ``` #### Kubernetes Controller ``` コントローラー層: 複数インスタンス + Leader Election 状態管理: etcd 並列処理: ワーカーPodで分散 ``` ### 10,000台規模での性能見積もり **現状(単一インスタンス)**: - Phone Home: **10,000リクエスト ÷ 1サーバー = 10,000リクエスト/サーバー** - デプロイ: **順次実行 = 10,000台 ÷ 1ワーカー = 非常に遅い** **改善後(API層10台 + ワーカー100台)**: - Phone Home: **10,000リクエスト ÷ 10サーバー = 1,000リクエスト/サーバー**(10倍高速化) - デプロイ: **10,000台 ÷ 100ワーカー = 100台/ワーカー**(並列実行で大幅短縮) **例**: 1台あたり10分かかる場合 - 現状: **10,000台 × 10分 = 100,000分(約69日)** - 改善後: **100台/ワーカー × 10分 = 1,000分(約17時間)** --- ## 改善案 ### Deployer[Bootstrapper]の位置づけ 現状のDeployer実装は **Deployer[Bootstrapper]** として位置づけ、以下の前提で設計する: - **実行環境**: 仮設マシンや手元のマシン(deploy-rsのように) - **役割**: 0→1の初期デプロイ(クラスタの最初の数台) - **独立性**: 他のソフトウェア(ChainFire、FlareDB等)から**完全に独立**している必要がある - **キャッシュ前提**: 手元/仮設マシンにはNixストアのキャッシュがあるため、リビルドは多くないはず **将来の移行**: ある程度デプロイが進んだら、完全に自動なデプロイ環境(キャッシュ実装済み、ISOはオブジェクトストレージ、スケーラブル)に移行する。ただし、この完全自動デプロイ環境の実装は**他のソフトウェアが安定してから**にしたい。 ### (将来)リモートflake化 + バイナリキャッシュ(Phase 3以降) **目的**: ビルド時間を大幅に短縮(完全自動デプロイ環境用) **実装内容**(Phase 3で実装): 1. **リモートにflakeを置く**(GitHub等) - **注意**: 現在のコードベースは大胆に変更される可能性があるため、GitHubへの公開は後回し 2. **バイナリキャッシュを用意**(Cachix、セルフホストならattic等) 3. `flake.nix` の `nixConfig` と、`nix/images/netboot-base.nix` / 各ノード設定に **substituters/trusted-public-keys** を入れて、netboot/ISO/インストール時のnixが自動でキャッシュを引くようにする **効果**: nixos-anywhere の実体が「ビルド」から「ダウンロード」に変わる。 **優先度**: **Phase 3以降**(完全自動デプロイ環境の実装時)。Deployer[Bootstrapper]では**ローカルで動くことを優先**し、キャッシュ系は後回し。 ### P0: `src = ./.` をやめ、ソースをフィルタする ✅ 実装済み **目的**: 無関係な変更で再ビルドが発生しないようにする **実装内容** (`flake.nix` の `repoSrc`): ```nix repoSrc = pkgs.lib.cleanSourceWith { src = ./.; filter = path: type: ! (dropPrefix [ "docs/" "baremetal/" ".git/" ".cccc/" "result" "result-" ] || base == "target" || dropSuffix [ ".qcow2" ".img" ".iso" ".qcow" ]); }; ``` **除外されるファイル/ディレクトリ**: - ✅ `**/target/`(Cargoビルド成果物) - ✅ `docs/`, `baremetal/`(Rustビルドに不要) - ✅ `.git/`, `.cccc/`, `result*`(Nix成果物) - ✅ `.qcow2`, `.img`, `.iso`, `.qcow`(大きなバイナリファイル) **効果**: ソース変更がなければNixのキャッシュが効き、再ビルドを回避。 ### P1: netbootは「最小のインストーラ」に寄せる ✅ 実装済み **目的**: netbootイメージのサイズとビルド時間を削減 **実装内容** (`nix/images/netboot-base.nix`): - ✅ `netboot-base.nix`: 最小限のインストーラツールのみ(disko, parted, curl, jq等) - ✅ サービスバイナリや仮想化ツールは含めない - 役割:netbootは「SSHで入れてnixos-anywhereできる」だけに絞る - サービスは **インストール後のNixOS構成**で入れる方が速く・安全 **効果**: initrd配布もビルドも速くなる。 ### P1: トポロジ生成とfirst-bootの接続を完成させる ✅ 実装済み **目的**: 構成管理の運用ループを完成させる **実装内容**: - ✅ `plasmacloud-cluster.nix`: クラスタトポロジ定義と `cluster-config.json` の自動生成 - ✅ `first-boot-automation.nix`: cluster-config.json を読み込んでChainfire/FlareDB/IAMへの自動接続 - ✅ `environment.etc."nixos/secrets/cluster-config.json"` でファイル配置 **効果**: 「構成管理」が「運用の自動化」に直結する。 ### P2: ISOルートは「本番のゼロタッチ」に必要な要件を埋める(Phase 2以降) **目的**: ISOベースの自動デプロイを本番対応にする **実装内容**: - ✅ Deployerの鍵・証明書生成は実装済み(`LocalStorage.get_or_generate_*`) - TODO: ISO内で disko を同梱してローカル実行に寄せる(現状はネットワーク依存) ### P1: Deployer[Bootstrapper]の独立性確保 ✅ 実装済み **目的**: 他のソフトウェア(ChainFire、FlareDB等)に依存しない独立したデプロイツールにする **実装内容** (`deployer/crates/deployer-server/`): - ✅ `LocalStorage`: ローカルファイルベースのストレージ(ChainFire不要) - ✅ `config.local_state_path`: デフォルトで `/var/lib/deployer/state` に設定 - ✅ `state.init_storage()`: `local_state_path` があれば LocalStorage を優先使用 - ✅ Phone Home API: 簡易HTTPサーバーとして動作(ChainFire不要) - ✅ SSH host key / TLS証明書: LocalStorage で永続化 **効果**: ChainFire等が動いていなくても、Deployer[Bootstrapper]だけでデプロイが可能。 **将来**: Phase 3 で ChainFire との統合を実装(大規模デプロイ用)。 ### (将来)完全自動デプロイ環境の設計 **目的**: 大規模デプロイ(10,000台規模)に対応した、完全に自動化されたデプロイ環境 **実装内容**(Phase 3で実装): - **API層のStateless化**: Phone Homeリクエストを複数APIサーバーで分散処理 - **ワーカー層の追加**: デプロイジョブを並列実行(ChainFireベースのジョブキュー) - **ISOのオブジェクトストレージ配布**: LightningStor等にISOを保存し、高速配布 - **バイナリキャッシュの完全実装**: すべてのビルド成果物をキャッシュ **効果**: マシンをいくら増やしても高速でデプロイできる。 **前提条件**: 他のソフトウェア(ChainFire、FlareDB、LightningStor等)が安定してから実装する。 --- ## 優先度とロードマップ ### Phase 1: Deployer[Bootstrapper]の改善 ✅ 完了 **目標**: 0→1の初期デプロイを高速化・安定化(**ローカルで動くことを優先**) 1. ✅ **`src` フィルタリング**(`target/` や `docs/` を除外) - `flake.nix` の `repoSrc` で実装済み - ソース変更がなければ、Nixのキャッシュが効き、Cargoの再ビルドも避けられる 2. ✅ **Deployer[Bootstrapper]の独立性確保** - `LocalStorage` でChainFire非依存 - `local_state_path` がデフォルトで設定 3. ✅ **netbootイメージの最小化**(サービスバイナリを除外) - `netboot-base.nix` を最適化 - `netboot-worker.nix`, `netboot-control-plane.nix` が netboot-base をベースに使用 4. ✅ **トポロジ→first-boot接続** - `plasmacloud-cluster.nix` でクラスタトポロジ定義と cluster-config.json を自動生成 - `first-boot-automation.nix` でサービス間の自動接続 5. ✅ **SSH/TLS鍵生成** - `phone_home.rs` で ED25519 鍵と自己署名証明書を生成・永続化 **達成効果**: - Deployer[Bootstrapper]が他のソフトウェアから独立し、安定して動作 - ソース変更がなければ、ビルド時間が大幅に短縮 - Cachix/Attic連携なしでもローカルで動作 **実行環境**: 手元/仮設マシン(Nixストアのキャッシュがある前提) ### Phase 2: 他のソフトウェアの安定化(数ヶ月) **目標**: ChainFire、FlareDB、IAM等のコアサービスの安定化 1. **コアサービスの機能完成** 2. **クラスタ運用の安定化** 3. **監視・ログ・バックアップ等の運用基盤の整備** **期待効果**: 完全自動デプロイ環境を構築する基盤が整う ### Phase 3: 完全自動デプロイ環境の実装(将来、Phase 2完了後) **目標**: 大規模デプロイ(10,000台規模)に対応した、完全に自動化されたデプロイ環境 1. **リモートflake化** + **バイナリキャッシュ導入**(Cachix/attic) - GitHub等への公開(コードベースが安定してから) - Cachix/Attic連携によるバイナリキャッシュ 2. **API層のStateless化** + **ワーカー層の追加** 3. **ジョブキューの実装**(ChainFireベース) 4. **ISOのオブジェクトストレージ配布**(LightningStor等) 5. **Deployerの鍵・証明書・インベントリ管理の実装** **期待効果**: - マシンをいくら増やしても高速でデプロイできる - 完全に自動化されたゼロタッチデプロイが可能 **前提条件**: - Phase 2(他のソフトウェアの安定化)が完了していること - コードベースが安定し、GitHub等への公開が可能になったこと --- ## まとめ ### 現状の評価 このプロジェクトは、**NixOSベースのベアメタル配備に必要な部品がすべて揃い、Phase 1が完了**している: #### ✅ Phase 1 完了項目 1. **Deployer[Bootstrapper]の独立性**: LocalStorage でChainFire非依存 2. **キャッシュ効率化**: `repoSrc` フィルタリングで不要ファイルを除外 3. **netboot最小化**: `netboot-base.nix` でインストーラ専用イメージ 4. **トポロジ→first-boot接続**: cluster-config.json 自動生成 5. **SSH/TLS鍵生成**: ED25519 鍵と自己署名証明書の生成・永続化 #### 残りの課題 1. **完全自動デプロイ環境の未実装**: 大規模デプロイに対応するための基盤(Phase 3で実装) ### 段階的なアプローチ **Phase 1 ✅ 完了**: Deployer[Bootstrapper]の改善 - 0→1の初期デプロイを高速化・安定化 - 他のソフトウェアから独立 - 手元/仮設マシンで実行可能 **Phase 2(現在)**: 他のソフトウェアの安定化 - ChainFire、FlareDB、IAM等のコアサービスの安定化 - クラスタ運用の確立 **Phase 3(将来)**: 完全自動デプロイ環境の実装 - 大規模デプロイ(10,000台規模)に対応 - 完全に自動化されたゼロタッチデプロイ - Phase 2完了後に実装 ### 達成済みの成功条件 1. ✅ **Deployer[Bootstrapper]の独立性**: 他のソフトウェアが動いていなくても、デプロイが可能 2. ✅ **ローカルでの動作優先**: Cachix/Attic連携なしでも、ローカルNixストアのキャッシュで動作 3. ✅ **キャッシュの効率化**: `src` フィルタリングで、ソース変更がなければNixのキャッシュが効く 4. ✅ **トポロジ→first-boot接続**: plasmacloud-cluster.nix からの設定生成が機能 5. ✅ **SSH/TLS鍵の永続化**: LocalStorage で鍵を永続化 ### 次のステップ 1. ~~Phase 1を最優先で実装~~ ✅ **完了** 2. **Phase 2で他のソフトウェアを安定化**(基盤の確立) 3. **Phase 3で完全自動デプロイ環境を実装**(大規模対応) - コードベースが安定してから、リモートflake化とバイナリキャッシュを実装 **Phase 1が完了し、0→1のデプロイが可能になった。次はPhase 2でコアサービスの安定化を進める。** --- ## 参考資料 - [NixOS Netboot](https://nixos.wiki/wiki/Netboot) - [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) - [disko](https://github.com/nix-community/disko) - [Cachix](https://www.cachix.org/) - [attic](https://github.com/zhaofengli/attic)