photoncloud-monorepo/docs/nixos-deployment-challenges.md

22 KiB
Raw Blame History

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 ISOphone-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.clusternix/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で埋める設計。

OpenStackIronic等のベアメタルとの比較

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.nixnixConfig と、nix/images/netboot-base.nix / 各ノード設定に substituters/trusted-public-keys を入れて、netboot/ISO/インストール時のnixが自動でキャッシュを引くようにする

効果: nixos-anywhere の実体が「ビルド」から「ダウンロード」に変わる。

優先度: Phase 3以降完全自動デプロイ環境の実装時。Deployer[Bootstrapper]ではローカルで動くことを優先し、キャッシュ系は後回し。

P0: src = ./. をやめ、ソースをフィルタする 実装済み

目的: 無関係な変更で再ビルドが発生しないようにする

実装内容 (flake.nixrepoSrc):

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.nixrepoSrc で実装済み
    • ソース変更がなければ、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でコアサービスの安定化を進める。


参考資料