1–5 分で納品

Runner 待ち行列を回避、iOS ビルドを直接実行

$21.8 / 日〜 · 専用物理サーバー専有
クラウド Mac を設定
M4 · 16 GB Xcode バージョン固定可能 5 つのグローバルノード

Mac がなくても iOS CI/CD を実行:GitHub Actions セルフホスト Runner 接続ガイド

GitHub ホスト macOS Runner はピーク時 20 分待ちが日常、Xcode バージョンも制御不能。本文はゼロから解説:専用 Mac mini M4 クラウドノードでセルフホスト Runner インストール、Xcode Archive とコード署名の完全設定、fastlane で IPA を TestFlight へ自動プッシュ、Jenkins Agent 方案との比較。

なぜセルフホスト Runner が GitHub ホスト Runner より iOS ビルドに適しているのか?

GitHub Actions の macOS ホスト Runner は理論上ハードウェアメンテナンス不要だが、本番環境では回避しにくい問題がいくつかある。

第一に待ち時間。GitHub の macOS Runner プール容量は Linux よりはるかに少ない。ピーク(UTC 12:00–20:00、アジア太平洋勤務時間帯)で runs-on: macos-latest トリガーから Runner 準備まで、待ち時間中央値 8–15 分、20 分超も。Clean Build 自体 6 分の中型 SwiftUI プロジェクトでは、待ち時間が実コンパイル時間を超える。

第二にXcode バージョンが制御不能macos-latest タグは GitHub インフラアップグレードで Xcode バージョンがサイレント切替。Xcode 15 → 16 の無通知アップグレードでビルド失敗の先例あり。手動で xcode-select ステップ追加とメジャーバージョン互換待ちが必要。

第三に無料枠の消費が早い。macOS Runner の課金ウェイトは Linux の 10 倍(GitHub 公式ドキュメント)。無料アカウント月 2000 分は macOS で 200 分に換算、やや密集したイテレーションサイクルで超過課金。

対照的に、自前 Mac に接続したセルフホスト Runner は上記 3 点を完全回避:Runner は常時オンライン、Xcode バージョンは自行管理、実行時間は課金なし。唯一のハードルは常時稼働 macOS マシンが必要——本文が解決する問題。

8–20 min
GitHub ホスト macOS Runner ピーク待ち時間
< 30 s
セルフホスト Runner(オンライン Mac)job 起動遅延
10×
macOS 対 Linux 課金倍率(GitHub 公式)
固定
セルフホストノードの Xcode バージョンは完全に制御可能

準備:クラウド Mac ノードの開通と基本環境

iOS CI/CD 接続前に、SSH 接続可能で 24 時間オンラインの macOS マシンが必要。本文は VPSRox 専用 Mac mini M4 ノードを例に(物理 Mac mini / Mac Studio も適用可)。VPSRox コンソール納品後 5 分以内に以下の手順を完了可能。

SSH 接続と Xcode Command Line Tools

  1. 01
    SSH 鍵認証を設定

    コンソールでパブリック IP をコピーし、ローカルで実行:

    ssh-copy-id -i ~/.ssh/id_ed25519.pub user@<ノードIP>

    完了後、パスワードログインを無効化(PasswordAuthentication no)し、ブルートフォース攻撃を防止。

  2. 02
    Xcode Command Line Tools をインストール

    xcode-select --install

    完全な Xcode GUI(Archive 署名用)が必要な場合、developer.apple.com/downloads から .xip をダウンロード、解凍後 /Applications/ に移動してパス切替:

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

  3. 03
    Homebrew をインストール

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    インストール後、/opt/homebrew/bin を PATH に追加し、~/.zprofile に書き込む。

  4. 04
    Xcode ビルドチェーンを検証

    xcodebuild -version

    Xcode バージョンと Build Version の出力を確認。後続 YAML で XCODE_VERSION 環境変数でバージョンを固定可能。

推奨:xcodes ツールで複数 Xcode バージョンを管理

