← 開発日記に戻る

Mac M4 CI はいつ分割すべき?同一ホストから二ノード構成への判断と移行手順(2026)

OpenClaw · 2026.06.23 · 約 11 分

Mac M4 CI ビルドノードと OpenClaw Gateway 二ノード構成

6 月初、Xcode CI と OpenClaw Gateway を同一のカナダ M4 に詰め込み、launchd の Nice=-5 と並列コンパイル制限で 2 週間凌いだ。3 週目から、業務チームが IM で「Gateway がまた重い」と文句を言い始める——ビルドログは正常、curl ヘルスチェックだけがピーク時に 50ms から 400ms 超へ漂う。並列数を下げ、DerivedData を掃除、一時的に 24GB プランへ上げても、問題は「1 日 2 回」から「1 日 1 回」に減っただけだった。

これは設定ミスではなく、同一ホストのリソースモデルが天井に達したサインだ。ポートは衝突しない(20300 vs 18789)、CPU コアも足りる。本当に争うのはユニファイドメモリと swap。本稿は 同一ホスト配置と launchd チューニング の次の段階——いつ二ノードに分けるか、トポロジの描き方、Channels を壊さず切り替える移行手順。公式のメモリ・プロセス挙動は Apple の Xcode ビルドキャッシュドキュメント、Tailscale 組網は Tailscale インストールガイド を参照。

結論先行:分岐点はリソース分離であり、「もう 1 台買う」ことではない。

  • 4 つのハードシグナル、1 つでも該当なら分割

    ビルド ≥50 回/日、並列 ≥3 本、Gateway がエンドユーザー向け、または週内 swap Critical ≥3 回——同一ホストで Nice をいじり続けるのは先延ばし。

    ≥50 回/日

  • 最小二ノード:ビルド機 + Gateway 専用機

    ビルドノードは 24GB+ と大容量 SSD;Gateway ノードは 16GB で常駐 ~500MB 十分。2 台の M4 を Tailscale で内網接続し、公開は必要な入口だけ。

    16GB Gateway 専用

  • 移行の核心:状態と DNS、再インストールではない

    設定ディレクトリを rsync、token 再利用、Tailscale MagicDNS で切替。ビルド機は止めず、Gateway はブルー/グリーン 15 分以内。

    ブルー/グリーン ≤15分

1. なぜ同一ホスト構成が「突然足りなくなる」のか

多くのチームの最初のクラウド Mac は 3 役:xcodebuild、OpenClaw Gateway 18789、たまに VNC でキーチェーン操作。初期負荷が低いと 16GB は余裕に見える。ブランチ増加、UI テスト並列、Channels が社内試験から本番サービスへ——メモリ曲線が「のこぎり」から「台地」へ。ビルド終了後 10 分も compressed ページが 8GB 超、Gateway の heap が swap に押し出される。

同一ホスト最適化(並列低下、Nice 引き上げ、キャッシュ掃除)はピーク重複確率を下げるだけで、ピーク自体は消せない。時間軸で 2 つのピークがほぼ必ず重なる——例:APAC 昼のビルド、北米夜の IM ピーク——なら、パラメータ調整ではなくスケジューラへの賭けになる。Apple Silicon のユニファイドメモリに独立 VRAM バッファはなく、Xcode と Node.js Gateway は同一物理プールを奪い合う。memory_pressure が Warn に入ると、ユーザーには遅延ジッターが体感され、CI にはタイムアウトと署名ステップ失敗が散発する。

分割の本質は「スケール神話」ではなく、圧縮不能なピークを分離すること:ビルドピークはビルドノードだけに、Gateway 常駐メモリは xcsbuildd に永遠に奪われない。GitHub Actions セルフホスト macOS Runner をクラウド Mac に載せる 記事の「専用 Runner にデスクトップを混ぜない」と同じ論理で、ここでは Gateway と CI を分ける。

2. 3 種のトポロジ分類:同一ホスト、二ノード、三ノード

