2026年 越境チームの「インタラクティブ開発」と自己ホスト macOS Runner の同区共プール:マルチリージョン物理 Mac でキュー飢餓とリソース争奪をどう避ける?——地域ノード選定とセッション/CI 区分しきい値の意思決定マトリクス(コピペ可能なパラメータと FAQ)
複数地域の物理 Macを同一リージョンの予算プールに載せると、低遅延のインタラクティブセッションと高スループットのCIを同時に満たす必要があります。区分しきい値がないと Runner キュー、コンパイルと索引のディスク争奪、あるタイムゾーンだけスロットが常に後回しになる問題が起きます。本記事では三枚のマトリクス(負荷×プーリング戦略、地域アフィニティ、セッション/CI のしきい値)、コピペ可能なラベルとワークフロー断片、七ステップの Runbook、引用用の数値、FAQ をまとめます。マルチリージョンの Git checkout 尾部は 越境 CI の partial clone/blobless/フルクローン意思決定、Trunk/Merge Queue との相互作用は マルチリージョン物理 Mac のオーケストレーション記事 と併読すると整理しやすいです。
はじめに:プーリングと「同一 OS インスタンスの共有」は別物
同リージョンのプーリングは調達・監視・コストが一つの FinOps セルに収まる話です。同一 OS 上で Remote IDE と CI を詰め込むと、I/O とメモリの障害領域が一つにまとまり、Apple Silicon で NVMe 書き込み増幅が重いワークロードでは特に危険です。本稿は「同時に押さないでください」ではなく、オーケストレータのキュー、Runner ラベル、ホストあたりの並列上限で衝突を吸収する前提です。
読み終えたあとに手元にあるもの:① 負荷タイプとプーリング方針の結論、② 地域をまたいだ Git/成果物の近接と開発者 RTT のトレード、③ コピペ可能な Runner ラベルとワークフロー上のガード、④ 七ステップの展開と FAQ です。
1. 三つの痛点:飢餓の正体は「Mac が足りない」だけではない
- 二層のキュー。 GitHub Actions などは並列スロットまたはオンラインで
runs-onに合う Runner の有無のどちらかで詰まります。オフライン・誤タグ・不一致は偽の飢餓を生み、紙上は余裕でもジョブだけ滞留します。 - インタラクティブと CI は同じキャッシュを奪い合う。 リモート IDE の索引、シミュレータ、
xcodebuildによる Derived Data 書き込みが重なると NVMe 遅延が跳ね、CI の壁時計と SSH の応答の両方を悪化させます。 - タイムゾーン間の公平性。 地域やチーム単位の
concurrencyと重いジョブの時間帯設計がないと、一地域のプッシュ嵐がグローバルスロットを占有し、GHz の問題ではなくスケジューリングの問題になります。
2. マトリクス A:ワークロード種別×プーリング戦略
どのワークロードを同一物理機に載せてよいか、どれを別プールまたは別ホストに分けるかを決めます。
| ワークロード | 典型的なボトルネック | 推奨プール戦略 |
|---|---|---|
| Remote SSH/IDE | 常時セッション、安定 CPU、遅延敏感 | pool:interactive。CI とはボリューム分離。ユーザーあたり同時セッション上限 |
| PR ビルド+テスト | メモリスパイク、ディスク書き込み、シミュレータ | pool:ci-standard。ホストあたり max_jobs=1–2 から開始 |
| リリース/署名/アップロード | 秘密の所在、ネットワーク尾部、コンプライアンス | pool:release。日常 CI から分離。必要ならシングルテナント Mac |
| UI/E2E/スナップショット | GPU、ディスプレイサーバ、フレーク感受性 | 専用 Runner と固定解像度。コンパイル専用ジョブと混ぜない |
3. マトリクス B:マルチリージョンのアフィニティとノード選定
Git に合わせると開発者に合わせるはしばしば衝突します。下表を一次のトレードとして使います。
| 主なアライン先 | 最も得をする側 | 典型コスト |
|---|---|---|
| Git/成果物/依存ミラー | CI の clone、キャッシュ復元、成果物取得 | リモート開発者の RTT は上がりがち。地域別インタラクティブノードが別途必要 |
| 毎日コードを書くエンジニア(マクロリージョン単位) | Remote SSH、レビュー、ペアリング | CI は読み取りレプリカや同期スケジュールが要る場合。マージ窓を本拠リージョンに合わせる |
| コンプライアンス/管轄 | 署名、PII、監査ログ | Runner を越境ジョブに安易に載せられない。environment と承認を明示 |
実務ルール: 地理ごとに少なくとも zone:<region> ラベルを出し、夜間フルスイートなどグローバルな重いジョブは pool:heavy と専用の concurrency グループへ回し、地域の PR プールを飢餓させないようにします。
4. マトリクス C:セッション/CI 区分のしきい値(出発点——負荷試験で調整)
| 指標/方針 | 推奨の初期しきい値 | こう見えたら調整 |
|---|---|---|
| 物理 Mac あたりの並列 CI ジョブ | ユニファイドメモリ M シリーズでは 1。安定実証後にのみ 2 を試す | OOM、SIGKILL、コンパイルのフレーク、シミュレータクラッシュ増 |
| リポジトリ単位のワークフロー concurrency | PR は concurrency: group + cancel-in-progress。地域あたり並列ワークフローは目安 ≤4 |
キュー P95 > 15 分でスロットが空=ラベル。満杯=台数か並列を見直し |
| インタラクティブと CI のディスクレイアウト | 別 APFS ボリュームまたはマウント。Derived Data のパス接頭辞を強制 | ネットは健全なのに SSH が重い。diskutil で書き込み遅延スパイク |
| 公平性(マルチタイムゾーン) | team/region ラベルでキューを分割。重いジョブは時間帯制御 |
常に特定リージョンだけが後回し。concurrency グループとブランチ保護を監査 |
5. コピペ可能なパラメータ(Runner ラベル+ワークフロー骨格)
GitHub Actions 系の命名例です。利用中の CI のラベル、concurrency グループ、自己ホスト Runner 設定に読み替えてください。
5.1 Runner に登録するラベル
zone:apac
pool:ci-standard
os:macos
arch:arm64
capacity:shared
5.2 ワークフロー:プール選択+ concurrency(抜粋)
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: [self-hosted, macOS, ARM64, zone-apac, pool-ci-standard]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
5.3 環境変数(挙動用。秘密情報ではない)
# 例:CI でインデクサ負荷を抑える
export COMPILER_INDEX_STORE_ENABLE=NO
# Derived Data を CI 専用ボリュームへ
export DERIVED_DATA_PATH=/Volumes/ci-derived/PR-${{ github.run_id }}
署名用の秘密は共有プールのデフォルトに載せず、スコープされた environment かリリース専用 Runner に閉じます。
6. 七ステップ実装 Runbook
- 負荷のヒートマップ化: リポジトリとブランチごとに、日次ジョブ数、ピーク時間帯、所要時間をチャート化する。
- ラベル文法の凍結:
zone/pool/capacityを RFC に文書化し、私用エイリアスを禁止する。 - インタラクティブと CI の分割: 最低でもボリューム分離。インタラクティブノードは CI ラベルを外してもよい。
- concurrency グループと timeout: PR とデフォルトブランチでグループを分け、長尺タスクは別ワークフローとより長い
timeout-minutesを付ける。 - 四週間の観測: キュー P95、Runner オフライン率、ジョブ失敗率、エンジニア RTT をアラートに載せる。
- 四半期スケール: 1 台のスペックアップより、地域内スロットを増やす方を優先する。
- ロールバックの文書化: ラベル巻き戻し、ワークフロー kill switch、緊急リリース用ホスト引き継ぎのオンコールを明記する。
7. 引用用数値とチェックリスト(SLO と調達向け)
- 並列の出発点: 本番プールではホストあたり CI ジョブ 1。週次で見直してから 2 を試す。
- キューアラート: 地域の待ち時間P95 > 15 分が三連続インターバルで発火したら容量レビュー。
- インタラクティブ RTT: 主要な Remote SSH 経路で片道 < 120 msを目安(許容は組織で調整)。これを超えるなら、CI 用 Mac を増やす前に近いサンドボックスを足す。
- 四半期監査: 実機とラベルを突合し、退役ホストがワークフローに残らないようにする。
8. FAQ
同じリージョンのプーリングは、Remote SSH と CI を同一物理 Mac に載せる必要がありますか?
いいえ。プーリングは地域と FinOps の境界です。本番では interactive と ci のサブプール(必要ならさらに分割)を使い、同一ホストで Xcode とコンパイルがユニファイドメモリとディスク I/O を奪い合わないようにします。
キュー飢餓のとき、最初に何を見ますか?
オーケストレーションのキュー深度、Runner スロット利用率、インタラクティブの RTT/切断を同時に。キューが深いのにスロットが空いているのは、だいたいラベルのずれかオフライン Runner です。
区分マトリクスで「ホストあたり最大並列ジョブ数」はどう選びますか?
まず 1 ジョブでピークメモリと Derived Data サイズを検証し、2 を試す。OOM、コンパイルのフレーク、シミュレータの不安定化が出たら戻す。ユニファイドメモリでは、紙のコア数より並列を絞る方が勝つことが多いです。
マルチリージョン:Runner は Git のリージョンに合わせるべき? 開発者のリージョンに合わせるべき?
CI は通常 Git・成果物・ミラーに追随。インタラクティブな Remote SSH は毎日打鍵するエンジニアに追随。衝突するときはラベルとプールで分割し、無理に共有ホストに詰めません。
大容量 RAM の 1 台でマルチホスト区分を代替できますか?
メモリは助けになりますが、ディスク書き込み争奪とシミュレータのフレークはインタラクティブと CI を同一障害領域に結びつけます。厳格なラベル付きで水平に Mac を増やす方が、限界まで載せた単一タワーに勝ちがちです。
自己ホスト Runner がフラップするとき、偽の飢餓を止めるには?
Runner プロセスを自動再起動で監督し、ハートビートを監視し、重要プールにN+1 の冗長を確保。ジョブが溜まっているのにオンライン Runner がゼロなら、並列を上げる前に可用性を直します。
Merge Queue/トランク圧力とはどう相互作用しますか?
Merge Queue はデフォルトブランチに負荷を集中させます。merge-group 用に別プールまたは時間帯を用意し、既存のトランク方針と並列度を揃えて PR プールが飢餓しないようにします。
9. 区分されたプールを Mac mini クラスのハードで回す
Runner ラベル、ボリューム分離、常時ハートビートは、Apple Silicon の Mac mini のようなホスト上でこそ運用しやすいです。アイドル時の消費電力が低く、冷却が静かで、CI のバーストに対するメモリ帯域が読みやすい。macOS は OpenSSH、Git、Xcode 系ツールチェーンをネイティブで揃えられ、WSL のようなギャップがありません。長期稼働の Runner に自動化資格情報を載せるなら、Gatekeeper、SIP、FileVault もマルウェア面を抑えます。
分散チーム向けに地域別の物理 Mac プールを張るなら、オーケストレータの concurrency とホスト上限を揃えた方が、GHz だけ追うより P95 が安定しやすいです。Mac mini M4 は前払いコスト、効率、無人稼働の安定性のバランスが良く、本文のマトリクスを信頼できるハードに載せ替えたい場合は、下の CTA から ZoneMac を確認してください。
自己ホスト Runner とインタラクティブを安定運用したいですか?
ZoneMac の物理 Mac クラウドは、ラベル設計した macOS Runner プールと Remote SSH の両方に使えます。