ビルドが失敗するたびに、Xcodeの差異、署名情報、Runnerの再接続を個別に確認している。

最短解は、GitLab Runner macOSビルド機を「信頼できるプロジェクト専用ノード」として1台から始め、構築・署名・再起動復旧を確認してから増設することです。全リポジトリに開放する汎用Shell Runnerにはしないでください。

01

このガイドを読むべき担当者

GitLab CI/CDへiOSプロジェクトを移行し、macOS Runnerを新設したいプラットフォームエンジニア向けです。

コード署名、ネットワーク分離、CI/CDの認証情報を監査するIT・セキュリティ担当者にも役立ちます。Macを購入するか、レンタルするか、混在させるかを判断するCTOや技術責任者も対象です。

02

最初に決めるべきノードの境界

GitLab Runner macOSビルド機では、最初に性能ではなく「何を実行させるか」を決めます。Shell executorはホスト上でスクリプトを実行するため、ジョブ間の隔離が限定的です。GitLabもShell executorは信頼できるビルド専用にするよう説明しています。
GitLab公式のShell executorに関する安全上の注意 を必ず確認してください。

次の3つを別々に定義します。

  • 通常のPull Request検証を実行するノード
  • TestFlightやApp Store向け署名を実行するノード
  • Xcodeのバージョン切り替えや実験的依存関係を扱うノード

署名証明書を持つノードへ、未検証のブランチや外部コントリビューションを到達させてはいけません。複数プロジェクトを1台で動かす場合も、プロジェクトの信頼度、署名権限、キャッシュの共有範囲を分けて考えます。

単一ノードから始める判断

次の条件なら、まず1台で試します。

  • 使用するXcodeの系列が少ない
  • 同時に走るiOSジョブが限定的
  • 署名ジョブを保護された経路へ限定できる
  • 再起動後の復旧を担当者が検証できる

反対に、複数のXcode系列を常時維持する場合、リリース時間帯にジョブが集中する場合、現地で再ログインできない場合は、最初から役割別のノード構成を検討します。人数だけで台数を決めると、空いている時間の余剰と、ピーク時の待ち時間を見誤ります。

03

導入初日に行うmacOSと実行アカウントの準備

macOS版GitLab Runnerは、システムレベルのLaunchDaemonではありません。ログイン中のユーザーセッションで動くLaunchAgentです。Apple SiliconとIntel Macの両方に導入できますが、iOS Simulatorやコード署名にはユーザーセッションとKeychainへのアクセスが関係します。
GitLab公式のmacOSインストール仕様 を基準にしてください。

準備は次の順番が安全です。

  1. CI専用のmacOSユーザーを作成する
  2. SSH、VNC、または管理用コンソールの接続経路を限定する
  3. FileVaultを有効にし、復旧キーの保管担当を決める
  4. macOS、Xcode、Command Line Toolsの基準を記録する
  5. GitLab RunnerをそのユーザーのGUIセッションから導入する
  6. 再起動後に自動ログインとRunner接続を検証する

FileVaultは保存データを暗号化しますが、暗号化を有効にしただけで運用上の復旧問題が消えるわけではありません。再起動後にディスクのロック解除が必要になる構成では、無人運用の手順とリモート救援経路を別に用意します。
Apple公式のFileVault資料 では、Apple Silicon Macにおける暗号鍵とSecure Enclaveの扱いも説明されています。

Xcodeの基準も先に固定します。GitLabのmacOSセットアップ手順では、Xcodeの初回セットアップとアクティブなDeveloper Directoryの指定が必要です。代表的な確認コマンドは次の骨格に留めます。

sudo xcodebuild -runFirstLaunch
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcodebuild -version

Xcodeのバージョンは、CI/CD変数やノードタグと対応付けます。例えば macos-xcode-a のように、実際の社内命名規則でタグを決めてください。タグ名とXcodeの実体がずれると、ジョブは成功しても再現性を失います。

注意:GitLab Runnerが管理画面でオンラインでも、再起動後にユーザーセッション、Keychain、Simulatorが利用できるとは限りません。必ず実際の再起動を含めて確認してください。

04

Runner登録とジョブの振り分け

Runnerの登録範囲は、プロジェクト、グループ、インスタンスの順に公開範囲が広くなります。最初はプロジェクト単位、複数の関連リポジトリを束ねる場合でもグループ単位から始めるのが無難です。インスタンスRunnerは、署名環境をすべてのプロジェクトへ広げる可能性があるため、明確な管理基準が必要です。
GitLab公式のRunner登録とスコープ説明 を参照してください。

登録時は、現行のRunner認証トークンを使います。旧来の登録トークン方式は非推奨で、将来の削除が予定されています。
GitLab公式の新しいRunner登録ワークフロー に沿って、管理画面でRunnerの範囲、保護設定、タグを先に決めてください。