先に分類してから選定——いきなり「2 台追加」は避ける:

  • T0 同一ホスト共存:1 台の M4 で Xcode Server / セルフホスト Runner + Gateway。日次ビルド <30、Gateway 社内のみ、偶発遅延許容向け。
  • T1 二ノード(本稿の主役):ノード A が CI 専任(24GB+、大 SSD);ノード B が Gateway 専任(16GB で可)。Tailscale または DC 内網で Channels / Dashboard は B、ビルドトリガーは A。
  • T2 三ノード:T1 に「署名/アップロード専用機」または「並列テスト専用機」を追加。日次ビルド >150、TestFlight アップロードとコンパイルのハード分離が必要なときのみ;多くの中小チームは T1 で十分。

非対称結論を再掲:問題は M4 の性能不足ではなく、SLA の異なる 2 サービスを同一メモリプールに縛ったこと。 Gateway は 99.9% の安定応答;CI はスループット。同一ホストは 1 つの SLA で 2 目標を妥協している。

T1 二ノード:ビルド機 + Gateway 専用機 ノード A · CI ビルド機 M4 24GB+ · 1TB SSD xcodebuild / Runner DerivedData ローカル :20300 Xcode Server ノード B · Gateway 専用機 M4 16GB · 256GB OpenClaw Gateway Channels / Dashboard :18789 安定低遅延 Tailscale <5ms エンジニア SSH / CI トリガー → A;IM / モバイル / Agent → B
二ノード最小モデル:ビルドピークと Gateway SLA の物理分離

3. 同一ホスト vs 二ノード vs スペックアップ:比較の仕方

Mac M4 CI 拡張パス比較(2026)
観点 同一ホスト調整継続 Nice / 並列低下 単機 32GB へ メモリ増、トポロジ不変 二ノードへ分割 CI + Gateway 分機
根本原因ピーク重複の緩和メモリ上限の引き上げ2 種 SLA の分離
Gateway 遅延ビルドに連動してジッター改善するが消えないビルド中も <100ms 維持可
月額(概算)最低中(アップグレード差額)中(+16GB 小型機)
運用複雑度中(+1 台、Tailscale)
向く段階日次ビルド <30並列 2 本、社内 Gateway≥50 回/日または対外 Gateway
分割トリガーシグナルチェックリスト(1 つでも該当なら T1 推奨)
シグナル 閾値 観測方法 誤検知の除外
ビルド頻度≥50 回/日CI ログ / Runner カウント手動ローカル Archive は除外
並列本数≥3 本フルビルドxcodebuild -jobs とキュー深度軽量 lint は 1 本に数えない
Gateway 利用者エンドユーザー / 7×24 Channelsプロダクト SLA 要件純社内 webhook は猶予可
メモリ圧力週内 Critical ≥3 回memory_pressure ログ一回性リークは先に調査
ディスク競合月間成果物 >50GB かつ I/O wait 高df -h + iostatarchive 掃除後に再判定
スペックアップは分割の代替にならない
32GB 同一ホストは「並列 2 本 + Gateway 社内試験」向き。Gateway が対外なら、メモリ増はジッターを 1 日 3 回から 1 回へ減らすだけ——ユーザーは依然「また重い」と感じる。

4. シナリオ別の選び方:意思決定マトリクス

  • 2 人チーム、日次ビルド <20、Gateway 自用のみ:T0 のまま、同一ホスト launchd チューニング で十分。
  • APAC でビルドトリガー、Gateway が IM ユーザー向け:即 T1。Follow-the-sun ではピークがほぼ必ず重なり、同一ホストは負ける。
  • GitHub Actions クラウド Runner あり、Gateway 立ち上げ直後:Runner は A、Gateway は B;Runner 機に 18789 を載せない。
  • TestFlight アップロードとコンパイルがディスクを奪い合う:まず T1;まだ足りなければ T2 で署名/upload 専用機。TestFlight 専記事を参照し、本稿と混同しない。
  • 予算が 1 台のみ:Gateway SLA を優先、ビルドは夜間バッチか並列低下——妥協であり長期アーキテクチャではない。

