ホーム / ブログ / GitLab CI iOSパッケージング:2026年リモートMacチュートリアル
ENGINEERING_BLOG · 2026.08.31

GitLab CI iOSパッケージング:2026年リモートMacチュートリアル

Linux Runnerではビルド段階を通過するのに、iOS Jobだけ「Xcodeが見つからない」と失敗する。

最短の解決策は、専用のmacOSユーザーセッションでShell executorを動かし、Xcode・署名情報・成果物・再起動後の復旧を6項目で検証することです。GitLab CI iOSビルドはRunnerを登録するだけでは本番投入できません。

このページは、GitLabでコードを管理しているものの、現在のRunnerがAndroidやバックエンド専用になっている個人開発者、手動のXcode Archiveを自動化したいiOS開発者、署名とTestFlight配信を常時稼働するMacへ移したい小規模チーム向けです。

SECTION 01まず切り分けるべき「Macが必要な境界」

iOSのコンパイル、シミュレーターを使うテスト、Archive、署名済みアプリの書き出しは、macOS上のXcodeとAppleの開発ツールチェーンを前提にします。Linux RunnerはGitLab Jobを実行できますが、Xcodeを動かす環境にはならないため、iOS用JobをmacOS Runnerへ明示的にルーティングする必要があります。

GitLab公式ドキュメントでは、macOS上のRunnerはユーザー単位のLaunchAgentとしてサービス化でき、Shell executorではホスト上でスクリプトを実行します。ログイン中のユーザーセッションやKeychainへ到達できる一方、仮想マシンのような強い分離はありません。macOS RunnerのサービスモードShell executorの実行境界を先に確認してください。

リモートMacでGitLab Runnerを動かす場合、グラフィカルなログイン状態は必要ですか。

常に画面を操作する必要はありませんが、ユーザーセッションが存在しないとLaunchAgent、Keychain、GUIを必要とする処理の挙動が変わります。自動ログインだけを唯一の対策にせず、専用ユーザー、画面ロック、ディスク暗号化、物理ホストへのアクセス権限を含めて運用を決めます。

SECTION 026つの運用指標を先に採点する

第一指標:再起動後もRunnerが接続するか

次の順序を、設定完了の証拠として扱います。

  1. リモートMacを再起動します。
  2. CI専用ユーザーでログインし、ユーザー単位のRunnerサービスが起動しているか確認します。
  3. GitLabのRunner画面でオンライン状態とタグを確認します。
  4. tagsでiOS用Jobを専用Runnerへ送り、実際にJobを受け取るか確認します。
  5. そのJob内でwhoamixcode-select -psecurity list-keychainsを実行し、想定ユーザーと環境を脱敏して記録します。

GitLab RunnerがmacOSの再起動後にオフラインになる場合はどうしますか。

Runnerの登録情報だけでなく、LaunchAgentの読み込み、ログインセッション、ネットワーク接続、Runnerプロセスのログを順番に確認します。再起動後に手動でサービスを起動しないと復旧しないなら、常駐ビルド機としては「要修正」です。

第二指標:同じコミットが同じXcodeを呼び出すか

Macに複数のXcodeが入っている場合、アプリケーションフォルダーの一覧だけでは実際の呼び出し先を判定できません。Job内でxcode-select -pxcodebuild -versionxcodebuild -showsdksを実行し、XcodeのDeveloper Directory、SDK、Command Line Toolsを確認します。

依存関係も同じ基準で固定します。Swift Package Manager、CocoaPods、Carthageなどを利用しているなら、ロックファイルをリポジトリに保存し、CIではそのファイルを基準に解決します。環境変数、シェルのPATH、RubyやNode.jsの選択も、対話式ターミナルとRunnerで一致させてください。

単なる依存関係の解決成功は、リリース可能の証明ではありません。隔離した検証プロジェクトで同一コミットを連続実行し、依存関係の解決、コンパイル、Archiveを別々の結果として記録します。

注意:xcodebuildの結果だけで「TestFlightへ配信できる」と判断しないでください。AppleのXcodeによるArchiveと配布の手順に沿って、署名済みの配布物まで確認します。

第三指標:誤ったJobが公開用Macを汚染しないか

