「iOS CIビルドタイムアウト」が発生し、Mac Runnerは空いているように見えるのに処理が進まない。
この場合はすぐにMacを増やさず、待機、タスク取得、依存関係、xcodebuild、シミュレーター、署名、アップロードの順に証拠を分けて調べます。健康なノードが継続的に満杯で、並列数の増加に合わせて待機も増え、単一ジョブの処理時間に異常がなければ、初めて増設や弾性レンタルを検討します。
企業IT責任者は、追加のMacが本当にタイムアウトを解消するか判断できます。
プラットフォーム担当者は、Runnerの状態からビルド工程までの証拠線を作れます。リリース責任者は、高負荷時の待機と納期遅延を切り分けられます。
[ SECTION_01 ] iOS CIビルドタイムアウトは総時間では判断できません
最初に記録するのは、パイプライン全体の経過時間だけではありません。ジョブ投入時刻、Runnerがタスクを取得した時刻、依存関係の取得開始と終了、xcodebuildの開始、テストまたはシミュレーターの開始、署名、成果物のアップロードを同じ時系列に並べます。
| 証拠 | 確認する状態 | 疑う故障 |
|---|---|---|
| ジョブ投入から取得まで | 待機が続いたか | ラベル、権限、並列制限、依存ジョブ |
| 取得から処理開始まで | Runnerが実行状態か | Runnerのオフライン、初期化、作業領域 |
| 依存関係の取得 | Git、Git LFS、Swift Package、私有リポジトリ | 認証、プロキシ、キャッシュ未命中 |
| xcodebuildのログ | コンパイル、リンク、テストのどこか | プロジェクト設定、DerivedData、同時実行 |
| 署名とアップロード | KeychainやAppleサービスへの接続 | 証明書、権限、ネットワーク、公開処理 |
GitHub Actionsを使う場合、セルフホストRunnerはラベルやRunner Groupなどの条件でルーティングされます。空きノードが存在しても、ワークフローの指定条件に一致しなければ処理は始まりません。詳細は自前Runnerのルーティング仕様とラベルによる割り当てで確認できます。
Mac Runnerが空いているのに処理が遅い場合
「空き」と表示された時刻と、ジョブが実際にタスクを受け付けた時刻を分けます。Runner Groupの権限、要求ラベル、ワークフロー間の依存、同時実行制御を確認してください。GitHub Actionsの同時実行設定は、同じグループの処理を待機させることがあります。仕様は公式の同時実行ドキュメントにあります。
この段階では、MacのCPU使用率だけを根拠に容量不足と判定してはいけません。タスクがノードに到達していないなら、Macを増やしても待機は解消しません。
注意:待機時間、タスク取得時刻、Runnerの稼働状態、依存ジョブの終了時刻を一つの記録にまとめます。別々の画面を見ていると、ルーティング障害を容量不足と誤認しやすくなります。
[ SECTION_02 ] 依存関係とネットワークが作る「容量不足に見える」遅延
Git、Git LFS、Swift Package、社内アーティファクト、プロキシ、Apple関連サービスへの接続を工程別に記録します。初回取得だけ遅いのか、キャッシュが外れた実行だけ遅いのか、サーバー応答そのものが不安定なのかを分ける必要があります。
キャッシュは再生成できるデータの取得を短縮できます。しかし、資格情報の失効、私有ネットワークへの到達不能、依存バージョンの変動は解決しません。リトライ回数、HTTPエラー、認証エラー、取得サイズをRunnerログに残します。
ここで確認すべき判断は、「キャッシュ方針を直すべきか」「依存サービスへの経路を直すべきか」「Macを増やすべきか」です。依存取得が複数のジョブで同じように停止しているなら、ノード追加より先に依存トポロジーを調べます。
[ SECTION_03 ] Xcodeとxcodebuildの停止点を分けて確認します
第一歩:xcodebuildの開始点を固定する
xcodebuildの開始前に時間を使っているなら、Macのコンパイル性能は原因ではありません。開始後にコンパイル、リンク、テスト、成果物生成のどこでログが止まったかを確認します。コマンドの種類や引数は、AppleのXcodeコマンドラインツールリファレンスに照らして記録します。
第二歩:シミュレーターとストレージを別の証拠にする
シミュレーターの起動待ち、ランタイムの不一致、DerivedDataの作成失敗、ディスク容量不足を同じ「Xcodeが遅い」にまとめません。シミュレーターや実機での実行条件はAppleの実行ガイドで確認できます。
単一ジョブだけが遅い場合は、プロジェクト、依存関係、テスト構成を優先します。複数ジョブが同じノードで互いに遅くなる場合は、作業領域、メモリ圧力、ディスクI/O、同時実行数を調べます。CPUやメモリの瞬間値ではなく、遅延した工程と同じ時刻の記録を使います。
第三歩:署名と公開処理を構築処理から分離する
コンパイルが終わった後にKeychain、証明書、プロビジョニング、成果物のアップロードで止まるなら、一般的なPR用Runnerを増やしても解決しない場合があります。配布用署名の流れはAppleの署名コード作成に関する説明を基準にし、実行ユーザー、Keychainの解錠、証明書の識別子、アクセス権を確認します。
署名情報を扱うノードは、通常のビルドノードと分離するほうが監査しやすくなります。署名待ちをMac容量不足として扱わず、専用ノード、認証経路、公開サービスの状態を別に評価します。
[ SECTION_04 ] iOS CIは遅いのか、Mac容量が不足しているのか
判断には、次の条件分岐を使います。
- 単一ジョブの特定工程だけが長い。依存取得、xcodebuild、シミュレーター、署名のどれかに停止記録がある。
→ まずプロジェクト、依存関係、Xcode設定、署名経路を改善します。 - Runnerがオフライン、要求ラベル不一致、Runner Group権限不足、依存ジョブ待ちになっている。
→ ノード増設ではなく、ルーティングとワークフロー定義を修正します。 - 健康なRunnerが継続的に処理中で、並列実行が増えるほど待機が伸び、各ジョブの工程時間は大きく変わらない。
→ 固定Macの増設、共有ビルドプール、または弾性Macを比較します。 - 遅延がリリース期間や短期試験に集中し、平常時は余剰が大きい。
→ 常設設備を先に増やさず、NOVAKVMのMacレンタルを実際のワークフローで検証します。 - 署名だけが詰まり、一般ビルドは処理できている。
→ 署名専用ノードを検討し、共有Runnerの追加を回避します。
企業のMac打包機に容量不足の証拠があると言えるのは、単なるCPU使用率ではありません。待機が並列数に連動すること、健康なRunnerが継続稼働していること、単一ジョブの工程時間に異常がないこと、この三つを同じログ期間で確認できる場合です。
容量モデルは、ピーク時の同時実行数、平均実行時間、許容待機時間、固定ノード数、予備容量、障害時の復旧要件を変数として扱います。実績のない価格、性能、処理時間を先に埋めてはいけません。Mac miniの購入を検討する場合も、Mac miniの導入条件を確認し、実際のCIログから必要台数を算出します。
[ SECTION_05 ] 第四歩:増設後のエンドツーエンド受け入れ
増設または弾性ノードの導入後は、次の順番で一つの実ジョブを検証します。
- 新ノードが想定ラベルとRunner Groupに登録されることを確認します。
- 実際のワークフローが新ノードへルーティングされることを確認します。
- Git、Swift Package、私有アーティファクト、キャッシュの挙動を既存ノードと比較します。
- xcodebuild、テスト、シミュレーター、成果物生成が完了することを確認します。テスト結果の読み方はAppleのテスト結果説明を基準にします。
- 署名とアップロードを実行し、証明書、Keychain、アクセス権の記録を残します。
- ノード再起動後にRunnerが復帰し、失敗時のログを追跡できることを確認します。
経験則:新しいMacがジョブを受け付けたことだけでは受け入れ完了になりません。依存関係、署名、再起動後の復帰まで同じ証拠線で確認できて、初めて容量対策の効果を評価できます。
固定Macは、安定した継続負荷と物理的な管理要件に向きます。共有ビルドプールは、複数チームの平常負荷をまとめたい場合に向きます。署名専用ノードは資格情報の境界を明確にしたい場合に向きます。弾性Macレンタルは、リリース高峰や短期PoCのように需要が偏る場合に向きます。
既存の自社Macだけで運用すると、購入時の先行費用、遊休時間、保守担当者の作業、故障時の交換待ちが発生します。特に一時的な高負荷のために常設ノードを増やすと、平常時の余剰資源を抱えることになります。反対に、長期の安定負荷、物理ポート、社内設備への直接接続が必要なら、レンタルが最適とは限りません。
そのため、最初から全体を移行するのではなく、実際のiOS CIジョブを一つ選び、待機、ビルド、署名、復帰の記録を取るPoCから始める方法が安全です。短期の検証環境やリリース期間の補助容量であれば、NOVAKVMのMac環境を候補に加える価値があります。専用設備を購入する前に、同じ証拠項目で比較すれば、追加費用が本当に待機時間を減らすのかを判断できます。