2026-04-27 レンタルクラウド Mac(HK / JP / KR / SG / US)における複数 Xcode.app、xcode-select、ジョブ単位 DEVELOPER_DIR の CI マトリクス
リリースとプラットフォームチームが シンガポール などで単一の Apple Silicon Mac mini M4 を App Store 向けに借りつつ、実験ブランチ用の高速レーンも残したいとき、複数の Xcode.app を同居させるのはごく普通の話です。失敗パターンも型にはまっています。10:00 のジョブはサポートシェルで誰かが xcode-select -s したせいで Xcode 16.3 に見えて緑、10:15 のアーカイブは静かに 16.2 を拾い、App Store Connect が将来の SDK 下限不足でバイナリを弾く——という具合です。本稿は 2026-04-27 時点の運用層の記録であり、抽象的な「ツールチェーンを固定せよ」という助言の下に、xcode-select をいつ選ぶか、CI ではなぜ DEVELOPER_DIR だけに頼るべきか、/Applications の命名規則、そして セルフホスト ランナーのラベルを絶対パスへどう写像するかを順に押さえます。関連して Swift 6 厳格並行性 CI、カバレッジと xcresult ゲート、ジョブ単位 DerivedData もあわせて読むと隔離の全体像が揃います。同じホストで OpenClaw のような常駐ゲートウェイを動かしている場合は、姉妹編 LLM API の 429/503 とリトライ予算 と対にすると、ビルド側のドリフトとモデル HTTP の飽和を切り分けやすくなります。
2026 年、1 台のレンタルホストに第 2 の Xcode を載せるのが普通になりつつある理由
Apple のリリース周期とチームのスプリント周期はもはや噛み合いません。iOS 18 向けにリスクを抑えたまま 16.2 系に留まる一方で、別チームは近い将来の 最低 SDK ゲートを先に満たすために 16.3 以降で検証し、組織ポリシーを一括で切り替える前に並行証明を取りたい——という割り当ては珍しくありません。物理ノードは高価なので、東京 や ソウル の共有クラウド Mac に数週間だけ両方を載せるのは自然な経済合理性です。抽象化の単位は「ワークスペースを二重化する」ではなく、1 ハードウェア租約に複数の論理ツールチェーン、そして各 CI ジョブで選択をログに残すことです。YAML の matrix がラベルと環境の写像なしに並んでいるだけなら、それは演劇に過ぎません。加えて、変更管理の観点では「平日昼に誰が既定を切り替えられるか」「メンテナンス枠外で xcodebuild -version を Wiki に貼る義務は誰か」を明文化しておかないと、人が替わった瞬間に暗黙知が蒸発します。
- コンプライアンスの時間窓——Apple が公表する 最低 SDK / Xcode ビルド要件はカレンダーで動きます。本番は固定したまま、並行環境だけ新ラインで受け入れ可能かを示すために第 2 ツールチェーンが要る、という形は 2026 年でも頻出です。
- テストと出荷の分離——統合ブランチは新しい SDK で非推奨警告を洗い、ストアラインは文書化済みの コードサインとエクスポート 手順に留める、という二層運用は エクスポートと App Store Connect API の記事と相性が良いです。
- ビルドファームの経済性——マイナー Xcode のたびにノードを倍にするのは稀にしか正当化できません。規律ある
DEVELOPER_DIR運用なら、NVMe と ユニファイドメモリ を 1 台の 24〜32 GB 筐体で共有しつつ、スケジューリングでピークを避けられます。
セキュリティと監査の双方から見ても、「いつ誰がグローバル既定をどのビルドに切り替えたか」は後から再構成できなければなりません。チケット番号と golden ビルドのツールチェーンフィンガープリントを PR テンプレートに含めるだけで、インシデント後の説明責任が格段に楽になります。
xcode-select か DEVELOPER_DIR か:四列の意思決定枠
どちらも Xcode.app/Contents/Developer を指しますが、爆発半径が違います。xcode-select -switch は人間向けの便宜と捉え、DEVELOPER_DIR=... は自動化におけるプロセス契約と捉えるのが安全です。
| 制御 | 影響範囲 | 典型用途 | 避けたいリスク |
|---|---|---|---|
xcode-select -s /Applications/... |
ユーザセッション全体と、次回起動の一部 GUI ツール | アドホック SSH、VNC での手動アーカイブ | 同一ユーザー上の 2 並列 CI——最後のスイッチが勝つ。Developer シンボリックリンクへの競合書き込み。 |
DEVELOPER_DIR=…/Xcode-16.2.app/Contents/Developer をエクスポート |
そのシェル/plist から派生する子プロセスのみ | GitHub Actions、Buildkite、cron | launchd でエクスポートし忘れ、ログインセッション由来の古い PATH を継承する。 |
スクリプト内の絶対パス(…/usr/bin/xcodebuild) |
単発で明示的 | 環境継承が信用できない診断 | アップグレードで脆い——検証後は DEVELOPER_DIR と素の xcodebuild が保守しやすい。 |
sudo xcode-select を呼んではいけません。本当にグローバル既定が要る(単一テナント M4 では稀)なら、メンテナンス枠 とチケット、事後の xcodebuild -version ログをセットにしてください。ファイルシステム配置:ls /Applications でアクティブが一目で分かるように
アップグレード後も残る命名規則
.xip の展開が終わったその場で Xcode.app を Xcode-16-2-0.app のようにリネームしましょう。一ヶ月後の記憶に頼ると必ず事故ります。バンドル名に空白やアポストロフィを入れることは合法ですが、シェルとモバイル端末からの SSH 入力を面倒にします。ハイフン区切りの断片は、後から DEVELOPER_DIR を打つときのストレスを減らします。.app 拡張子は残し、Developer サブツリーだけを plist なしで symlink しないでください。DTXcode は dSYM とクラッシュ帰属に流れ込みます。チーム内表で「表示名 ↔ ビルド番号」を固定しておくと、口頭の 16.3 とディスク上のパズルが一致しなくなる事故を防げます。
du -sh /Applications/Xcode-*.app は容量のバロメータです。現行のフル Xcode はシミュレータ前でもだいたい 12〜20 GB、第 2 のメジャー iOS プラットフォームで 8〜20 GB 足すことも珍しくありません。1 TB 共有プールでは CI ディスク整理 とセットで、マトリクス行が10 営業日ゼロになってからだけ古いランタイムを削る、というルールがセキュリティレビューでも説明しやすいです。
ラベル駆動 CI マトリクス:1 ランナー、2 つの DEVELOPER_DIR
GitHub Actions のセルフホストラベルでも Buildkite のキューでも、内部の nomad 類似物でも不変条件は同じです。キューラベル(例 xcode-16-2 と xcode-16-3)は xcodebuild 開始前に唯一の環境ブロックへ写像されなければなりません。ルート README に表を置けば、リリースマネージャが誤ったノードで 16.3 を試す事故を減らせます。
| ラベル | DEVELOPER_DIR 先 |
想定利用者 |
|---|---|---|
xcode-stable |
/Applications/Xcode-16-2-0.app/Contents/Developer |
App Store、TestFlight、ホットフィックス、長期 LTS |
xcode-next |
/Applications/Xcode-16-3-0.app/Contents/Developer |
非推奨警告パイロット、Swift 6 段階導入、ノータライズ実験 |
macOS では セルフホストランナー の環境継承が runsvc.sh と対話 ssh で異なるのが常です。DEVELOPER_DIR はランナーが実際に実行するラッパー(例 bash -lc "export …; exec $@")に焼き込み、個人の ~/.zshrc には置かないでください。署名とキーチェーン の謎再発が 1 レーンだけ UI テストで起きたときに初めて気づく、というパターンは本当によくあります。アジア太平洋で夜間オンコールを回すなら、ラベルとヘルスチェックスクリプトを結びつけ、「ラベルはあるがパスが死んでいる」沈黙ドリフトも検知した方がよいでしょう。
8 ステップの手順書:導入、固定、検証、前進
- 展開:
.xipを/Applicationsへ、一意の明示バンドル名で。チケットに.xipのshasum -a 256を残す。 - 初回起動(ライセンス):方針が許せば
sudo xcodebuild -license acceptを自動化し、license サブコマンドで CI が止まらないようにする。 - プラットフォームキャッシュ:そのバンドルに対し、マトリクスが本当に必要とする最小の iOS/tvOS ランタイムだけを
xcodebuild -download…で入れる。GUI の全部入りは避ける。 - 短いスクリプト
/usr/local/bin/mxcode-16-2を書き、DEVELOPER_DIRのエクスポートとxcodebuild -versionの stdout 出力(JSON ログ向け)だけを行う。gist ではなく infra リポジトリへ。 - オーケストレータのラベル をそのスクリプトに結び、既知の golden シミュレータテスト を再実行し
Build versionを過去基線と突き合わせる。 - 署名の突合:
codesignのパスはDEVELOPER_DIRと連動する——署名最適化 チェックを回し、配布アイデンティティがキーチェーン上の同じSHA-1のままか、別の not-valid-before を持つ重複になっていないか確認する。 - トレーサビリティ:TestFlight アップロードに
Build version、ProductVersion、CLANGベンダフラグを IPA 横のci-toolchain.txtに残し、カバレッジと junit アーティファクトの証跡と揃える。 - 退役:ディスク圧力だけを理由に消さない。ラベルを参照する未クローズチケットがゼロになってから。ディスクは ディスク記事 の手順で、深夜の緊急 rm は別ルート。
export DEVELOPER_DIR="/Applications/Xcode-16-2-0.app/Contents/Developer"
/usr/bin/xcodebuild -version
落とし穴、監査、App Store で防御できる説明の仕方
複数 Xcode が同居するとき、毎回のコンパイルで最低限ログに残すべきは三つです。(1) Build version を含む完全な xcodebuild -version、(2) フィルタ後の echo $DEVELOPER_DIR、(3) exportOptions plist の要約ハッシュです。監査人と焦ったリリースマネージャは、ビルド 5421 と 5422 の dSYM UUID がなぜ違うかを後から辿れるべきです。macOS ヘルパのノータライズを行うなら notarytool 実行がコンパイルと同じ DEVELOPER_DIR かも突き合わせてください。16.2 と 16.3 の codesign メタデータが 1 バンドルに混ざると、インシデントコールより長生きするチケットになります。
iPhone 16, OS=18.2 形式の -destination は、ランタイムの増減のたびに再ベースラインが必要です。そうしないと 2 インストール間で同じ名前から UDID への写像が食い違います。FAQ:レンタル Apple Silicon でのマルチツールチェーン
| 質問 | 2026 年の実務的回答 |
|---|---|
2 系統で DerivedData を共有できるか |
本番では避ける。インデックスストアと Swift インタフェースが違う。DerivedData 記事 の隔離を踏襲し、ジョブごとの JOB_ID ルートを二重化する。 |
ホストが CI 専用ならグローバル xcode-select は安全か |
「CI 専用」は稀。人は依然 SSH で再現に入る——グローバル既定は足元の地雷。自動化は DEVELOPER_DIR 優先で、オンコール向けの便宜スイッチは ヘルプ に文書化する。 |
HK / JP / KR / SG / US のベアメタル Mac mini M4 がこのモデルに合う理由
2 系統のフル Xcode 族はメモリと I/O に負荷が集中するパターンです。Swift コンパイラ、インデックスサービス、Metal シェーダキャッシュはすべて同じ ユニファイドメモリ プールを奪い合うため、Apple がこのクラスの筐体に広い帯域を載せる意味がここにあります。仮想化や古い Intel ファームは、第 2 ツールチェーンを NUMA 局所性について嘘をつくハイパーバイザの背後に隠しがちです。香港・東京・ソウル・シンガポール・米国 で借りた Mac mini M4 では、DEVELOPER_DIR の計算は素直です。clang -v が示すものが、SSH や VNC の下のベアメタルで実際に動いているものと一致します。キューが飽和しているなら、単一 24 GB ノードへの並列盛りで「クラウドのバグ」のように見えるメモリ枯渇を招く前に、同一リージョンでもう 1 台を MacXCode の料金ページ から足す方が筋が良いです。ツールチェーンの固定と、出口ネットワークの予測可能性はセットで効いて、同一ベンダ・同一サポート時間帯に揃えると障害切り分けが短くなります。