Kubernetes は Mac ビルドマシンを公式の通常 Worker Node として直接スケジュールできません。今週は、Kubernetes をキューと制御層に残し、Xcode 用の外部 Mac プールと本番署名ノードを分離する構成を非本番ジョブで検証してください。

この記事は、Kubernetes 基盤をすでに運用し、Apple 向けビルドを統合したいプラットフォーム責任者向けです。複数チームの共有 Mac プール、ピーク時の増設、固定購入とレンタルの組み合わせを判断する担当者にも向いています。

01

Kubernetes と Mac ビルドマシンの境界

Kubernetes の Node は、kubelet などの Node コンポーネントを通じてコンテナワークロードを実行する単位です。公式ドキュメントは Node の管理とコンポーネントを説明しており、Windows についても専用のサポート範囲を示しています。一方、macOS を公式の標準 Worker Node として扱う説明はありません。

Kubernetes の Node コンポーネントと管理モデルを確認すると、Mac に kubectl をインストールできることと、Mac が本番 Worker になれることは別問題だと分かります。操作クライアント、制御面、実行ノードを同じものとして設計してはいけません。

Apple のコマンドラインツールは、Xcode をインストールして選択した macOS 環境で使います。Xcode のコマンドラインツールに関する Apple の説明に沿えば、xcodebuild や simctl を通常の Linux Pod に置き換えることはできません。

ここで分けるべき層は次のとおりです。

  • 制御面:Kubernetes API、キュー、Controller、Operator。
  • 共通処理:Linux Pod で動く静的解析、一般的なスクリプト、バックエンドテスト。
  • CI Runner:Mac 上でジョブを受け取り、Xcode コマンドを実行するプロセス。
  • 実行環境:Xcode、Apple SDK、Simulator、Keychain を持つ実際の Mac。
  • 署名ノード:配布用資格情報を扱う、さらに強く分離された Mac。

注意:Custom Resource や Operator を使って外部 Mac の状態を Kubernetes に登録しても、それは Kubernetes が macOS を Worker Node として公式にスケジュールしている意味ではありません。企業独自の制御層を作っているだけです。

02

第一段階:Kubernetes 内で完了する処理を先に固定する

Apple 固有のツールを使わない処理は、先に Kubernetes 内で終わらせます。たとえば、ソースコードの検査、共通ライブラリのテスト、依存関係の検証、成果物のハッシュ作成、バックエンドのテストなどです。

この分離には三つの利点があります。Mac の待ち行列を減らせること、失敗箇所を Apple 環境に限定できること、Linux 側の再実行を安定させられることです。逆に、Mac でしか成立しない処理まで Pod に押し込むと、失敗原因の切り分けが難しくなります。

入力と出力の契約を決める

Kubernetes のジョブから Mac へ渡す入力は、少なくとも次の情報を含めます。

  • コミット識別子とソースの取得先
  • 依存関係の固定情報
  • ビルド対象と構成
  • 必須の Xcode 環境識別子
  • 署名が必要かどうか
  • 成果物の保存先
  • 再試行してよい失敗かどうか

Mac から Kubernetes へ返す出力は、終了コードだけでは足りません。ログの保存先、成果物の URI、実行した Runner、作業ディレクトリの清掃結果、失敗理由を返します。

この契約を先に定義すると、Linux 側の処理と Mac 側の処理を別々に更新できます。成果物が存在しない場合、署名前後のどちらで失敗したかも追跡できます。

03

第二段階:Xcode ジョブを外部 Mac プールへルーティングする

Kubernetes が担当するのは、ジョブの要求状態と待ち行列です。xcodebuild、simctl、アーカイブ作成は、Xcode を選択した Mac 上で実行します。Apple は Xcode を使った自動化やテストの方法を公式に説明しているため、Mac 側の実行スクリプトはその前提に合わせて固定します。

外部 Mac との接続方式は、次の三つに整理できます。

CI プラットフォームの Runner を使う

