← 開発日記に戻る

人はシンガポール、コードはクラウド:短期出張の Xcode リモートビルド Runbook

出張メモ · 2026.06.03 · 約 9 分

シンガポール出張中、軽量ノートから SSH でクラウド Mac 上の Xcode ビルドを実行する構成

本稿が答える問いは一つだけ:短期間シンガポールにいる間、手元は軽量ノートだけで、72 時間以内に「コード修正 → リモートコンパイル → TestFlight」まで完走できるか?Mac Studio を預け入れなくてよいか?

前提(以降すべてここに立脚): すでに常時オンライン・Xcode 版固定・出口 IP が予測可能な macOS build node があること。同僚の Mac を借りる一時利用でも、CI が毎回コールドスタートする空機でもない。Runbook が扱うのは「現地からどう起動するか」であり、安定した build node がなければ、どんなに良い SSH チェックリストも崩れる。

以下のタイムラインは、当チームの 2025-11-13~11-15(シンガポール時間) の hotfix 実録です。識別子はマスク済み。ログは当時の端末と GitHub Actions の原文抜粋で、自環境との照合用です。

出発前に揃える 3 点:

  • まず安定 build node

    固定 IP、Xcode 版固定、match は単一書き込み。出張はトリガーのみ、現地で環境構築しない。

    commit + run ID を記録

  • ノードは「成果物の出口」に合わせる

    APAC 内測だけならシンガポール優先。北米 ASC・固定出口 IP はカナダ build 機のまま。

    対照表を参照

  • VNC で一日コードを書かない

    越洋・ホテル回線では画面共有は SSH より脆い。VNC はキーチェーン操作のみ。

    SSH 優先

現地(SG) ローミング / ホテル Wi‑Fi git · ssh 軽量ノート · SwiftUI 大規模編集は非推奨 Internet クラウド Mac mini M4 SG または CA DC xcodebuild · match Derived Data 常駐 TestFlight ASC API コンパイルはホテル NAT を通らず、アップロードは build 機の固定出口から
出張地は編集とトリガーのみ。重いコンパイルとアップロードはクラウド Mac で完結

照合可能な時間アンカー(2025-11 出張実録抜粋)

リリース成功日、チケットに以下のフィールドを固定記録しました。自チームの Runbook でも同様に残さないと、後から「遅いのは回線かコンパイルか」を切り分けられません:

1 回の完走に必要なキーフィールド(機密情報マスク済み)
フィールド 今回の記録値 取得方法
Git commit7f2a91cmaingit rev-parse --short HEAD
GitHub ActionsRun #18472930156 · workflow ios-ship.ymlActions UI → run URL
build 機 Xcode16.2 (16C5032a) · Selected SDK iphoneos18.2xcodebuild -version + build log 先頭
手元ノート Xcode16.2(build 機と一致)同上、出発 T-48h で揃える
Archive 所要11m 34s(クラウド M4 24GB)log 末尾 ** ARCHIVE SUCCEEDED ** 前の時刻差
同 commit 手元 Air Clean Build38m 12s(1 回失敗後に再実行)ローカル対照、クラウド編成の根拠
TestFlight 処理アップロード 4m 08s · ASC「処理中」約 22maltool / API 応答 + ASC メール時刻
build 機出口203.0.xxx.xxx(カナダ機、変更なし)build 機で curl -4 ifconfig.me
build 機 archive ログ抜粋(2025-11-14 23:41 SGT トリガー)
Build description signature: 7f2a91c7e3b2…
ExecuteExternalTool …/Xcode.app/Contents/Developer/Toolchains/…
** CLEAN SUCCEEDED **
** ARCHIVE SUCCEEDED ** [684.123 sec]   ← 約 11m 24s(clean 含む)
note: Using codesigning identity: Apple Distribution: Acme *** (TEAMID)

当日夜、シンガポールでスマホテザリングから SSH トリガー。コンパイルとアップロードのログはすべて build 機上。ノートには Actions run リンクと commit のみ。self-hosted runner 利用時は run ID を PR 説明に必ず書く——クラウド Mac セルフホスト runner の記録習慣と同じです。

Runbook が依存する build node とは?(出発前に選定)

出張週に現地で「Mac を借りられるか」を比較するのが最も怖い。当時却下した案と採用案を表にまとめました——製品名は最終列の実装例に過ぎず、結論そのものではありません