iOSビルドではShell executorが現実的な候補です。Xcode、Simulator、KeychainをmacOS上で直接扱えるためです。ただし、Dockerコンテナのような強い隔離を期待してはいけません。

gitlab-runner register \
  --url "https://gitlab.example.com/" \
  --token "$RUNNER_AUTHENTICATION_TOKEN" \
  --executor "shell"

.gitlab-ci.ymlでは、Runnerタグを明示します。署名処理には、通常ビルドと異なるタグを割り当てます。

build_ios:
  script:
    - xcodebuild -scheme "$SCHEME" -destination "$DESTINATION" build
  tags:
    - macos-xcode-a
  rules:
    - if: '$CI_COMMIT_BRANCH'

release_ios:
  script:
    - ./ci/sign-and-export.sh
  tags:
    - macos-signing
  rules:
    - if: '$CI_COMMIT_TAG =~ /^release-/'

保護されたブランチとタグを使うと、署名ジョブの実行経路を絞れます。GitLabではRunnerを保護し、保護ブランチや保護タグだけを処理する設定が可能です。
GitLab公式のRunner保護設定保護タグの仕様 を組み合わせてください。

05

最初のパイプラインで署名とキャッシュを検証する

最初から本番用の複雑なワークフローを投入しないでください。最小構成で、次の順に通します。

  1. Gitリポジトリを取得する
  2. Xcodeのバージョンをログへ出力する
  3. Swift PackageやCocoaPodsなどの依存関係を復元する
  4. xcodebuildでビルドする
  5. 単体テストとSimulatorテストを実行する
  6. .ipa、テスト結果、失敗ログをアーティファクトへ保存する

Appleは、外部CIでxcodebuildを使う方法を案内しています。依存関係を固定する場合は、Package.resolvedに基づく解決を使う設計が重要です。
Apple公式のCIでのXcodeビルド資料 を確認してください。

署名情報は、通常ビルドと同じ場所へ置かないでください。証明書とProvisioning ProfileはCI/CD変数から一時的に取得し、専用Keychainへインポートします。ジョブ終了後はKeychain、作業ディレクトリ、一時ファイルを削除します。

Appleのコード署名では、Provisioning Profileが一部のEntitlementを認可します。つまり、証明書ファイルだけを隠しても、署名ノードのアクセス範囲やKeychain権限が広ければ安全とは言えません。
Apple公式のコード署名とProvisioning Profile資料 を基準に、署名担当者と監査担当者の権限を分けてください。

キャッシュはビルドを速くする一方、プロジェクト間の残留リスクを作ります。共有キャッシュを使う場合は、プロジェクト単位のキー、保存期間、削除担当、機密情報が含まれないことを確認します。最初の試験では、キャッシュ有りと無しの両方を実行し、速度差よりも再現性を優先します。

06

FAQ:運用開始前に確認する5項目

GitLab RunnerをmacOSで常時稼働させるには何を確認すべきですか?

macOS版Runnerはユーザーセッションで動くLaunchAgentです。専用ユーザーを用意し、自動ログイン、Keychainへのアクセス、再起動後の再接続を順番に確認します。管理画面のオンライン表示だけで合格にせず、Xcodeビルドと署名処理まで実行してください。

iOSビルド機にはどのexecutorを選ぶべきですか?

iOSやmacOSのネイティブビルドでは、Shell executorが基本候補です。Xcode、Simulator、Keychainを直接扱えるためです。ただし隔離能力は限定的なので、信頼できるリポジトリだけを割り当て、未検証コードや一般公開プロジェクトと混在させないでください。

複数プロジェクトで1台のmacOS Runnerを共有できますか?

共有は可能ですが、通常テストとリリース署名を同じノードに集約することは避けます。プロジェクトまたはグループ単位で登録し、タグと保護タグで処理を振り分けます。共有する場合は、作業ディレクトリ、依存キャッシュ、ログ、Keychainの残留を毎回確認してください。

iOS署名証明書はどのように管理すべきですか?

証明書、秘密鍵、Provisioning Profileをリポジトリへ保存せず、CI/CD変数から一時的に注入します。専用Keychainへ取り込み、署名ジョブの終了時に削除します。署名Runnerは保護されたタグだけを処理し、通常のブランチから到達できないようにしてください。

企業ではMacビルドノードを何台用意すべきですか?

開発者数ではなく、同時実行数、ピーク時の待ち時間、Xcodeの系列数、リリース頻度で判断します。まず1台で記録を取り、待ち時間が継続して許容範囲を超えた時点で増設します。Xcodeの違いと署名権限がある場合は、単純な台数追加よりノード分離を優先します。

07

1週間目に行う無人運用と復旧確認