brew install xcodesorg/made/xcodesxcodes をインストールし、Xcode バージョンを素早く切替。xcode-select パス手動変更不要。CI ワークフローで xcodes select 16.2 によりバージョンを厳密固定、漂移を防止。

GitHub Actions セルフホスト Runner のインストールと登録

GitHub 提供のセルフホスト Runner インストーラーは Mac 上でポーリングデーモンを実行し、workflow トリガー時に job をローカルで実行。Mac からポートを公開する必要はない。

GitHub リポジトリで登録トークンを取得

対象リポジトリ → SettingsActionsRunnersNew self-hosted runnermacOS プラットフォーム選択、ページのダウンロードコマンドと登録トークンをコピー(Token 有効期限 1 時間)。

  1. 01
    Runner をダウンロードして解凍

    mkdir actions-runner && cd actions-runner

    curl -o actions-runner-osx-arm64-2.319.1.tar.gz -L https://github.com/actions/runner/releases/download/v2.319.1/actions-runner-osx-arm64-2.319.1.tar.gz

    tar xzf ./actions-runner-osx-arm64-2.319.1.tar.gz

    osx-arm64 パッケージ(Apple Silicon)を選択。バージョンは GitHub ページの表示に従う。

  2. 02
    Runner を登録

    ./config.sh --url https://github.com/YOUR_ORG/YOUR_REPO --token <TOKEN> --name mac-m4-vpsrox --labels mac,xcode16,ios

    --labels カスタムラベルは後で YAML の runs-on で使用し、このマシンへ正確にルーティング可能。

  3. 03
    launchd サービスとしてインストール(起動時自動起動)

    ./svc.sh install

    ./svc.sh start

    launchd はユーザーログイン後に Runner プロセスを自動起動。状態確認:./svc.sh status

Workflow YAML でセルフホスト Runner を指定

登録完了後、.github/workflows/ios-ci.ymlruns-on をカスタムラベルに置換:

jobs:
  build:
    runs-on: [self-hosted, mac, xcode16]
    steps:
      - uses: actions/checkout@v4
      - name: Show Xcode version
        run: xcodebuild -version
セキュリティ警告:公開リポジトリではセルフホスト Runner に注意

セルフホスト Runner は公開リポジトリで fork PR によりトリガーされる可能性があり、悪意コードが Mac 上で実行される。推奨:①プライベートリポジトリまたは Organization 範囲のみ有効化;②Runner をシステムアカウント(非管理者)で実行、権限を厳格制限;③~/.bash_history~/actions-runner/_diag/ ログを定期監査。

Xcode ビルド環境と依存関係管理の設定

クリーンな iOS ビルドには通常 3 点が必要:依存取得、コンパイルキャッシュ、派生データパス分離。

CocoaPods vs Swift Package Manager

プロジェクトが CocoaPods を使用する場合、Runner マシンに一度インストール:

sudo gem install cocoapods

CI ステップ内で:

- name: Install CocoaPods
  run: pod install --repo-update
  working-directory: ./ios

Swift Package Manager 使用時、Xcode は初回ビルドで依存を自動解決。後続 CI を高速化するため、job 内で SPM 解決結果をキャッシュ可能:

- uses: actions/cache@v4
  with:
    path: ~/Library/Developer/Xcode/DerivedData
    key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}

DerivedData パス分離

同一 Runner 上で複数プロジェクトが並列ビルドする場合、デフォルトの DerivedData パスが干渉する。xcodebuild コマンドで派生データパスを明示指定することを推奨:

xcodebuild \
  -project MyApp.xcodeproj \
  -scheme MyApp \
  -sdk iphoneos \
  -configuration Release \
  -derivedDataPath ./DerivedData \
  clean build

並列ビルドパラメータ最適化

Mac mini M4 は 10 コア CPU(4 性能コア + 6 効率コア)。Xcode のデフォルト並列数は通常コア数に相当。大規模プロジェクトではメモリ圧力回避のため適宜下げる:

defaults write com.apple.dt.Xcode IDEBuildOperationMaxNumberOfConcurrentCompileTasks 6