出張 iOS リモートビルド:4 種の算力源と「専用クラウド Mac」だけが残った理由
方式 出張週に不向きな理由 それでも必要な特性
Xcode Cloudmatch 秘密鍵・カスタム Fastlane・固定出口 IP を完全自控しにくい。トラブルシュートがブラックボックスPR チェックと併用可。hotfix 署名チェーンは自前 node が要る
AWS EC2 Mac最低 24h 契約、クォータとリージョン調整。出口 IP はデフォルト可変実 macOS ハード。AWS コンプライアンス体制があるチーム向け
共有/ローテ Mac クラウドキーチェーンと Derived Data 残留。証明書串線リスク低価格。署名なし純コンパイルのみ
オフィス Mac mini同僚のシャットダウン、OS 更新、ディスク交換無人完全自控だが出張中 7×24 は保証不能
専用クラウド Mac(当方採用)事前起動・版固定・IP ホワイトリストが必要SSH + 固定出口 + キーチェーン単一機。SG/CA 分 DC

当時、APAC 日中の SSH は シンガポール DC の M4(仕様は シンガポール拠点ページ)、TestFlight アップロードはカナダ機のまま——ASC API ホワイトリストと match 秘密鍵がカナダ出口 203.0.xxx.xxx に既に紐づいていたため。ベンダー変更は可能だが、出張週は出口変更禁止。Hashvps を選んだ理由は、更新しても IP が変わらず、ベアメタル mini で VM ラッパーではない点——1 台 1 IP の要件と一致。既に EC2 Mac やオフィス mini があるなら「固定 IP + 版固定」さえ満たせば、以下 Runbook はそのまま使えます。

先に切り分け:「回線」か「算力」か

シンガポール到着後すぐ「現地 Mac レンタル」を探す人が多いですが、iOS コンパイルと XCTest だけならクラウド Mac の契約地と自分がいる都市は無関係。チャンギから DC への SSH は上海発と本質的に同じ。現地で本当に揃えるべきは:

  • 安定した上り: ローミング eSIM か信頼できるテザリングで SSH を切らさない(GSMA の eSIM 解説。デュアル SIM ならデータ SIM と音声 SIM を分離可)。
  • タイムゾーン協調: 国内チームとの standup、Code Review 窓。ビルドには影響しないが push タイミングには影響する。
  • コンプライアンス出口: App Store Connect と企業プロキシのホワイトリストが見るのはbuild 機の出口 IP。ホテル客室 IP ではない。

算力側:出発前にリポジトリ clone 済み・証明書 import 済み・Derived Data パス固定の build 機を用意。着地後は git pull とトリガースクリプトのみ。空港で Xcode インストールを始めない——72 時間をコンポーネント DL に使うことになる。

72 時間タイムライン(実タイムスタンプ付き)