既存の CI プラットフォームが Mac Runner を正式に扱えるなら、最初の選択肢になります。ジョブ状態、ログ、成果物、再試行の仕組みを利用しやすいからです。

ただし、Runner が切断されたときの再登録、Xcode の選択状態、作業領域の清掃を自社の受け入れ条件に追加してください。Runner がオンラインでも、実際に署名や Simulator が正常とは限りません。

キュー消費型の Runner を使う

Mac 上の Runner が Kubernetes のジョブキューを監視し、自分のタグや能力に合う要求だけを取得する方式です。Xcode の世代、Simulator の有無、署名可否などを属性として登録できます。

この方式は、固定 Mac プールを段階的に増やしたい企業に向きます。欠点は、キューの可視性と重複取得の防止を自分で設計する必要があることです。

Custom Resource と Controller を使う

Kubernetes の Custom Resource の仕組みを使い、MacBuildRequest のような要求を API オブジェクトとして管理できます。Controller は要求を監視し、対応する Mac Runner へ割り当て、完了状態を更新します。

Operator の設計モデルを採用する場合でも、Mac を Node として偽装するのではなく、外部資源を管理する Controller として扱います。状態遷移、タイムアウト、重複実行、Runner の再登録を実装できるチーム向けの方法です。

ジョブの流れは次のように分けます。

制御流:Kubernetes API → Queue → Runner割り当て → 完了状態
タスク流:コミット → Mac Runner → xcodebuild / simctl → 終了コード
成果物流:成果物 → 保管先 → Kubernetes上の成果物参照
資格情報流:承認要求 → 署名ノード → Keychain / 配布資格情報

SSH でスクリプトを起動するだけの方式は、短い検証には使えても、本番の状態管理には弱い構成です。接続断、端末再起動、途中で停止した xcodebuild、未回収の成果物を Kubernetes が認識できないためです。

04

第三段階:本番署名ノードを通常の Mac プールから分離する

ビルドを共有できることと、署名を共有してよいことは同じではありません。Developer ID、証明書、秘密鍵、Keychain、配布用 API 資格情報は、通常のビルド環境より狭い範囲に置くべきです。Apple の配布用署名コードに関する資料も、署名情報を扱う工程を独立した管理対象として考える材料になります。

推奨する流れは次の分離です。

  1. Kubernetes でコード検査と依存関係の検証を完了する。
  2. 通常の Mac プールで Xcode ビルドとテストを実行する。
  3. 承認済みの成果物だけを署名ノードへ渡す。
  4. 署名ノードで資格情報を参照して署名する。
  5. 署名済み成果物、監査情報、清掃結果を返す。
  6. 失敗時は配布処理を止め、資格情報の無効化や再発行の手順へ移る。

署名ノードには、一般開発者の対話的なログインを許可しない設計が適しています。ジョブごとの承認、成果物のハッシュ、実行主体、使用した資格情報の参照を記録してください。

経験上、署名ノードを「高性能な共有ビルド機」として扱うと、権限設計と事故対応が複雑になります。性能よりも、入力制限、承認経路、作業領域の消去、監査記録を先に受け入れ条件へ入れてください。

05

第四段階:ピーク容量と故障回復を別シナリオで検証する

固定 Mac プールは、継続的な基礎負荷に向いています。短期のリモート Mac は、リリース前の回帰テスト、複数プロジェクトのピーク、移行期間、固定ノードの故障時に有効です。

容量は開発者数から逆算しません。次の観測値を使います。

  • 同時に待つ Xcode ジョブ数
  • Mac 1 台が処理できる有効なジョブ量
  • Xcode 環境を渡すまでの時間
  • 失敗したジョブの再実行時間
  • ノード障害時に必要な予備容量
  • 許容できる待ち時間

たとえば、待ち行列が増えているのに Mac が空いているなら、Runner 登録やタグの条件が誤っています。逆に、Mac が常に埋まっているなら、ノード追加だけでなく、Linux 側へ移せる前処理が残っていないか確認します。