80 個の Swift ファイルを持つ SwiftUI プロジェクトを実測。16 GB RAM の M4 ノードで Clean Build は約 4 分 12 秒、swap 圧力なし。

コード署名とキーチェーン:Archive パッケージングの全工程

コード署名は iOS CI/CD フローで最もエラーが起きやすい工程。GUI なし CI 環境では、デフォルトの macOS Keychain の挙動が通常の開発環境と異なり、キーチェーンを明示的に管理する必要がある。

2 つの主流署名方式の比較

方式 適用シーン メリット デメリット
p12 証明書を手動インポート 小規模チーム向け単一マシン CI 設定が簡単、外部依存なし 証明書ローテーションは手動再インポートが必要
fastlane match チーム協業 / 複数 CI ノード 証明書を統一暗号化保存、自動ローテーション Git リポジトリまたは S3 ストレージバックエンドが必要

手動 p12 方式:一時キーチェーンを作成

CI 環境で最も安定した方法は、各 job で一時キーチェーンを作成し、ビルド完了後に削除。残留資格情報を回避:

# Create a temporary keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security set-keychain-settings -t 3600 -u build.keychain

# Import signing certificate
security import "$CERTIFICATE_P12_PATH" \
  -k build.keychain \
  -P "$P12_PASSWORD" \
  -T /usr/bin/codesign \
  -T /usr/bin/xcodebuild

# Allow xcodebuild to access the key without UI prompt
security set-key-partition-list \
  -S apple-tool:,apple: \
  -s -k "$KEYCHAIN_PASSWORD" build.keychain

KEYCHAIN_PASSWORDP12_PASSWORD など機密変数は GitHub Repository Secrets に保存し、${{ secrets.KEYCHAIN_PASSWORD }} で参照。YAML にハードコード厳禁。

Archive を実行して IPA をエクスポート

完全な Archive → Export フローは 2 段階:xcodebuild archive.xcarchive 生成、-exportArchive で IPA エクスポート。

# Step 1: Archive
xcodebuild archive \
  -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -sdk iphoneos \
  -archivePath ./build/MyApp.xcarchive \
  CODE_SIGN_IDENTITY="Apple Distribution: Your Name (XXXXXXXX)" \
  DEVELOPMENT_TEAM="XXXXXXXX"

# Step 2: Export IPA
xcodebuild -exportArchive \
  -archivePath ./build/MyApp.xcarchive \
  -exportOptionsPlist ExportOptions.plist \
  -exportPath ./build/

ExportOptions.plist は Export ステップの重要設定ファイル。methodapp-store / ad-hoc)、teamIDsigningStyle フィールドが必要。Xcode GUI で手動 Export し、生成された一時ディレクトリからテンプレートとして取得可能。

fastlane で TestFlight へ自動アップロード

IPA パッケージ後、最後のステップは App Store Connect の TestFlight チャネルへプッシュ。fastlane の pilotupload_to_testflight)が最も安定。App Store Connect API Key 認証対応、Apple ID パスワード不要。

fastlane をインストール

Bundler で fastlane バージョンを管理することを推奨。グローバルバージョン競合を回避:

# In project root, create Gemfile
source "https://rubygems.org"
gem "fastlane"

その後 bundle install を実行。以降の fastlane コマンドは bundle exec fastlane ... で呼び出し。

App Store Connect API Key を設定

App Store Connect → Users and AccessIntegrationsApp Store Connect API で API Key 作成、.p8 ファイルをダウンロード、Key ID と Issuer ID を記録。

GitHub Secrets に以下の変数を設定:

  • ASC_API_KEY_ID:API Key の ID
  • ASC_API_ISSUER_ID:Issuer ID
  • ASC_API_KEY_CONTENT.p8 ファイルの Base64 エンコード内容

Fastfile 設定例