5. 推奨スタック(重ね合わせ可)

  1. 最小二ノードスタック:Hashvps カナダ M4 24GB(A、CI)+ M4 16GB(B、Gateway)+ Tailscale tailnet + openclaw doctor 週次。T0 から上げる大多数のチーム向け。
  2. CI ハイブリッドスタック:A にセルフホスト Runner で GitHub Actions;B に Gateway + Channels。編成は GitHub、実行面は macOS、Gateway はビルドピークを背負わない。2027 macOS ビルド市場の変化 の「環境主権」と同方向。
  3. 可観測スタック:B に Gateway 遅延プローブ常駐(curl 5 秒間隔)+ A のビルド終了 hook で memory_pressure スナップショット;2 週間のデータで分割 ROI を経営層に示せる。

6. 移行前のよくある誤解

  • ビルドを止めてから Gateway 移行:ビルド停止コストが高い;Gateway をブルー/グリーン、ビルドは継続。
  • 新機を再インストールのみで rsync しない~/.openclaw、token、Channels ペアリング喪失で全員再ログイン。
  • 公網で 18789 を 2 IP 同時公開:切替期は Tailscale または内網 DNS;2 Gateway が同時に Channels を受けない。
  • ビルド機で Gateway ディレクトリを早く削除:ロールバック窓では旧機 Gateway プロセスを残し、DNS だけ切替。
  • 時刻と証明書の軽視:2 台の NTP ずれ >30s で token 検証が散発失敗;移行日は先に sudo sntp -sS time.apple.com

7. 実装手順:7 ステップで二ノード移行

以下 Runbook の前提:旧機 mac-ci-01 で CI+Gateway 同居;新規 mac-gw-02(16GB)を Gateway 専用に購入。Tailscale 済み(OpenClaw 日常運用 Runbook 参照)。

ステップ 1:ベースラインスナップショット(移行日前日)

旧機で Gateway 遅延 P50/P95、ビルド回数、memory_pressure 分布を記録し分割後と比較。openclaw status と Channels 一覧のスクリーンショットを保存。

bash — ベースライン:Gateway 遅延とメモリ圧力
# 延迟采样 60 次
for i in $(seq 1 60); do
  curl -o /dev/null -s -w "%{time_total}\n" http://127.0.0.1:18789/health
  sleep 5
done | sort -n | awk '{a[NR]=$1} END{print "p50="a[int(NR*0.5)],"p95="a[int(NR*0.95)]}'

memory_pressure
vm_stat | head -8

ステップ 2:新機初期化と Tailscale 参加

mac-gw-02 で macOS 更新、Homebrew、Node、Tailscale;mac-ci-01 との相互 ping <5ms を確認。新機で xcodebuild は走らせない。

ステップ 3:rsync で Gateway 状態(メンテナンス窓開始)

bash — 旧機から Gateway 専用機へ OpenClaw 設定を同期
# 在原机 mac-ci-01 执行;先停 Gateway 避免写入分裂
sudo launchctl unload /Library/LaunchDaemons/com.openclaw.gateway.plist

rsync -avz --delete \
  ~/.openclaw/ \
  builder@mac-gw-02.tailnet-abc.ts.net:~/.openclaw/

# 同步 launchd plist
scp /Library/LaunchDaemons/com.openclaw.gateway.plist \
  builder@mac-gw-02.tailnet-abc.ts.net:/tmp/

ステップ 4:新機で Gateway 起動とローカル検収

bash — mac-gw-02 でサービス読み込みとヘルスチェック
sudo cp /tmp/com.openclaw.gateway.plist /Library/LaunchDaemons/
sudo launchctl load /Library/LaunchDaemons/com.openclaw.gateway.plist

openclaw doctor
curl -s http://127.0.0.1:18789/health
sudo lsof -iTCP:18789 -sTCP:LISTEN

ステップ 5:切替——Tailscale MagicDNS またはリバースプロキシ

チームが使う Gateway ホスト名(例 gateway.tailnet-abc.ts.net)を新機へ;モバイルと Channels 設定を新 MagicDNS 名へ。切替中は旧機で Gateway を再起動しない

ステップ 6:ビルド機の負荷軽減

Channels と Dashboard が新機で正常なら、旧機から Gateway launchd をアンロードし CI 用メモリを解放。並列コンパイルを 5–6(24GB 機)に戻せる。

