Xcode、コード署名、Apple Siliconに依存する継続的なビルドでは、実機のMacをセルフホストRunnerとして運用する価値があります。本記事では、登録、タグによる振り分け、Xcode固定、署名情報の隔離、サービス化、障害時の確認、本番投入前の検収までを時間軸に沿って説明します。
ビルドが待機し続ける、署名鍵を置く場所がない、再起動後にMacがRunnerへ戻らない――この状態なら、登録だけで本番運用へ進めてはいけません。
Xcode、コード署名、Apple Siliconを使う安定した高頻度ワークフローなら、実機のMacをGitHub Actions macOS セルフホストRunnerとして構築する価値があります。反対に、たまにビルドするだけで固定環境も不要なら、ホスト型Runnerのほうが保守負担を抑えやすいです。
この手順は、WindowsまたはLinuxを主力機としてiOS開発を行う開発者、Xcodeのバージョンや署名情報を管理するDevOps担当者、Mac miniの購入と周期レンタルを比較している小規模チームを対象にしています。
動かす前に、実機Macが必要かを判定する
次の条件に該当するほど、セルフホストRunner向きです。
- Xcodeを使ったビルド、シミュレーター、アーカイブが継続的に発生する
- Appleのコード署名、証明書、プロビジョニングプロファイルを管理する必要がある
- Apple Silicon向けの依存関係やネイティブバイナリを検証する
- XcodeやmacOSの組み合わせを固定し、同じ環境で再現性を確保したい
- キューの待機時間よりも、専用ノードを維持する運用コストを許容できる
一方、週に数回だけ実行するテストや、Xcodeを必要としない一般的なスクリプトであれば、専用Macの電源状態、OS更新、ディスク、Runnerの監視まで負担する合理性は薄くなります。特に、外部コントリビューターのコードを実行する公開リポジトリでは、秘密情報を保持する自前ノードを無条件に使えません。
GitHubも、セルフホストRunnerではワークフローコードがホストへアクセスできる可能性を警告しています。公開リポジトリや信頼できないプルリクエストを署名用Runnerから分離する設計は、登録作業より先に決めておくべき安全境界です。GitHub公式のアクセス管理と安全上の注意を確認してください。
最初の時間でMacを専用ノードにする
日常作業用の管理者アカウントを、そのままRunnerプロセスに使う構成は避けます。専用のmacOSユーザー、専用の作業ディレクトリ、必要最小限の権限を用意し、署名を担当するノードと通常のテストノードを分けられる状態にします。
登録前の準備
- macOSのバージョンとCPUアーキテクチャを記録する
- Xcode、Homebrew、Git、必要なSDKの導入状態を確認する
- Runner専用ユーザーのホームディレクトリと作業場所を決める
- 着信接続、SSH、管理コンソールへのアクセス経路を限定する
- 署名鍵をまだ配置せず、まず署名なしのジョブを通す
GitHubのリポジトリまたは組織の設定画面から、セルフホストRunner追加用の一時トークンを発行します。トークンをソースコード、シェル履歴、チャットへ貼り付けず、対象のmacOSとプロセッサアーキテクチャに一致するRunnerパッケージを選択します。登録コマンドの最新版は、GitHub公式のRunner追加手順と公式Runnerリポジトリで確認してください。
ルーティング用ラベルを先に設計する
標準ラベルとしてself-hosted、macOS、ARM64を付け、さらにios-buildやsigningのような用途ラベルを追加します。Apple Siliconのノードへ限定したい場合は、ワークフロー側で必要なラベルをすべて指定します。
jobs:
build:
runs-on: [self-hosted, macOS, ARM64, ios-build]
steps:
- uses: actions/checkout@v4
- name: 環境を確認
run: |
sw_vers
uname -m
xcodebuild -version
ラベルは「速いノード」を選ぶための性能設定ではなく、ジョブを実行できるRunnerを絞り込む条件です。ラベルの組み合わせに一致するノードがなければ、ジョブは待機したままになります。GitHubのラベルとルーティング仕様と、Runnerの状態やラベルを扱う公式リファレンスを照合してください。
最初のジョブは「検出・ビルド」だけに絞る
いきなり証明書、キャッシュ、アーカイブ、成果物保存をすべて追加すると、失敗原因が分かりません。最初はコード取得、シェル実行、環境情報の出力、署名なしビルドだけに限定します。
name: macOS runner smoke test
on:
workflow_dispatch:
jobs:
smoke:
runs-on: [self-hosted, macOS, ARM64, ios-build]
steps:
- uses: actions/checkout@v4
- name: ツールチェーン確認
run: |
xcode-select -p
xcodebuild -version
swift --version
- name: 署名なしビルド
run: |
xcodebuild \
-project Sample.xcodeproj \
-scheme Sample \
-configuration Debug \
CODE_SIGNING_ALLOWED=NO \
build
この段階で確認するのは、GitHub上でRunnerがオンラインになっていること、ジョブが意図したタグへ到達したこと、チェックアウトとShellが動くことです。ジョブ終了後には作業ディレクトリを確認し、設定ファイル、アクセストークン、署名関連ファイルが残っていない状態にします。
actions/checkoutのバージョンやプロジェクト名はリポジトリの実装に合わせて変更してください。上記はXcodeプロジェクトを対象にした例であり、Swift Packageやワークスペースではコマンドを置き換えます。
最初の日にXcode、署名、キャッシュを固定する
Xcode 26を採用する場合でも、ノードのmacOSが対応条件を満たすと経験だけで判断してはいけません。Xcode 26とmacOSの組み合わせは、Apple公式のXcodeシステム要件にある対応表を確認し、安定版とテスト版を明確に分けます。公式テスト版を本番の固定条件として扱わないことも重要です。
Xcodeの選択は、複数のインストール先を明示する構成にします。
sudo xcode-select --switch /Applications/Xcode.app
xcodebuild -version
実際のパスは導入したXcode名に合わせて変更し、ジョブの冒頭でxcodebuild -versionを記録します。依存関係については、Swift Packageの解決ファイルや各種ロックファイルを変更しない限り、同じ入力から同じ依存関係を復元できるようにします。
署名が必要なステップだけでキーチェーンを一時的に解除し、証明書とプロファイルを環境変数へ無期限に残さない構成にします。公開プルリクエスト、外部ブランチ、未確認のスクリプトを、署名情報のあるRunnerで実行してはいけません。署名用Runnerを専用グループへ入れ、アクセス可能なリポジトリとワークフローを限定します。
キャッシュは、依存関係キャッシュ、ビルド成果物、DerivedData、本地の一時残留物を分けて扱います。キャッシュキーにはロックファイル、macOS、Xcode、アーキテクチャの変化を反映させ、ツールチェーンを更新したのに古い生成物を再利用する状態を避けます。
中盤の構成を比較して、用途を固定する
| 構成 | 向いているワークフロー | 運用上の利点 | 先に確認する制約 |
|---|---|---|---|
| ホスト型Runner | 短時間の一般ビルド、固定環境が不要な検証 | ノードのOS更新やサービス監視を自分で持たずに済みます | Xcode、署名情報、Apple Silicon依存の条件を細かく固定しにくい場合があります |
| 署名なしの自前Mac Runner | テスト、無署名ビルド、専用SDKの検証 | 機密情報を置かずに実機環境を再現できます | ノードの稼働状態、ディスク、キューを管理する必要があります |
| 署名用の専用Mac Runner | App Store提出用アーカイブ、内部配布、署名付きCI | 証明書を通常ジョブから分離できます | 公開コードを実行しないルール、Runnerグループ、鍵の消去手順が必須です |
| Apple Siliconの自前Mac Runner | ARM64向けビルド、Apple Siliconでの実機相当検証 | ネイティブ依存関係の差異を早期に検出できます | ラベル、Xcode、macOS、依存関係の組み合わせを固定して管理します |
高頻度で安定したMac CI/CDを回すなら、署名なしノードと署名用ノードを分離する構成が現実的です。反対に、単発のアーカイブだけなら、専用ノードを常時維持するより、必要な期間だけ実機環境を用意するほうが管理項目を減らせます。
最初の週にサービス化と監視を終える
Runnerをログイン中の画面に依存させると、再起動、ログアウト、停電復旧のあとにジョブが拾われません。RunnerディレクトリでGitHub公式のサービス導入手順を実行し、macOSのlaunchdによって起動されることを確認します。
導入後は、次の順で復旧試験を行います。
- [ ] GitHub上でRunnerがオンラインになっている
- [ ] macOSを再起動してもRunnerサービスが起動する
- [ ]
launchctlで対象サービスの状態を確認できる - [ ] Runnerの診断ログに登録失敗や認証失敗がない
- [ ] 短い検証ジョブを実行し、再起動後も同じラベルで到達する
- [ ] 署名用Runnerへ通常の公開プルリクエストが到達しない
- [ ] ジョブ後に秘密情報と一時生成物が残っていない
- [ ] ディスク空き容量、通信、待機時間、失敗ログを確認できる
Runnerの自動更新は、適用後にXcodeや依存関係の挙動を確認できる保守窓口と組み合わせます。macOSとXcodeの更新を同日に自動適用すると、Runner更新、SDK変更、署名環境のどれが原因か追跡しにくくなるため、変更を分けて記録します。利用中のRunnerのリリース状況は、actions/runnerの公式Releasesで確認できます。
上線前に実タスクで検収する
本番投入前は、サンプルの無署名ビルドだけで合格にしません。実際のリポジトリで、依存関係の初回取得、キャッシュ復元、コンパイル、テスト、アーカイブ、成果物の保存、再起動後の復帰までを順番に実行します。
記録する項目は、利用したMacのCPUアーキテクチャ、macOS、Xcode、依存関係のロックファイル、Runnerラベル、署名の有無、キャッシュのヒット状況、失敗時のログです。所要時間は環境やプロジェクト規模で変わるため、他社のベンチマークを自環境の基準にせず、同じノードで冷起動とキャッシュ復元を分けて測定します。
判定は次の三つに分けると、導入後の判断が明確になります。
- 合格:指定ラベルへ確実に到達し、署名境界、再起動復旧、ログ収集、作業領域の消去を確認できる
- 要改善:ビルドは成功するが、キャッシュ無効化、キュー監視、サービス復旧、秘密情報の消去に未整備がある
- 不適合:公開コードが署名用ノードへ到達する、XcodeとmacOSの対応条件を満たせない、障害時に復旧経路がない
自前Macの長期運用では、ハードウェア購入費だけでなく、OS更新、Xcodeの共存、ディスク整理、証明書更新、障害対応の担当時間も発生します。購入前の比較では、Mac mini購入とMacレンタルの費用検討を参照し、必要な稼働期間と保守担当の有無を分けて見積もると判断しやすくなります。
よくある確認事項
FAQでは、登録先がリポジトリか組織か、タグの一致条件、Apple Siliconのラベル、launchdの復旧、署名用Runnerのアクセス範囲を個別に確認します。Runnerがオフラインの場合は、再登録より先にサービス状態、通信、ディスク、権限、ラベルを順番に切り分けます。
本番用Macをまだ用意していない場合は、日本向けMac環境の利用条件を確認し、必要なXcodeとApple Silicon条件に合う実機で検収を行います。現在のLinuxまたはWindows環境だけで進める方法は、Xcode専用ツールチェーン、コード署名、Apple Silicon依存の検証を再現しにくく、公開PRと本番鍵の分離も別途設計しなければなりません。購入して物理機を保守するほど長期安定負荷がないなら、必要な期間だけnuvcloudのMacをレンタルしてRunnerを構築するほうが、環境準備と回収の負担を抑えやすい選択です。
macOSセルフホストRunnerに、専有M4 Mac miniという選択を
nuvcloudなら、専有ベアメタルのM4 Mac miniで、コード署名や継続的なビルドに適した安定したmacOS環境を構築できます。
専有IPv4と1Gbps接続を備え、SSHとVNCの બંનેのアクセス方式で運用や保守を柔軟に行えます。