lane :beta do
  api_key = app_store_connect_api_key(
    key_id: ENV["ASC_API_KEY_ID"],
    issuer_id: ENV["ASC_API_ISSUER_ID"],
    key_content: Base64.decode64(ENV["ASC_API_KEY_CONTENT"])
  )

  upload_to_testflight(
    api_key: api_key,
    ipa: "./build/MyApp.ipa",
    skip_waiting_for_build_processing: true
  )
end

GitHub Actions YAML から呼び出し:

- name: Upload to TestFlight
  env:
    ASC_API_KEY_ID: ${{ secrets.ASC_API_KEY_ID }}
    ASC_API_ISSUER_ID: ${{ secrets.ASC_API_ISSUER_ID }}
    ASC_API_KEY_CONTENT: ${{ secrets.ASC_API_KEY_CONTENT }}
  run: bundle exec fastlane beta
高速化のコツ:App Store 処理待ちをスキップ

skip_waiting_for_build_processing: true で fastlane はアップロード完了後即座に返却、App Store Connect の IPA 処理待ちなし(通常 10–30 分)。後続ステップが処理結果に依存しない場合(Slack 通知など)、CI 総時間を大幅短縮。

キーチェーンのよくあるエラー集中トラブルシュート

コード署名のエラーメッセージは曖昧なことが多い。以下は CI ヘッドレス環境で最も頻出するエラーとその根本原因・解決策。

エラーメッセージ 根本原因 解決策
errSecItemNotFound 証明書が現在アクティブなキーチェーンにインポートされていない、または一時キーチェーンが GC された security default-keychain -s build.keychain 実行を確認。archive ステップ前に security unlock-keychain を追加
could not find signing certificate for "Apple Distribution" 証明書 Identity 名と Xcode プロジェクトの CODE_SIGN_IDENTITY が不一致 security find-identity -v -p codesigning build.keychain を実行し、完全な Identity 文字列を確認してコピー&ペースト
User interaction is not allowed キーチェーンがロックされており、codesign が UI 認可ダイアログを表示する必要がある(ヘッドレス環境では表示不可) security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" build.keychain を追加し、codesign が UI なしで秘密鍵にアクセス可能に
Provisioning profile doesn't include the entitlement プロビジョニングプロファイルとプロジェクト Entitlements が不一致(Push Notifications、App Groups など) Apple Developer でプロビジョニングプロファイルを再生成し、全 Capability にチェック、再ダウンロードしてインストール
No signing certificate "iOS Distribution" found プロビジョニングプロファイルと証明書タイプが不一致(Distribution vs Development) ExportOptions.plistmethod フィールドを確認(app-store は Distribution 証明書が必要)

デバッグのコツ:ビルドログで完全な署名コマンドを確認

xcodebuild 後に | xcpretty -r json-compilation-database を追加、または xcpretty パイプを外して生ログを確認。CodeSign キーワード検索で実際の署名コマンドと引数を確認。Xcode GUI エラーパネルより情報量が多い。

もう一つの一般的なデバッグコマンド:

codesign -dv --verbose=4 ./build/MyApp.xcarchive/Products/Applications/MyApp.app

.app 内の署名情報を直接確認し、証明書チェーンが完全か検証。

Jenkins Agent 比較:移行とトレードオフ分析

チームに Jenkins インフラがある、または会社のセキュリティポリシーで GitHub にコードをプッシュできない場合、Mac 上の Jenkins は一般的な代替案。両者の核心的な差はいくつかの観点に現れる。

観点 GitHub Actions セルフホスト Runner Jenkins Agent (macOS)
設定ハードル 低、5 分以内で登録完了 では、先に Jenkins master(通常 Linux/Docker)を構築する必要あり
コードリポジトリ連携 GitHub ネイティブ、PR チェック状態を自動反映 GitHub Branch Source プラグインの設定が必要
マルチプラットフォーム混在 同一 workflow で macOS / Linux / Windows を混在可能 Label ルーティングが必要、設定がやや煩雑
パイプライン可視化 GitHub Actions ネイティブ UI、直感的 Blue Ocean プラグインは見やすいが、自行メンテナンスが必要
シークレット管理 GitHub Secrets + OIDC Jenkins Credentials、Vault 連携可能
オフライン/イントラネットビルド 非対応(GitHub へのアクセスが必要) 対応、強コンプライアンス向け
ハードウェア要件 オンラインの macOS マシン(Runner ホスト)が必要 オンラインの macOS マシン(Jenkins Agent ホスト)が必要

