2026年独占リモート Mac の iOS/macOS CI:Bazel(rules_xcodeproj/Tulsi)とネイティブ xcodebuild はどう選ぶ?——リモートキャッシュ、Worker トポロジ、SSH ヘッドレス排障と運用コストの再現可能な意思決定マトリクス+FAQ
「どのビルドグラフを正とするか」を趣味論ではなく、runbook に書ける制約として整理します。独占リモート Mac上で非対話の SSH、シングルテナントまたは固定プール前提なら、Bazel(rules_xcodeproj/レガシーの Tulsi)とネイティブ xcodebuild を、リモートキャッシュ・Worker トポロジ・排障・運用コストの軸で並べ、下のマトリクスと FAQ をプラットフォーム ADR に貼れる形にします。壁時計の土台づくりは
xcodebuild のタイミング要約と XCLogParser
と合わせると、キャッシュヒット率の変動で期待値がぶれにくくなります。同一ホストで GitHub/GitLab の Webhook 受け口と重いビルドを同居させる場合は
共有シークレットとゲートウェイ経路のレート設計(401/413/タイムアウト FAQ)
も参照し、CI 入口のペーシングがコンパイル I/O やリモートキャッシュ帯域を奪わないようにしてください。
1. 独占ノードがツールチェーン選択を増幅する理由
ホステッド Runner のキューやマシンドリフトはグラフ差をかくします。独占リモート Macでは同一の Xcode ビルド、キーチェーン方針、DerivedData/Bazel 出力ルートが固定されるため、主な緊張軸は キャッシュヒット率 と 増分の正当性 です。
2. Bazel(rules_xcodeproj/Tulsi)とネイティブ xcodebuild — 能力マトリクス
前提:iOS/macOS アプリ+単体テスト+アーカイブ、Runner は Apple Silicon Mac。
| 観点 | Bazel + rules_xcodeproj(Tulsi は移行表層) | ネイティブ xcodebuild(xcworkspace/SPM/CocoaPods) |
|---|---|---|
| ビルドグラフ | 宣言的 Starlark。rules_apple/rules_swift が背骨。Tulsi は歴史的 Xcodeproj ブリッジが中心 |
Xcode が pbxproj/SPM を解釈し、IDE に最も近い挙動 |
| リモートキャッシュ | HTTP/gRPC のリモートキャッシュが第一級。アクション再現性と資格情報の統治が前提 | クラスタキャッシュは標準なし。DerivedData 再利用・モジュールキャッシュ・独自 rsync/オブジェクトストアに依存 |
| 並列度とサンドボックス | Worker の水平スケールに向く。サンドボックス方針を締めやすい | -parallelizeTargets・スキーム・コア数で頭打ち |
| SSH ヘッドレス適合 | BAZELISK_BASE_URL・出力ルート・Xcode 選択を固定。Simulator は依然ローカル |
Apple 公式ドキュメントと整合。キーチェーン+ xcodebuild ログのエコシステムが成熟 |
| チーム学習コスト | 高め:Starlark・依存グラフ・リモート実行の意味論まで研修が要る | 低〜中:多くの iOS チームが Fastlane/シェルで既にラップしている |
3. リモートキャッシュ — ヒット率・シークレット・ライフサイクル
Bazel:キャッシュキーの前提は 再現可能なアクション。コンパイラ版・環境変数・パス写像のドリフトはミスヒットや危険ヒットの原因になります。独占 Mac では Bazel(Bazelisk)と Xcode.app パスを固定し、/var/tmp と出力ルートのディスクを監視。リモートキャッシュは TLS、CI 用の読み取り専用ロールと書き込みメンテ用ロールを分離します。
xcodebuild:勝ちは パスの安定化と予測可能な掃除(DerivedData/Swift module cache)。マシン横断の再利用は git SHA+スキーム等で独自の成果物プロトコルを持ち、コード署名中間成果物の盲信は避けます。
4. Worker トポロジ — 独占 Mac、リモート Worker、ハイブリッド
- すべてローカル独占:Bazel も xcodebuild も可。Bazel はコンパイルとテストをキャッシュ可能なアクショングラフに切り分けやすい。
- リモート Linux Worker + Mac 実行部:RBE でよくある構成。iOS 実機・Simulator は Mac 必須のため「Linux でスケジュールし Mac で署名」の区間が出る — runbook に引き渡しを明記する。
- シングルテナントプール:ツールチェーンはプールごとに一つに寄せる。メジャー Xcode の混在はキャッシュキー基数を爆発させます。
5. SSH ヘッドレス排障チェックリスト(共通)
- ログインセッションとキーチェーン:非対話 SSH ではアンロック方針と
security系エラーがビルドログに出るかを確認。 - xcode-select:複数 Xcode では絶対パスの
xcodebuildかDEVELOPER_DIRの統一。 - ディスクと inode:Bazel 出力ルートと DerivedData は積み上がりが速い。水位アラートと定期 GC を独占ホストに設定。
- Simulator の安定性:ヘッドレスではランタイム版を固定し、同一デバイス集合への並列 UI テスト集中を避ける。
6. Tulsi と rules_xcodeproj — 「運用」とは何か
Tulsi は歴史的パス「Xcodeproj → Bazel ビュー」向け。新規は rules_xcodeproj でローカルデバッグ用 Xcode プロジェクトを生成しつつ、真実は Bazel に置く構成が多い。Bazel を単一の正とするかを決めないと、Xcodeproj を正とし CI だけ Bazel のときに IDE と CI の乖離税が継続します。
7. 再現可能な意思決定マトリクス(短縮版)
| 制約がこうなら… | 寄せる先 |
|---|---|
| 複数リポ/アプリで巨大 Swift コンパイル単位を共有でき、プラットフォーム工数を投下できる | Bazel + リモートキャッシュ/任意で RBE |
| 納期がタイトでチームが小さく、Xcode とピクセル級に揃えたい | xcodebuild + DerivedData/キャッシュ方針の厳格化 |
| CocoaPods の dynamic integration が重く、近期に Bazel 移行の予定がない | まず xcodebuild。Bazel はパイロットモジュールのみ |
| リージョン横断で同一コンパイルが重複し、グローバルな成果物重複排除が欲しい | Bazel リモートキャッシュ(統治込み) |
8. FAQ
Q1:rules_xcodeproj は Tulsi の代替になりますか?
役割が異なります。rules_xcodeproj は Bazel から デバッグ可能な Xcode プロジェクトを生成することに注力。Tulsi は「既存 Xcodeproj → Bazel」でした。真実が Bazel 側にあるか Xcode 側にあるかで置き換え可否が決まります。
Q2:Bazel がなくてもエンタープライズ級のキャッシュは無理ですか?
いいえ — ただしプロトコルとキー空間は自前です。Bazel はキャッシュ単位をアクショングラフとしてモデル化するため、プラットフォーム実装は短く済む一方、学習曲線とルールセット更新があります。
Q3:同一独占 Mac で Bazel と xcodebuild は共存できますか?
はい。ただしユーザー分離かディレクトリ接頭辞で出力ルートとキーチェーンの衝突を避ける。一ジョブ内で無隔離に混ぜると排障コストが超線形になります。
Q4:Simulator テストはどちらが落ち着きますか?
多くのチームでは xcodebuild のドキュメントが豊富です。Bazel 側は rules_apple と Xcode の互換をアップグレード週にスモーク確認してください。
なぜ Apple CI グラフの比較には Mac mini が軸になりやすいか
Bazel でも xcodebuild でも、独占ノードの価値は 環境ノイズを抑えること にあります。Apple Silicon の Mac mini は、Xcode と一体化した macOS ネイティブツールチェーン、Swift のコンパイルとリンクに効くユニファイドメモリ帯域、待機電力が数ワット程度という点で、24 時間温めた Runner に向きます。同価格帯の小型 x86 箱と比べても、長期の電力と冷却では Mac 側が有利になりがちです。SSH 自動化で資格情報を常時オンにする前提では、Gatekeeper・SIP・FileVault によるベースライン硬質化も効きます。
上記のキャッシュキー設計と Worker トポロジの議論を 観測可能な本番金属 の上で「退屈」に保ちたいなら、Mac mini M4 は 2026 年時点でも強い出発点です。プラン比較は下のホームからどうぞ。