チームの規模が大きくなると、「誰のマシンならビルドが通るか」がそのままボトルネックになりがちです。iOS プロジェクトの CI/CD を Kvmzen の Mac mini M4 クラウドホストに完全移行したところ、ビルド待ち時間は大きく短縮し、署名関連の事故もほぼゼロになりました。本稿では、ゼロからパイプラインを構築する際にぶつかった落とし穴と、最終的に落ち着いた Fastfile とキャッシュ戦略をまとめます。
クラウド Mac mini M4 を CI/CD に選ぶ理由
Xcode のビルドは「計算負荷が高く、OS バージョンに強く依存する」典型的なタスクで、ローカルの Runner を長期間安定運用するのは難しいものです。クラウド Mac ノードを選んだ理由は主に 3 つです。
- 再現性のあるスペック:イメージに Xcode とコマンドラインツールのバージョンを固定し、誰かが手動で OS を更新した結果「その人のマシンだけビルドできる」という事態を防げます。
- 柔軟な拡張:リリース前の回帰テストでは、一時的にノードを複数並行で立てて実行後に解放でき、ピーク用にハードウェアを常時確保する必要がありません。
- 24 時間稼働:M4 チップは待機電力が低く、夜間ビルドや定期セキュリティスキャンを常駐運用しても電気代やノイズを心配せずに済みます。
最初に失敗したのは、「クラウドホスト」を単なる遠隔モニターとして手動パッケージングにしか使わなかったことです。本当の効果が出たのは、CI のトリガーチェーンに組み込んでからでした。
CI/CD パイプライン設計
ステージ分割
リリースパイプライン全体を 4 つのステージに分けています。
- コード取得と依存解決(SPM / CocoaPods)
- 単体テストと静的解析(並列実行)
xcodebuild archiveによるアーカイブと署名- TestFlight へのアップロードと当番チャンネルへの通知
フックとトリガー条件
main ブランチへのマージごとにステージ 1-2 が自動的に走り、release/* タグが付いたときだけステージ 3-4 が実行されます。こうすることで日常の小さな変更で署名クォータを消費しません。Fastlane スクリプトをローカルでデバッグする際は、まず Ctrl+C で一連の実行を中断し、失敗したステップだけを再実行する習慣があり、待ち時間をかなり節約できます。
Fastfile サンプル
lane :ci_archive do
cocoapods
run_tests(scheme: "Kvmzen")
build_app(
scheme: "Kvmzen",
export_method: "app-store",
output_directory: "./build"
)
upload_to_testflight(skip_waiting_for_build_processing: true)
end
このスクリプト自体は複雑ではありませんが、重要なのは同じイメージベースライン上であれば毎回同じ結果になることです。そのためビルドログにイメージのバージョン番号を必ず記録し、失敗が環境由来かコード由来かを後から追跡できるようにしています。
キャッシュと依存関係管理
キャッシュの設定が甘いと、クラウドビルドの速度メリットは依存関係のダウンロード時間にすべて食われてしまいます。3 か月間運用してまとめた比較表は以下の通りです。
| キャッシュ対象 | キャッシュなし | イメージ内キャッシュあり |
|---|---|---|
| CocoaPods インストール | 約 4〜6 分 | 約 30 秒 |
| SPM 依存解決 | 約 3 分 | 約 15 秒 |
| DerivedData 増分ビルド | ほぼフルビルド相当 | ヒット率 80% 以上 |
用語をここで揃えておきます。
- DerivedData
- Xcode の増分ビルド成果物キャッシュ。ビルドをまたいで再利用することで、2 回目以降のコンパイルが大幅に短縮されます。
- SPM キャッシュ
- Swift Package Manager がローカルに保持するパッケージソースと解決結果のキャッシュで、毎回のリモート取得を避けられます。
- イメージベースライン
- 起動直後から使えるクラウドホストのシステムスナップショットで、固定バージョンの Xcode / CLT と予熱済みの依存キャッシュを含みます。
よくあるトラブルの切り分け
意外と見落としがちなのは、証明書の期限切れは即座にエラーにならず、TestFlight へのアップロードという最後のステップで初めて失敗する点です。そこまでにパイプライン全体が十数分空回りしてしまいます。現在はステージ 1 で証明書の有効期限をチェックし、早期に失敗・通知するようにしています。
初期は「毎晩キャッシュを全消去してフルビルドする」という力任せの方法でキャッシュの腐敗を防いでいましたが、後にイメージのバージョン番号でキャッシュを無効化する方式(バージョンが変わらなければ再利用、イメージ更新時のみクリア)に切り替え、速度を保ったまま古いキャッシュが数週間潜伏する事態も防げるようになりました。
「一度の green CI を信じるな。10 回連続の green CI を信じろ」——当番手引きで繰り返し強調している言葉で、特に新しいクラウドノードへ移行した直後の 2 週間は意識するようにしています。
よくある質問
クラウド Mac mini は自前の Mac Runner と比べてセキュリティ面でどう違いますか?
クラウド側はベースとなる OS イメージを統一管理しますが、署名用証明書や Provisioning Profile のアクセス権限管理はチーム側の責任です。証明書は実行時の環境変数として注入し、イメージには焼き込まず、ノードを返却する前にキーチェーンを必ず空にしましょう。
無料の Xcode Cloud のクォータでこの仕組み全体を代替できますか?
小規模チームなら Xcode Cloud で十分です。並列ビルド数、独自スクリプト、プロジェクト間で共有するキャッシュへの要求が増えてきたら、クラウド Mac ノード上に自前で構築したパイプラインの方が柔軟で、コストの上限も管理しやすくなります。
複数プロジェクトで同じクラウドノード群を共有する場合、証明書はどう分離すべきですか?
プロジェクトごとに専用のキーチェーンまたはキーチェーンプロファイルを用意し、ビルド開始時にインポート、終了時に消去する運用を推奨します。これにより異なるプロジェクトの証明書が同じシステムキーチェーンを汚染するのを防げます。
CI/CD を M4 Mac mini に載せると、本当に手間が減る
本稿で紹介した Xcode・Fastlane・CocoaPods・SPM はすべて macOS のネイティブ環境で動作し、仮想マシンや互換レイヤーは不要です。Mac mini M4 の統合メモリアーキテクチャにより、署名・アーカイブ・アップロードのような I/O と計算が混在するタスクが互いを遅らせにくくなり、待機電力約 4W のおかげで 24 時間稼働ノードの電気代もほぼ無視できます。
自前で Mac Runner を維持する場合と比べ、クラウドノードなら冷却設備や OS 更新のタイミング、故障時の機器交換といった運用負担を丸ごと外部化でき、チームはパイプライン自体の品質に集中できます。
「結局誰のマシンならビルドできるのか」に頭を悩ませているなら、今こそ CI をクラウド Mac mini M4 へ移すタイミングです——Kvmzen のプランを見る、数分で最初のビルドノードが立ち上がります。