Shell executorはコンテナ内の一時環境ではなく、macOSホスト上でコマンドを実行します。作業ディレクトリ、DerivedData、Keychain、環境変数、インストール済みツールが次のJobへ影響する可能性があるため、公開用Runnerを不特定のコードに開放してはいけません。

GitLabではRunnerタグと保護されたブランチ、保護された変数を組み合わせられます。タグと保護されたRunnerの公式説明を基準に、例えば次のように分けます。

  • ビルド用Runner:内部リポジトリのビルドとテストのみを受け付けます。
  • 公開用Runner:保護ブランチからのArchiveとTestFlight配信だけを受け付けます。
  • 外部からのMerge Request:署名情報を持つRunnerへ送らない設定にします。
  • 作業ディレクトリ:ビルド、テスト、公開で共用するか、ジョブごとに分離します。

ビルドと公開を同じアカウントや同じ作業領域で実行してよいのは、リポジトリの信頼境界、削除処理、同時実行の制御を説明できる場合だけです。説明できない場合は、公開用Macを分離する方が安全です。

SECTION 03署名と配信を壊さない構成はどれか

第四指標:GitLab側とmacOS側の権限を分ける

CI/CD変数、App Store Connect API Key、証明書、秘密鍵、Keychain、Provisioning Profileは別の資産です。API Keyはアップロード認証に使えても、ローカルの署名証明書と秘密鍵を代替するものではありません。App Store Connect API Keyの作成要件を確認し、用途を混同しないでください。

GitLabには、通常の変数、保護された変数、ファイル型変数があります。CI/CD変数の公式仕様に沿って、秘密情報は保護ブランチだけで利用できるようにし、ログに展開されない設計にします。ただし、ログのマスキングは秘密情報が漏れないことを保証しません。コマンドのデバッグ出力、署名ツールのエラー、生成ファイルのArtifactsも確認対象です。

例では、実在する値を絶対に書かず、明確な置換記号を使います。

variables:
  CERTIFICATE_FILE: "<PLACEHOLDER_CERTIFICATE_FILE>"
  PROFILE_FILE: "<PLACEHOLDER_PROFILE_FILE>"
  KEYCHAIN_NAME: "<PLACEHOLDER_KEYCHAIN>"

sign:
  tags:
    - "<PLACEHOLDER_IOS_RELEASE_RUNNER>"
  script:
    - security create-keychain -p "<PLACEHOLDER_KEYCHAIN_PASSWORD>" "$KEYCHAIN_NAME"
    - security unlock-keychain -p "<PLACEHOLDER_KEYCHAIN_PASSWORD>" "$KEYCHAIN_NAME"
    - security import "$CERTIFICATE_FILE" -k "$KEYCHAIN_NAME" -P "<PLACEHOLDER_CERTIFICATE_PASSWORD>" -T /usr/bin/codesign
    - mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
    - cp "$PROFILE_FILE" "$HOME/Library/MobileDevice/Provisioning Profiles/<PLACEHOLDER_PROFILE>.mobileprovision"

実運用では、作成した一時Keychainの削除、権限の限定、失敗時の後始末を加えます。証明書名、Bundle ID、Team ID、Key ID、パスワード、Tokenは公開用設定や記事へ貼り付けません。

第五指標:キャッシュと成果物を混ぜていないか

依存関係の再利用にはCache、次のStageへ渡すファイルにはArtifactsを使います。GitLab公式仕様でも両者は目的が異なるため、署名用秘密鍵や唯一の公開用Archiveを通常のCacheへ入れる設計は避けます。CacheとArtifactsの違いを基準に、ロックファイルが変わったときにキャッシュキーが変わるよう設計します。

成果物は、次の関係を追跡できるようにします。

成果物 用途 保管・確認の考え方
依存関係キャッシュ 再取得の削減 ロックファイルをキーにし、署名情報は含めません
.xcarchive Archive結果の保存 コミット、Scheme、署名方式と関連付けます
Export後のアプリ TestFlight配信用 Archiveから生成されたものと記録を結び付けます
.xcresult テスト・ビルド診断 失敗したテストや警告を後から確認します

保管期限や容量はプロジェクト設定に依存するため、固定の保存日数として扱いません。GitLabの現在の設定値を確認し、公開版だけは外部バックアップや再生成手順も用意します。