bash — 旧ビルド機から Gateway 削除、CI 並列を復元
# mac-ci-01:确认已无流量打到 18789 后
sudo launchctl unload /Library/LaunchDaemons/com.openclaw.gateway.plist
sudo mv /Library/LaunchDaemons/com.openclaw.gateway.plist \
        /Library/LaunchDaemons/com.openclaw.gateway.plist.bak

defaults write com.apple.dt.Xcode \
  IDEBuildOperationMaxNumberOfConcurrentCompileTasks 6

ステップ 7:48 時間観察とロールバック手順

旧機の .openclaw バックアップと plist.bak を 7 日保持。新機 Gateway P95 >200ms または Channels 切断なら DNS を旧機へ戻し launchctl load——CI キューは触らない。新 Gateway セットアップは OpenClaw リモート Mac 導入 と照合。

8. FAQ

Q1. 16GB 1 台だけのとき、「論理ロール」分割で 2 台目を買わずに済む?

物理分割の代替にはならない。 時間帯ずらし(夜間ビルド、昼 Gateway)は可能だが、Follow-the-sun や 7×24 Channels では再びピーク衝突する。論理分割の価値は「Gateway を移したら遅延が戻るか」を検証し、調達に 2 台目の必要性を示すこと。

Q2. 二ノードに Tailscale は必須?

必須ではないが強く推奨。 同一クラウド内網、WireGuard 自前、SSH トンネルも可;Tailscale の強みは MagicDNS、ACL、低運用。Hashvps カナダ M4 2 台が同リージョンなら内網 RTT は通常 <2ms、Gateway から A 機のビルド webhook を叩くのに十分。

Q3. 二ノードは単機 32GB よりどれくらい高い?

プラン次第だが、しばしば「24GB ビルド機 + 16GB 小型機」vs「単機 32GB」に近い。 重要なのは絶対差額ではなく Gateway SLA の証明可能性——対外サービスチームはダウンタイムで計算し、月額だけ見ない。

Q4. GitHub Actions ホスト Runner があれば Mac 自前は不要?

環境主権次第。 ホスト macOS は分課金で波峰向き;固定日次ビルド >50 で鍵と DerivedData を握るならクラウド Mac 自前。Gateway は独立ノード推奨、Runner ホストかどうかは無関係。

Q5. 移行失敗時の最速ロールバックは?

DNS を戻す + 旧機で launchctl load。 ロールバック日に大規模ビルドは走らせない;先に Gateway health と 1 本の Channel メッセージを確認してから CI を開放。状態ディレクトリは新指標が安定するまで二重保持。

9. まとめ

Mac M4 CI の分割は失敗ではなく、同一ホスト最適化が成功したあとの自然な次段階——ビルドと Gateway を同時に必要と証明したが、物理的にはもう 1 枚のメモリに押し込むべきではない。4 つのハードシグナル、T1 二ノードで SLA 分離、7 ステップ Runbook でブルー/グリーン——分岐点はリソース分離であり、台数ではない。

「Gateway がまた重いがビルドは止められない」窓にいるなら、Nice をいじり続けるより 16GB Gateway 専用機を足す方が根治に近い。ビルドは 24GB クラウドで走らせ、Agent とユーザーは別機で安定した 18789——2026 年の小チームが負担できる「準本番」トポロジだ。

二ノード分割は、2 台のクラウド Mac mini から

Xcode CI と OpenClaw Gateway を分機すると、ビルド機は 24GB と大 SSD で DerivedData を背負い、Gateway 機は 16GB で 7×24 低遅延稼働で足りる。Hashvps カナダ M4 ベアメタル、専用 IPv4、SSH/VNC 即利用、同リージョン 2 台で低遅延組網——T1 二ノードの出発点として、単機 32GB 強化より swap ジッターを分離しやすい。

同一ホストから二ノードへの移行を計画中なら、 Hashvps クラウド Mac mini M4 はコスパの良い 2 台目の起点—— プランを見る 、Gateway と CI をそれぞれの居場所へ。

Hashvps · Mac クラウド

ビルド機と Gateway を分離して安定運用

24GB CI + 16GB Gateway 専用機、ベアメタル macOS、専用 IP、Tailscale 対応。

プランを見る
期間限定