iOS ビルドに専用の macOS 環境が必要なのはなぜですか?
Linux コンテナ内で Gradle を実行できる Android とは異なり、Apple のビルド ツール チェーン - xcodebuild、コード署名、notarytool、App Store Connect API はすべて、macOS を Apple Silicon / Intel 物理マシンにバインドします。これは、iOS 製品を扱うすべてのチームが、遅かれ早かれ「この Mac を誰が提供するのか?」という問題に直面することを意味します。
一般的な問題点は 3 つのカテゴリに要約できます: パブリック ランナーのキューイング (GitHub Actions 無料 macOS クォータが不足しており、ワークフローはピーク時にマシンが割り当てられるまで 20 ~ 45 分かかる場合があります)、ローカル開発マシンが CI によって占有されている (同僚がコードをプッシュした後、Xcode がコンパイル速度が低下し、ファンが回転します)乱暴に)、証明書とキーの管理が混乱します(複数のマシンが個別に .p12 をインポートし、有効期限が切れた後は誰も知りません)。クラウド内の専用 Mac ノードは、最初の 2 つの問題を同時に解決し、3 つ目の問題に対して単一の信頼できる環境を提供できます。
ハードウェア: Mac mini M4 · 10 コア CPU · 16 GB ユニファイド メモリ · 256 GB SSD · 1 Gbps 専用帯域幅 (SpinMac 日本ノード)。
システム: macOS 15 Sequoia、Xcode 16.4。プロジェクト: SwiftUI 中型アプリ (約 120,000 行、3 つの拡張ターゲットを含む)。
CI ツール: GitHub Actions セルフホスト ランナー 2.323.0、Jenkins 2.479 LTS + macOS エージェント。
署名: Apple Distribution Certificate + App Store Connect API キー (発行者 ID + キー ID + .p8)。
3 つの CI ソリューションの比較: どれを選択すべきですか?
Xcode をインストールする前に、まずチームがどのパスに属しているかを決定してください。 3 つのオプションに絶対的な有利不利はありません。違いはキュー耐性、月次ビルド数、 コンプライアンス要件にあります。
| プラン | 一般的なコスト | キューイング/同時実行性 | チームに適した |
|---|---|---|---|
| GitHub ホスティング macOS ランナー | 分単位で請求されます (約 0.08 ドル/分から) | 共有プール、ピーク時間帯には明らかな行列 | 毎月のビルド <500 分、許容可能な待ち時間 |
| Mac miniを購入してパソコン室に置きました | ハードウェア $599+ 1 回 + 電気代の運用とメンテナンス | 排他的ですが、独自のシステムと証明書を維持する必要があります | 固定オフィススペースと長期高頻度工事を保有 |
| クラウド上の専用 Mac (日単位でレンタル) | SpinMac $21.2/日から、契約なし | 物理マシン限定、すぐに利用可能 | 中小規模のチーム、段階的なリリース、リモート コラボレーション |
私たちの実際のテスト プロジェクトは、中規模の SwiftUI プロジェクトにあります。 M4 ノードでの xcodebuild archive の完全なビルドには、約 4 分 12 秒かかります (Swift コンパイルとリンクを含む)。同じプロジェクトが macOS-14 Runner の GitHub でホストされています。 18 分間キューに入れられた後、実際のビルドには 5 分 40 秒かかり、合計時間は 24 分近くになります。 「プッシュしてテスト」する必要があるチームの場合、ビルド自体よりもキュー時間の方が配信リズムに影響を与えることがよくあります。
クラウドノード環境の初期化: Xcode および署名マテリアル
SpinMac は、macOS が完全にプリインストールされ、管理者権限が付与された Mac mini を出荷します。アクティベーション後、SSH またはブラウザ VNC 経由でログインし、次の順序で CI の事前設定を完了します。証明書と説明ファイルは固定パスに保存し、後続のワークフロー スクリプトで参照することをお勧めします。
-
01
コマンドラインツールを使用してXcodeをインストールします
App Store または
xcode-selectから Xcode 16.x をインストールするには、sudo xcodebuild -license acceptとxcodebuild -runFirstLaunchを実行します。確認:xcodebuild -versionは正しいバージョン番号を出力する必要があります。 -
02
署名証明書とプロビジョニングプロファイルをインポートする
Distribution .p12 とパスワードを安全なチャネル経由で
~/certs/に渡し、security importを使用してキーチェーンをインポートします。 .mobileprovision ファイルは~/Library/MobileDevice/Provisioning Profiles/に配置されます。 CI 環境では、プライベート キーチェーンを使用し、-T /usr/bin/codesign信頼を設定することをお勧めします。 -
03
App Store 接続 API キーの設定
Apple Developer バックエンドで API キーを作成し、
AuthKey_XXXXXX.p8を~/private_keys/に保存します。 TestFlight をアップロードするときは、xcrun altoolまたはfastlane パイロット アップロードを使用して、対話型の Apple ID ログインを回避します。 -
04
リポジトリのクローンを作成し、DerivedData をキャッシュする
初めて
git cloneを実行した後、ローカル アーカイブを実行して、署名リンクがスムーズであることを確認します。 DerivedData をローカル SSD (256 GB は中規模プロジェクトに十分) に保持することで、後続の増分ビルドの時間を 30 ~ 50% 節約できます。
codesign はヘッドレス環境 (SSH / ランナー) で失敗し、90% の確率でキーチェーンがロック解除または認証されていません。ビルド スクリプトの先頭に securityunlock-keychain -p "$KEYCHAIN_PASSWORD" ~/Library/Keychains/ci.keychain-db を追加し、codesign が秘密キーにアクセスできるように set-key-partition-list を設定します。パスワードを Git リポジトリにクリア テキストで書き込まないでください。パスワードを挿入するには、GitHub シークレットまたは Jenkins 認証情報を使用してください。
GitHub Actions 自己ホスト型ランナーをマウントします
専用ランナーが登録されると、ワークフローは runs-on: self-hosted またはカスタム ラベル (macos-m4 など) を介してこのクラウド Mac に送信され、パブリック プールのキューイングを完全にバイパスできます。次の手順は、SpinMac ノードでテストされ、合格しました。
GitHub リポジトリの設定 → アクション → ランナー → 新しいセルフホスト ランナーで、macOS ARM64 を選択し、ページの指示に従って actions-runner パッケージをダウンロードして解凍し、次のコマンドを実行します。
./config.sh --url https://github.com/YOUR_ORG/YOUR_REPO --token RUNNER_TOKEN --labels macos-m4,ios-build --unattended
登録が完了したら、システム サービスとしてインストールし、ノードの再起動後にランナーが自動的にオンラインになるようにします: sudo ./svc.sh install → sudo ./svc.sh start。ワークフロー YAML でラベルを指定します。
runs-on: [self-hosted, macos-m4]
一般的な iOS ビルド ジョブの中心的な手順には、コードのチェックアウト → キーチェーンのロック解除 → xcodebuild archive → xcodebuild -exportArchive → xcrun altool --upload-app または Fastlane upload_to_testflight が含まれます。 M4 ノードで実行する Fastlane レーンは、プッシュから TestFlight までの処理を完了するまでに平均約 11 分かかります (Apple 側のキューイングを含む) が、そのうちローカルのビルドとアップロードにかかる時間はわずか 6 分です。
セルフホスト型ランナーは、リポジトリ コードと署名キーにアクセスできます。リポジトリ コラボレーターの権限を制限し、ランナー登録トークンを定期的にローテーションし、フォーク PR でキー付きワークフローを自動的にトリガーしないようにしてください (pull_request_target は細心の注意を払って使用してください)。チームがノードを共有する場合、異なるプロジェクトに異なるランナーを登録したり、OpenClaw サンドボックスと連携してエージェントの操作範囲を分離したりできます。
Jenkins macOS エージェントの設定ポイント
チームが既に Jenkins コントローラー (Linux 上で実行可能) を持っている場合、macOS ビルド機能にはエージェント ノードを通じてアクセスします。 JDK 17 と Jenkins Agent.jar を SpinMac クラウド Mac にインストールし、LaunchDaemon モードに常駐すると、コントローラーが SSH または JNLP 経由でタスクをプルします。
Jenkins の利点は、パイプラインの視覚化とプラグインのエコロジーにあります。Xcode プラグイン、認証情報バインディング、AnsiColor ログのカラーリング、製品アーカイブのビルドなどです。一般的なパイプライン フラグメント ロジックは次のとおりです。stage('Archive') で sh 'xcodebuild...' を呼び出し、Fastlane を呼び出します。 stage('Upload') の altool。 Xcode の複数のバージョン間で切り替える際の混乱を避けるために、DEVELOPER_DIR を /Applications/Xcode.app/Contents/Developer に修正しました。
GitHub Actions と比較して、Jenkins は複数のブランチ、複数の環境があり、 手動の承認ゲートが必要な社内の企業プロセスに適しています。クラウド Mac を日単位でレンタルすることで、「柔軟なエージェント」として使用できます。ノードはリリース週にオープンされ、オフシーズンにリリースされるため、コンピュータ ルームの Mac を 365 日運用および保守する必要がなくなります。
アーカイブ、署名、TestFlight アップロードの練習
どの CI セットを使用しても、最終的な製品リンクは同じです。アーカイブで .xcarchive が生成される → エクスポートで .ipa が生成される → アップロードApp Store 接続。コマンド ライン アプローチ (Xcode GUI に依存しない) は、CI の標準的な手法です。
アーカイブの例 (リリース構成、指定されたスキーム、および出力パス):
xcodebuild archive -workspace MyApp.xcworkspace -scheme MyApp -configuration Release -archivePath build/MyApp.xcarchive CODE_SIGN_STYLE=Manual PROVISIONING_PROFILE_SPECIFIER="MyApp AppStore"
エクスポートには ExportOptions.plist を装備する必要があります (メソッドは app-store に設定されます)。その後、次のようになります。
xcodebuild -exportArchive -archivePath build/MyApp.xcarchive -exportPath build/export -exportOptionsPlist ExportOptions.plist
TestFlight をアップロードする 無人環境で 2 要素認証がスタックすることを避けるために、API キー方式を使用することをお勧めします。
xcrun altool --upload-app -f build/export/MyApp.ipa -t ios --apiKey KEY_ID --apiIssuer ISSUER_ID
中規模のプロジェクトでは、M4 の 10 コア CPU により、Swift の同時コンパイルが古い Intel Mac CI マシンよりも大幅に高速になります。 16 GB ユニファイド メモリには、スワップをトリガーせずに完全な クリーン ビルド を実行できる余地がまだあります。プロジェクトに多数の Swift パッケージの依存関係が含まれている場合は、後続のビルドを短縮するために -clonedSourcePackagesDirPath キャッシュ ディレクトリを有効にすることをお勧めします。
オフィスのコンピューター室なしで iOS CI を安定して実行するにはどうすればよいですか?
多くの独立系開発者や小規模チームの本当のジレンマは、構築には macOS が必要だが、オフィスを借りたり、ネットワーク ケーブルを引いたり、停電に対処したり、CI マシンのシステム アップグレードをしたくないということです。パブリック クラウドの仮想マシンは要件を満たすことができず (完全な macOS と Apple の署名チェーンが存在しません)、中古の Mac mini は不安定なアップリンク帯域幅、IP の変更、自宅に置いた場合の家族による誤ったシャットダウンなどの問題に直面します。
SpinMac はベアメタル Mac mini M4 の専用レンタルです:仮想化なし、オーバーセルなし。各台 16 GB メモリと 1 Gbps 専用帯域を備え、支払い後 1〜5 分で開通します。シンガポール、日本、韓国、中国香港、米国東部の 5 リージョンから選べます。例えば日本向けアプリなら東京ノードで TestFlight アップロード時の越境遅延を抑えられます。
請求に関しては、開始価格は 1 日あたり $21.2、1 週間あたり $57.3、1 か月あたり $106.1 です。長期契約はありません。多くの場合、マシンを自分で購入して年間を通じて電力を追加するよりも、リリースが集中する週にノードを開いてランナーをマウントし、毎日のメンテナンス期間中にリリースする方がコスト効率が高くなります。複数のマシンを並行して構築する必要がある場合は、Thunderbolt 5 並列サービスを購入して 80 Gbps クラスターを形成できます。これは、大規模なモノリポジトリや複数のアプリ マトリックスの同時アーカイブに適しています。
-
01
SpinMac でノードを選択し、アクティブ化します
コンソールにログインし、リージョンとリース期間を選択します。支払い後、SSH 認証情報と VNC 入り口が自動的に発行されます。詳細については、ヘルプセンターをご覧ください。
-
02
この記事のセクション 3 に従って、Xcode と署名の構成を完了します。
GitHub Actions / Jenkins で統一的に読み込むために、キーチェーンと API キーのパスを環境変数に書き込むことをお勧めします。
-
03
ランナーを登録し、最初のパイプラインをトリガーする
最初にデバッグ ビルドを実行し、次にリリース アーカイブ + TestFlight に切り替え、徐々に Fastlane またはネイティブ スクリプトをリポジトリに固めます。
コストと選択: 1 つの表に要約
| あなたの状況 | 推奨パス | クラウド Mac の役割 |
|---|---|---|
| 独立した開発者、月に 1 ~ 2 リリース | 毎日レンタルSpinMac + マニュアルアーカイブをリリース | 使用後に解放される一時的なビルド マシン |
| 5 ~ 15 人のチームで 1 日に複数回プッシュする | 常駐セルフホストランナー | 月額制で独占的で行列なしでレンタル可能 |
| Jenkinsはいますが、macOSエージェントが見つかりません | 柔軟なエージェントとしての Cloud Mac | 新しいマシンの購入を避けるためのピーク容量の拡張 |
| マルチアプリマトリックス + 夜間バッチビルド | TB5クラスタ並列接続 | 複数の M4 並列アーカイブ |
iOS CI/CD の技術的基準は、Xcode そのものではなく、安定したmacOS の計算能力 + 再現可能な署名環境です。パブリックランナーは低頻度の施工に適しています。自社で構築したコンピューター ルームは、運用とメンテナンスの能力を備えた成熟したチームに適しています。クラウド専用 Mac は、「行列に並びたくない、マシンを購入したくない」という中間点を満たします。請求は日単位で行われ、物理マシンのパフォーマンスは予測可能で、グローバル ノードは近くに展開されます。コンパイルと署名をクラウドに移動した後、ローカルの MacBook は、ファンとメモリを使用するために深夜に CI タスクに占領されるのではなく、コードの作成に集中できます。