クラウド Mac mini マルチノードビルド編成実践

CI/CD ·約 8 分

クラウド Mac mini マルチノードビルド編成実践

リリース前夜、プロジェクト内のメインApp、今日ウィジェット、Apple Watch連携Appという3つのターゲットを一斉にフルビルドすると、1台のマシンでは38分かかっていた。チームには自前のCIクラスタを年中維持する予算はないが、リリース日にはその待ち時間は許容できない。そこで折衷案として、リリース当日だけ云端(クラウド)Mac mini を3台一時的にレンタルし、「一日限りのビルドファーム」を組んでSSHマトリクスでタスクを分配、ビルド完了後に署名とアーティファクトの集約を一括で行う運用に落ち着いた。全工程15分未満で、アップロード可能な3つのパッケージが手に入る。本稿ではこの編成の具体的な手順を記録する。

マルチノード化が必要になるタイミング

すべてのプロジェクトがこれほどの手間をかける必要はない。判断基準はシンプルだ——1回のフルビルドが20分を超える、あるいは1回のリリースで複数ターゲット・複数アーキテクチャのパッケージを同時に作る必要がある場合にのみ、一時的にノードを増設する価値がある。日常のコーディングや単体テストだけであれば、Mini Standard(24GBメモリ)1台で十分であり、常時3台稼働させるのはむしろ無駄なコストになる。

マルチノードファームの核心は「日単位で借り、必要なくなれば即解散する」という考え方だ。リリースウィンドウの前夜に注文し、リリース完了後は即座に解放する。コストが発生するのは、実際に並列演算力が必要となるその日だけである。

ファームのトポロジーとノードの役割分担

役割分担は各ノードのネットワーク経路とリソース条件に基づいて決めている。役割を割り振る前にコンソールで各ノードで現在選択できるプランを確認し、負荷の高いビルド役はネットワーク経路とリソースの両方が適したノードに割り当てる。

ノードの役割 プラン チップ/メモリ ロケーション 日額 担当内容
メインビルドノード Mini Pro M4 Pro / 64GB アメリカ西部 $59.3/日 メインAppターゲット、署名の集約も兼任
ビルドノードA Mini Standard M4 / 24GB 東京 $40.1/日 今日ウィジェットターゲット
ビルドノードB Mini Standard M4 / 24GB ソウル $40.1/日 Watch Appターゲット

3台合計で$139.5/日。比較として、全台をMini Proに揃えると$177.9/日になる——ウィジェットとWatch Appのビルド負荷自体は大きくないため、Standardクラスで十分であり、その分の予算をメモリを多く消費するメインAppのビルドに回すべきだ。

教訓:当初、我々は3台すべてを東京に配置していた。メインビルドノードと署名ノードを1台に統合した結果、rsyncによる内部ネットワーク転送は速かったものの、その後のApp Store Connectへのアップロードを担うのはアメリカ西部のノードであり、実際にはアップロード出口に近いことのほうが重要だった——署名ノードのロケーションは、開発者に近い場所より、アップロード出口に近い地域を選ぶべきである。

分配スクリプトと実行

コーディネーター役は通常メインビルドノード自身が担う。シンプルなBashスクリプトで各ターゲットを従属ノードに分配し、バックグラウンドで並列実行させ、最後に一括で待機する:

#!/bin/bash
set -e

NODES=("node-a.internal" "node-b.internal")
TARGETS=("WidgetExtension" "WatchApp")

for i in "${!NODES[@]}"; do
  ssh "build@${NODES[$i]}" \
    "cd ~/repo && xcodebuild -scheme ${TARGETS[$i]} \
     -configuration Release -archivePath build/${TARGETS[$i]}.xcarchive \
     archive CODE_SIGNING_ALLOWED=NO" &
done

xcodebuild -scheme MainApp -configuration Release \
  -archivePath build/MainApp.xcarchive archive

wait
echo "all targets archived"

ポイントは、従属ノード側で CODE_SIGNING_ALLOWED=NO を付けて実行することだ。これにより未署名の .xcarchive のみが生成され、証明書をそれら2台のマシンに同期する必要が一切なくなる。メインビルドノード自身は証明書を保持し、MainAppの署名付きビルドを担当しながら、他ノードからのアーティファクトを待機する。

アーティファクトの集約と一括署名

従属ノードでのビルドが完了したら、rsyncで .xcarchive をメインノードに送り返す:

rsync -avz build@node-a.internal:~/repo/build/WidgetExtension.xcarchive ./build/
rsync -avz build@node-b.internal:~/repo/build/WatchApp.xcarchive ./build/

3つのアーカイブが揃ったら、メインノード上で同一のプロビジョニングプロファイルと証明書を使い xcodebuild -exportArchive を一括実行し、続いてfastlaneの pilot upload で3つのパッケージを一度にTestFlightへアップロードする。署名工程はすべて1台のマシン上でのみ発生し、秘密鍵は従属ノードには一切配置されない。この点はセキュリティ基準の確認時に繰り返しチェックされる項目だ。

注文前に一度チェックリストを確認しておくとよい:

よくある落とし穴と限界

マルチノード編成が割に合わない場面もある。プロジェクトにターゲットが1つしかない場合や、フルビルド自体が10分以内で終わる場合は、複数ノードに分割するとSSHのスケジューリングやrsync転送のオーバーヘッドで待ち時間がむしろ増える。そうした場合は1台のノードで素直にビルドしたほうがよい。また、ソウルには現時点でPro/Maxクラスが存在しない点にも注意が必要だ。3つのターゲットのうち1つが特にメモリを多く消費する場合(たとえば機械学習モデルの推論を含むターゲットなど)は、事前に東京またはアメリカ西部のPro/Maxノードに割り当てるべきであり、無理にソウルのStandardノードに詰め込んではならない。

よくある質問

マルチノードビルドファームはどの規模のプロジェクトに向いていますか?

フルビルドが20分を超える、または本体アプリ・ウィジェット・ウォッチアプリなど複数ターゲットと複数アーキテクチャを同時に出す必要がある場合に有効です。個人の日常開発なら1台の Standard ノードで十分です。

複数ノードでビルドする場合、署名証明書の一貫性と漏洩防止はどう担保しますか?

証明書とプロビジョニングプロファイルは米国西部の署名専用ノード1台にのみ保持し、他のノードは未署名の .app/.xcarchive を出力するだけにします。rsync で署名ノードへ集約し、一括で署名・アップロードすることで秘密鍵を複数台に置きません。

負荷の高いコンパイル役はどのノードに割り当てるべきですか?

コンソールで各ノードで現在選択できるプランを確認したうえで、チームのネットワーク経路と成果物のアップロード先を考慮して選びます。負荷の高いビルド役はリソースに余裕がありレイテンシの低いノードに、署名とアップロード役は出口帯域の大きいノードに置くのがおすすめです。

ビルド専用に独享Mac miniが必要ですか?

東京・ソウル・シリコンバレーの5拠点に物理ノードを配置。1日単位でレンタル可能、申込から10分でVNC/SSH接続情報をお届けします。

今すぐMac miniをレンタル