SECTION 04実際のArchiveとTestFlightで最終判定する

GitLab Runnerから自動でArchiveし、TestFlightへ送るには何を分けますか。

Jobを、ビルド、署名付きExport、App Store Connectへのアップロード、処理状態の確認に分けます。通常のDebug Buildが成功しても、配布用証明書、Provisioning Profile、Bundle ID、App Store Connect権限が正しいとは限りません。

次の手順で確認します。

  1. 保護されたブランチへ、検証対象のコミットを用意します。
  2. 専用macOS RunnerでXcodeの選択先とSDKを記録します。
  3. xcodebuild archiveを実行し、.xcarchive.xcresultをArtifactsへ保存します。
  4. 配布方式を明示してExportし、署名後のアプリを生成します。
  5. Appleが案内するApp Store Connectへのビルドアップロード要件に従ってアップロードします。
  6. App Store Connect側でビルド処理が完了し、TestFlightで利用可能になるまで確認します。
  7. Macを再起動し、Runnerの再接続、Xcodeの選択、Keychainアクセス、次のビルドを再度確認します。

この流れで、Archiveだけ成功してアップロードが失敗した場合は署名やAPI権限の問題、アップロード後の処理で止まった場合はApp Store Connect側の状態確認が必要です。各段階のログと成果物を残せば、同じ失敗を「Xcodeの問題」と誤認しにくくなります。

条件分岐で導入方法を決める

  • 保護ブランチだけが公開Jobを実行し、専用ユーザーとKeychainを用意できる場合は、常駐macOS Runnerとして進めます。
  • 再起動後にログインやRunner起動を毎回手作業で行う場合は、先にLaunchAgentとセッション復旧を修正します。
  • 外部Merge Requestを同じShell Runnerが受け取る場合は、署名情報を分離するまで公開用Runnerにしません。
  • 物理Macを常時オンラインにできない場合は、リモートMacで専用Runnerを構築し、ArchiveからTestFlightまで検証してから利用期間を決めます。
  • 長時間の常駐ビルド、物理デバイス接続、独自のネットワーク制御が必要な場合は、レンタルより自社管理のMacや専用ホストが適しています。

経験上、判定を「Pipelineが緑になったか」だけに絞ると、再起動後のオフライン、別Xcodeの呼び出し、署名情報の残留を見落とします。合格条件は、保護ブランチからの実際の配布と、その直後の再起動復旧です。

SECTION 05既存のMacとリモートMac、どちらで常駐Runnerを持つか

手元のMacをそのまま公開用Runnerにすると、開発中のKeychainや作業ディレクトリをCIへ共有しやすく、ログインユーザーの操作で環境が変わります。加えて、電源オフ、スリープ、回線変更、Xcode更新のタイミングが公開Jobの安定性に影響します。

一方、専用のリモートMacなら、CI専用ユーザー、公開用Keychain、タグ、保護ブランチを切り分けやすくなります。ただし、Shell executorの分離が限定的である点は変わらないため、信頼できないコードを実行するRunnerとは共用しません。

既存Macの常駐会話、専用アカウント、Xcodeと署名ツールの固定を確認したうえで、運用できない項目が残るなら、MACNOXのリモートMac利用案内を使って専用環境を検討できます。費用と期間を先に比較したい場合は、Macレンタルの料金案内で、週単位・月単位などの利用計画を確認してください。

個人用Macを流用する構成は初期費用を抑えられますが、開発作業との競合、秘密情報の混在、再起動時の復旧確認が弱点です。常時稼働する公開Jobを短期間だけ試すなら、リモートMacの申込み手順から専用Runnerを用意し、まず実際のGitLab PipelineでArchive、TestFlight、再起動後の復旧まで確認する方が、購入前の判断として無駄がありません。

最終的に、既存のMacでこれらの条件を満たせるなら自前運用で十分です。満たせない状態でLinux Runnerや個人環境へ公開処理を混ぜ続けると、Xcodeの不一致、署名情報の漏えい、再起動後の停止が繰り返されます。常時オンラインのMacが手元にないなら、MACNOXのリモートMacで検証期間を設け、ビルド頻度に応じて週、月、さらに長い期間の利用へ進む判断が現実的です。