登録が終わったら、次の確認を実施します。

  1. Runner認証トークンを管理台帳へ登録する
  2. SSH鍵とCI/CD変数の利用範囲を確認する
  3. 署名用Keychainの読み書きを監査する
  4. ジョブ終了後に作業ディレクトリを清掃する
  5. macOSを再起動する
  6. ユーザーセッションとRunnerの再接続を確認する
  7. Xcode、Simulator、Keychainを使う実ジョブを再実行する
  8. 失敗時のリモート救援手順を実行する

再起動後に自動ログインを使う場合は、利便性と物理的な端末保護を同時に評価します。データセンターや管理拠点でのアクセス制御、FileVaultの復旧キー、SSHの許可元、VNCの接続元を別々に記録してください。

安全性をさらに確認したい場合は、企業向けリモートMac運用の案内 と、自社で購入する場合の Mac mini調達ガイド を比較材料にしてください。

08

待ち時間を根拠にノードを増やす

運用開始後は、次の項目を記録します。

  • Runnerの待機時間
  • ジョブの実行時間
  • 成功率と再実行率
  • ディスク使用量の増加
  • Xcode切り替えによる停止時間
  • 署名ジョブの実行回数
  • 再起動後の復旧時間

増設の判断は、次の条件分岐で進めます。

  • 通常時間帯も待ち時間が続くなら、同じXcode系列のノードを追加します。
  • 特定のリリース時間帯だけ混雑するなら、ピーク期間だけ使える遠隔Macのレンタルを検討します。
  • Xcodeの系列が異なるなら、タグでノードを分けます。
  • 署名権限が異なるなら、台数より先にセキュリティ境界を分けます。
  • 再起動復旧を現地で対応できないなら、リモート管理と代替ノードを用意してから本番化します。
  • 負荷が安定し、長期稼働が確定しているなら、購入とレンタルのTCOを同じ計算式で比較します。

企業のMac基盤では、常駐ノードを増やすことが必ずしも最適とは限りません。購入の場合は初期費用、減価償却、保守、交換、保管、現地対応を含めます。レンタルの場合は月額または契約期間、転送、運用管理、追加ノード費用を含めます。

比較項目 自社購入Mac 遠隔Macレンタル 混合構成
初期費用 本体、周辺機器、設置費を計上 契約期間と初期設定費を計上 常駐分のみ購入
ピーク対応 余剰台数を持つ必要がある 必要期間だけ増設しやすい 変動分をレンタル
物理アクセス 自社で対応 接続経路と救援手順を確認 購入分は現地対応
署名環境 自社ポリシーで管理 専用ノードと権限設計を確認 署名は購入分に固定可能
Xcode切り替え 空き容量と保守枠が必要 ノード単位で分離しやすい 主要版を購入、試験版をレンタル
TCO計算 本体費+保守+設置+更新 契約費+運用費+拡張費 固定費と変動費を分離

導入前に、次の式へ自社の数値を入れてください。

購入TCO
= 本体・設置費
+ 保守費
+ 電源・回線費
+ 現地対応費
+ 更新時の移行費
- 売却または残存価値

レンタルTCO
= 契約費
+ 初期設定費
+ 運用管理費
+ 追加ノード費
+ データ転送・接続関連費

この比較では、特定の価格や削減率を先に置かないことが重要です。ピーク負荷が読めない、複数のXcode環境を短期間で試したい、現地での復旧担当がいない場合は、周期単位で増減できる遠隔Macが有利になりやすいです。一方、長期に安定した高負荷で稼働し、物理アクセスや社内監査を重視するなら、購入ノードが適する可能性があります。

09

本番投入のGo/No-Go判定

本番投入は、次の項目がすべて確認できた場合に進めます。

  • 信頼できるプロジェクトだけがRunnerへ到達できる
  • 通常ビルドと署名ビルドのタグが分離されている
  • 保護ブランチと保護タグが機能している
  • XcodeとCommand Line Toolsの基準が記録されている
  • Keychainと署名材料がジョブ後に残っていない
  • キャッシュの共有範囲と削除方法が決まっている
  • 再起動後にRunner、Xcode、Simulatorが復旧する
  • 失敗ログとアーティファクトを取得できる
  • 待ち時間と同時実行数を継続的に記録できる
  • リモート救援または代替ノードの手順がある

現在の構成が開発者のローカルMac頼み、全プロジェクト共有のShell Runner、または現地担当者の手動再起動に依存しているなら、長期運用では不安が残ります。環境差異、署名情報の露出、ピーク時の待ち時間、Xcode更新時の停止が同時に発生するためです。

単一ノードで実ジョブを検証した後、ピーク同時実行数、Xcodeの系列、リリース頻度、署名境界を整理してください。負荷が変動する場合や現地運用が難しい場合は、KVMNODEの遠隔Macを試験ノードとして追加し、実際のキュー待ち時間と再起動復旧記録でレンタル期間と長期ノード数を決める方法が現実的です。最初から購入台数を固定するより、GitLab CI/CDの実測値に合わせて段階的に拡張できます。