移行観点では、元 Jenkins パイプラインの sh 'xcodebuild ...' ステップを GitHub Actions YAML の run: フィールドへ移行はほぼ 1 対 1 対応。最大の差はトリガー条件構文並行制御:Jenkins の when { branch ... } は GitHub Actions の on: push: branches: に対応;Jenkins の lockable-resources プラグインは GitHub Actions の concurrency: グループ構文に対応。

両方式の共通前提:常時オンラインで固定 macOS バージョンの物理 Mac が Agent/Runner ホストとして必要。このマシンがパイプライン安定性の基盤——過熱やバージョン漂移があれば CI は予測不能に失敗する。

多くの中小チームの実際のジレンマは方式選択ではなく:CI を長期稼働できる物理 Mac がない。オフィス用 MacBook はメモリ 8 GB 程度、大規模プロジェクト编译時に放熱降速、継続 CI 負荷下で体験が悪い。新規 Mac mini 調達コストに設置・電力・メンテナンスも加わり、初期投資も低くない。

クラウド専用 Mac:専用物理サーバーがない場合の固定ビルド方案

上記のジレンマに対し、オンデマンドで専用クラウド Mac を借りるのは真剣に検討する価値がある選択肢——初期ハードウェア投資不要で、専用の固定環境 macOS ビルドノードを得られる。

本文で使用する VPSRox Mac mini M4 ノードの例:16 GB 統合メモリ + 256 GB NVMe SSD 標準構成、1 Gbps 専用帯域、ノード日単位 $21.8 から、支払い後 1–5 分で自動納品、契約ロックなし。

CI/CD の観点では、常時オンラインで算力専有の Mac mini を借りるのと同等。できることはローカル専用物理サーバーと変わらない:

  • 任意バージョン Xcode をインストール(xcodes ツールで管理)、ビルド環境を完全固定
  • GitHub Actions セルフホスト Runner または Jenkins Agent として登録、本文の全手順を直接適用可能
  • M4 の 10 コア CPU と 38 TOPS Neural Engine により、Core ML モデルコンパイルを含むプロジェクトでより良い性能
  • Thunderbolt 5 並列拡張で複数 Mac mini をプライベートビルドクラスタに(大規模チーム向け)

GitHub ホスト Runner との比較:日単位レンタルは高頻度ビルド(1 日 30 回超)で macOS Runner 超過課金より安いことが多い。Mac mini 自購との比較:初期調達予算不要、プロジェクト段階に応じてレンタル期間調整(スプリント期に増機、リリース後に減機)。

5 つのグローバルノード(シンガポール、日本東京、韓国ソウル、中国香港、米国東部)からチームに最も近い位置を選択し、git fetch と依存ダウンロードのレイテンシを低減、全体ビルド時間をさらに短縮。

1 台多用:CI/CD + リモート開発デスクトップ

クラウド Mac ノードは CI 専用ではない。ブラウザ VNC や SSH でリモート開発デスクトップとして同時利用可能。ローカル Mac なしで Xcode デバッグ、Instruments 分析、シミュレータテスト——単一ノードの利用率が大幅向上し、日単位課金の単位コストを分散。

専用物理サーバー専有 · 1–5 分で開通

この CI/CD パイプラインを稼働させる

本文の全ステップは VPSRox 専用 Mac mini M4 ノードで検証済み。ノード開通 → SSH 接続 → 本文の手順に従い、ゼロから TestFlight 自動アップロードまで、最短当日完了。日単位レンタル、契約不要。

標準構成
チップApple M4 · 38 TOPS
CPU10 コア(4P + 6E)
メモリ16 GB 統合メモリ
ネットワーク1 Gbps 専用帯域
SLA99.9% 可用性
納品1–5 分で自動開通