短期の Mac を本番キューへ入れる前に、次の順で確認します。

  1. ベースイメージまたは構成基準を固定する。
  2. Xcode と必要な Simulator の状態を確認する。
  3. CI Runner を登録する。
  4. 実際の非本番 Xcode ビルドを通す。
  5. ログ、終了コード、成果物の回収を確認する。
  6. Mac の再起動後に Runner が復帰するか確認する。
  7. 作業領域、キャッシュ、資格情報が回収されることを確認する。
  8. 失敗したジョブを再実行し、二重成果物が生じないことを確認する。

環境を作る時間、ジョブの処理時間、回収にかかる時間を分けて記録してください。これらを混ぜると、固定購入が必要なのか、ピーク時だけ外部 Mac を借りればよいのか判断できません。

06

条件分岐で構成を決める

次の条件で、最初の構成を選びます。

  • Apple 固有のビルドがない場合は、Kubernetes 単独にします。Mac を先に購入しないでください。
  • Xcode ジョブが安定して発生し、待ち時間も予測できる場合は、Kubernetes と固定 Mac プールを組み合わせます。
  • リリース時だけ待ち行列が急増する場合は、固定プールを基礎にして、ピーク分をリモート Mac で補います。
  • 署名資格情報を扱う場合は、通常の Mac プールとは別の信頼済み署名ノードを用意します。
  • Runner の状態を Kubernetes に返せない場合は、本番投入を止め、先に Controller またはキュー消費方式を整えます。
  • 再起動後の復帰と作業領域の清掃を確認できない場合は、台数を増やさず、環境回収を改善します。
07

受け入れ表で固定購入とレンタルを比較する

最後に、構成を次の表で判定します。価格や台数を先に決めるのではなく、証拠を取得できた項目だけを本番資源の根拠にしてください。

構成 向いているシナリオ 必須の確認項目 主な弱点
Kubernetes 単独 Apple 固有の処理がない Linux 側の検査、成果物生成、失敗再試行 Xcode と Simulator を実行できない
Kubernetes + 固定 Mac プール Xcode 負荷が安定している Runner 状態、Xcode 環境、再起動復帰、清掃 低負荷時も固定資源を保持する
Kubernetes + 固定 Mac + リモート Mac リリースや回帰でピークがある 環境交付、登録、実ビルド、状態回収、回収清掃 接続方式と容量判断が複雑になる
Kubernetes + 通常ビルド池 + 署名ノード 配布資格情報を扱う 承認、資格情報流向、監査、失敗時の無効化 署名工程の待ち行列と運用分離が必要

Mac の固定購入を検討する場合は、Mac の注文と構成を確認する案内と、社内の保守、故障交換、設置場所、アクセス制御を合わせて評価してください。短期の検証では、VpsMesh の Mac レンタル案内を使い、まず非本番の Xcode ワークフローを外部 Mac へ移して、ジョブの実測記録を作る方法があります。

受け入れ時に残す証拠

  • Linux 処理と Mac 処理の境界
  • ジョブの要求、割り当て、実行、完了の状態遷移
  • Xcode と Simulator の選択状態
  • ログと成果物の保管先
  • Runner の再起動後の復帰結果
  • 署名資格情報の流向と承認記録
  • 作業領域と一時資格情報の回収結果
  • 故障時の再試行と重複成果物の扱い
  • ピーク時の待ち行列と予備容量の根拠

Kubernetes と Mac Runner の組み合わせは、Mac を無理に Worker Node 化する問題ではありません。Kubernetes を制御層、Mac を専門実行環境、署名ノードを信頼境界として設計し、各層の状態を明示的に連携させる問題です。

短期のリモート Mac を使った検証は、固定購入より先に環境交付、Xcode 実行、状態回収、再起動復帰、ノード清掃を確認できます。固定 Mac は安定負荷に、レンタルはピークや移行試験に割り当てると、単一方式よりも調達と運用の失敗を抑えやすくなります。評価用の構成が必要なら、まず一つの非本番ワークフローだけを VpsMesh の Mac 環境へ移し、受け入れ表の証拠がそろってから本番容量を決めてください。