T-48h · 2025-11-11 上海: カナダ build 機で archive + TestFlight 完走(commit 9e0b44f、Run #18451002201 成功)。両機 xcodebuild -version は 16.2。SSH 公開鍵を authorized_keys に、ノート ~/.ssh/configServerAliveInterval 60

T-24h · 2025-11-12: ローミング開通。mosh build-ca を 10 分連続で切断なし。match 秘密鍵がカナダ機のみであることを確認(TestFlight 専用機)。

T+0 · 2025-11-13 19:10 SGT チャンギ: ホテル Wi‑Fi で初回 SSH 失敗(下記障害 ①)。テザリングに切替後 git pull + build 成功、4m 02s(増分、archive ではない)。

T+24h · 2025-11-14: 日中ミーティング。20:15 SGT に 7f2a91c を push。23:41 SGT archive トリガー → 翌 00:03 SGT ASC アップロード → 00:25 SGT TestFlight テスト可。PC 前にいなくても build 機と Actions が完走。

T+48h~72h: 顧客デモは処理済み TestFlight ビルド。展示会 Wi‑Fi で現場 Archive はしない。アップロードは App Store Connect API 経由で、ノートのローミングとは無関係。

シンガポール拠点 vs カナダ拠点:出張時の選び方

リージョン詳細は 5 拠点リモート Mac 選定。出張では 2 点だけ覚える:

短期シンガポール滞在時、build 機を置く場所
比較項目 シンガポール / APAC DC 現地編集向け カナダ / 北米 DC 北米出口の成果物
SSH 体感RTT 低、ログ追従が快越洋 150~250ms、十分(コンパイルはリモート)
TestFlight / ASC可。出口 IP ホワイトリスト要確認多くのチームで match / API が北米 IP に紐づく
向くタスク内測ビルド、APAC 協調、日中イテレーション本番リリース、公証、北米 CDN 依存取得
出張で機替え要否不要。同一 repo に複数機ロールタグ可不要。SG 機と「編/送」分離も可

当時シンガポール到着を理由に match を移さなかった:SG 機は debug/内測のみ、カナダ機が upload 継続。証明書移行は変更イベント——出張週は禁止(コンパイルのクラウドオフロード と役割分担が同型で、地理が逆転しただけ)。

接続チェックリスト:ローミング、ホテル Wi‑Fi、SSH

ホテル回線の典型問題:UDP 禁止、5 分アイドル切断、同一セグメント ARP 問題で SSH リセット。最低構成:

  • ノート + スマホ二系統:SSH はテザリング、ビデオ会議はホテル Wi‑Fi で帯域競合回避。
  • ServerAliveInterval 60 + ServerAliveCountMax 3~/.ssh/config に。
  • 長時間タスクは tmux または screen。切断後 tmux attach でログ再開。
  • 不安定回線で rsync DerivedData 禁止——Git のみ同期(オフロード記事と同じ教訓)。
出張週にやらないこと
build 機出口 IP 変更、Xcode メジャーアップ、match リポジトリ再構築、VNC で Storyboard 編集。いずれも顧客ミーティング外の専用窓に回す。

出張 2 日目の実障害記録(ログ付き)

以下 3 件はすべて 2025-11-14 同一時間帯、発生順。想定ではなく当時の端末原文(パスはマスク)。

① ホテル Wi‑Fi:SSH アイドル切断

ノート端末 · T+0 当夜
$ ssh build-sg 'cd ~/workspace/MyApp && git pull'
client_loop: send disconnect: Broken pipe
Connection to build-sg.xxx port 22: Broken pipe

原因: ホテル NAT がアイドル TCP を約 300s で切断。対処: テザリング + ServerAliveInterval 60。長時間タスクは tmux。以降同種は再発せず。

② Archive 失敗:キーチェーンに Distribution 証明書なし

カナダ build 機 · 初回 archive 失敗
error: No signing certificate "iOS Distribution" found
error: No profiles for 'com.acme.myapp' were found
** ARCHIVE FAILED **

原因: 前週、同僚が VNC で「ログイン」方式で証明書を入れたが login keychain に distribution を import していなかった。手元ノートは Xcode 自動管理で通るがクラウドは match 同期キーチェーンのみ——典型的な環境ドリフト。

対処: カナダ機で bundle exec fastlane match appstore --readonlysecurity find-identity -p codesigning -vApple Distribution を確認。archive 再実行成功(上記 11m 34s)。

③ 並列テスト:Simulator runtime と Xcode マイナー不一致

夜間 XCTest · 失敗ログ
xcodebuild: error: Unable to find a destination matching the provided destination specifier:
		{ platform:iOS Simulator, OS:18.1, name:iPhone 16 }
	Ineligible destinations: … missing matching iOS Simulator runtime

原因: build 機が先週 Xcode 16.2(18.2 runtime)に上がったが workflow は OS:18.1 のまま。対処: ios-ship.yml の destination を 18.2 に、.xcode-version を repo にコミット——Derived Data 削除では直らない。

④ Derived Data「壊れたように見える」:実はディスク満杯

同日やや早い増分 build
error: unable to attach DB: error: accessing build database
  "/Users/builder/Cache/DerivedData/…/build.db": database or disk is full

対処: df -h/ 残 6.2GB。旧 .xcarchive と 1 週間前ブランチの DerivedData を削除して復旧。「cache corrupt」でもディスク満杯なら、水位確認後に rm -rf DerivedData

失敗パターンマトリクス(ナレッジブロック検索用)

出張リモート iOS ビルド:問題 → 場面 → クラウド原因 → 対処
問題 発生場面 クラウド / リモート原因 対処
SSH 断線ホテル Wi‑FiNAT idle timeoutテザリング + ServerAlive + tmux/mosh
build 成功・アップロード失敗ASC / 企業プロキシ出口 IP 未ホワイトリストbuild 機 IP 固定。出張週に機替えしない
local OK / remote failarchive / 署名キーチェーン vs match ドリフトmatch readonly + find-identity 検収
Simulator 不在CI 夜間テストSDK / runtime 未 lock.xcode-version + destination 更新
build.db / cache エラー並列マルチブランチディスク満杯が corrupt 偽装df -h → archive と旧 DerivedData 削除
署名期限切れ四半期末リリースDistribution 証明書失効14 日前ローテ。出張週は readonly match のみ

リモート Xcode 最小ループ(コマンド)

着地当晚、「72 時間で完走できるか」をこの 1 本で検証——パラメータは TN2339 参照。commit 7f2a91c にバインド:

build 機ワンショット pull & build(抜粋)
ssh build-sg 'set -e
  cd ~/workspace/MyApp
  git fetch origin && git checkout 7f2a91c && git pull --ff-only
  xcodebuild -scheme MyApp -configuration Release \
    -derivedDataPath ~/Cache/DerivedData \
    -destination "generic/platform=iOS" \
    build 2>&1 | tee /tmp/build-7f2a91c.log'

Archive とアップロードは Fastlane lane に。シンガポールでは make ship COMMIT=7f2a91c のみ実行。Actions Run #18472930156 が記録。build 機は self-hosted runner 兼用。

スペックとディスク:出張週にいきなり降格しない

M4 build 機の水位(出張シナリオ)
構成 メモリ圧 ディスク 推奨
16GB / 256GB並列テストで Swap しやすい1 週間で満杯の可能性hotfix 単一 repo のみ
24GB / 512GB多くの iOS repo で十分週次 Archives 清掃要出張デフォルト
24GB / 1TB余裕マルチブランチキャッシュ可monorepo + 複数 Simulator

荷物に入れるもの(チェックリスト)

出張バッグは意図的に軽量化:持たない 16 インチ MacBook Pro、持つ Terminal が動くノート、Lightning/USB-C 実機、予備充電器、有効化済みローミング eSIM QR の紙/オフライン PDF。build 機アカウント・API Key・match パスワードは 1Password チーム庫だが、オフライン緊急袋には build 機 IP、SSH ポート、on-call 電話——「ローミング不通 + 2FA SMS 届かず」の二重ロック回避。

顧客デモは TestFlight インストール済みまたは Ad Hoc。展示会 Wi‑Fi で現場 Archive しない。デモとリリースは別経路:デモはコンシューマ回線、リリースは build 機固定出口。混同すると「デモは入るがアップロード拒否」の錯覚。

1 週間出張の隠れコスト(経営向け)

Mac mini を買って預ける/現地レンタルには、賃料以外に通関、電源、OS 再セットアップ、証明書 import、チームのデバイス再信頼がある。専用 build node の週次更新はすぐ使える運用環境の対価——Derived Data、match、固定 IP を出張週に再構築しない。スタートアップ Mac オフィス TCO と同型:出張週は CapEx を OpEx に置き換え、証明書を個人ノートに散らさない。

見落とされがちな機会費用:ホテル回線でローカルビルド 1 時間は顧客ミーティング 1 枠失う。コンパイルをクラウドに載せれば会議合間に push、部屋に戻ってログ確認。年に東南アジア 3~4 回飛ぶ身として、安定 build 機は「現地で Mac を買う」より予測可能。

FAQ

Mac 必須? Git と SSH が動くノートで可(Windows も可。Windows + クラウド Mac 選定記事参照)。実機デバッグ必須ならテスト端末を携行。コンパイルはクラウド。

出張 3 日目に build 機を新規契約間に合う? 間に合うが、証明書 import と初回フルビルドは国内で完了。着地後は増分のみ。

シンガポール DC と「人が SG」は同区必須? 必須ではない。同区は SSH RTT 低減。北米ストア公開はカナダ build 機で可。

ローミング流量で IPA 送れる? 送るべきでない。IPA は build 機から ASC 直送。ノートは数 MB の Git オブジェクトのみ。

「コンパイルをクラウドへ」と重複? あちらはノートのもたつき。本稿は地理移動 + 回線不確実下の Runbook とノード選定。

OpenClaw / Agent も移す? 不要。Gateway は既存カナダ機継続。シンガポールでは SSH でビルドトリガーのみ。

会社 VPN 常時必須? ポリシー次第。VPN が全流量を乗っ取り SSH 不安定なら「分割」申請:社内のみ VPN、build 機 SSH は直結。Tailscale で build 機のみ接続しホテル Wi‑Fi 平文区間を避けるチームも多い。

時差とリリース窓? シンガポール UTC+8、米西と約 15~16 時間差。米東昼の審査なら SG 午後に archive、カナダ build 機で深夜自動 upload——太陽に追従する北米バッチ のシフトと両立。出張者が徹夜で upload を見なくてよい。

文中 commit / Run ID は照合可? 内部 repo 実録。ドメインと IP はマスク。同じフィールド形式を自チームチケットに残せばよく、数値一致は不要。

まとめ:依存チェーン → 当方の実装

本 Runbook の依存順:安定 build node → 固定出口と match → 出張は SSH/CI トリガーのみ → ログと commit/run ID 記録。2025-11 は専用 M4 2 台(SG 編、CA 送)で充足。同等環境があればベンダー変更不要。

build node をゼロから組み、ベアメタル macOS・更新時 IP 不変・SG/CA 分 DC を重視するなら、 シンガポール拠点料金ページ を実装参考に——出口ホワイトリストを先に揃えてから航空券。

Hashvps · Mac クラウド

iOS build node をゼロから?

M4 ベアメタル、専用 IP、SSH 即利用——出張時の一時レンタルではなく、本文の長期 build 機向け。

プランを見る
期間限定