プラットフォーム/iOS リードがつまずくのは SSH ではなく、専用のリモート Mac上で同一コミットが週やセッションをまたいでドリフトするときです。本稿は再現可能ビルドをXcode フィンガープリント、複数バージョン共存、DerivedData 方針、キーチェーン分離に分解し、比較表・シェル断片・事前チェックリストを示します。ランナー、SSH/VNC、Xcode Cloud 比較の各記事とあわせて読んでください。
「コンパイルできた」は一点の観測です。再現性はツールチェーン状態、依存解決、署名素材の見え方を監査可能なベースラインに固定します。リモートノードでは、プロバイダーイメージ更新、複数利用者の残留物、無人ジョブと対話デバッグの混在といった変数が加わります。
レビューを正直に保つための 6 つの痛点:
フィンガープリントがチャットだけ: xcodebuild -version と swift --version がビルドログに残らず、どのツールチェーンが走ったか証明できない。
xcode-select のドリフト: OS 更新や手動切替でナイトリージョブが別の Xcode を指し、コンパイラと署名の境界挙動が変わる。
DerivedData のクロストーク: ブランチがキャッシュ接頭辞を共有し、増分ビルドが文脈をまたいでマクロ状態を運ぶ。
キーチェーンの見え方の不一致: 同一ホスト上の対話ユーザーと CI ユーザーで署名パスが異なる。SSH は通るがランナーは通らない。
権限ノイズ: TCC ダイアログがヘッドレスジョブを明確なプライバシーエラーではなくタイムアウトで止める。
過剰なクリーンアップ: スクリプトが「キャッシュっぽい」フォルダを削除し、比較不能なコールドビルドを強いる。
2 週間以内に 2 つ以上が再発するなら、パイプラインのステップ 1 でフィンガープリントを記録し、DerivedData とキーチェーン方針を Runbook に書く。これはノード統治であり、CI ベンダー談義ではありません。
マシンを契約上の CI ノードとして扱い、ランタイム同一性(CI ユーザー、ホーム構成、ツールルート、ログパス)を凍結します。ディスク階層は早めに計画:複数 Xcode とシミュレータは CPU 議論より速く肥大化します。
| 次元 | 共有の対話開発マシン | 専用リモート Mac(CI 優先) |
|---|---|---|
| ランタイム同一性 | 個人セッションや GUI 状態と混在しがち | 専用 CI ユーザーを推奨。SSH/ランナーと手動デバッグを分離 |
| ツールチェーン固定 | アップグレードが個人の習慣に従う | 組織承認の Xcode マイナーをピン留め。変更は変更管理で |
| DerivedData | デフォルトパスに複数プロダクトが混ざる | リポジトリまたはパイプラインごとにルート分割。クリーンアップは監査可能に |
| 署名素材 | 証明書がログインキーチェーンに散在 | 別キーチェーン/ユーザーまたはノードで分離。リリースと実験を切り離す |
| 可観測性 | 記憶頼みになりがち | すべてのビルドログ先頭にフィンガープリント用コマンドを出力 |
再現性は「アップグレード禁止」ではなく、「すべてのアップグレードに前後のフィンガープリントとロールバック経路を添える」ことです。
DerivedData は速くする一方でドリフトを隠します。共有は単一メインラインと長寿命ホットキャッシュに合い、隔離は実験ブランチ、ABI 感受性モジュール、リリース週のクリーンビルドに合います。削除論争ではなく方針を文書化してください。
重要パイプラインごとにルートを決める: 例 ~/DerivedData/$REPO/$BRANCH_SAFE。暗黙のデフォルトに頼らない。
明示的に渡す: -derivedDataPath または CI 環境変数を注入。「さっきのデフォルトは何だったか」を残さない。
リリース前にホットとクリーンを比較: 同一コミットは期待帯の範囲でのみ差が出るべき。
クリーンアップを段階化: 「消してよい」と「巨大再取得を強制する」を所有者と頻度で分ける。
ディスク閾値: 空き容量が赤線に触れる前に、保守的な保持かオブジェクトストレージキャッシュへ切り替える。
ランナーラベルと整合: ラベルごとにキャッシュルートを分け、リリースと実験ジョブが衝突しないようにする。ランナー ガイド参照。
# ログヘッダ:ツールチェーン・フィンガープリント(例)
xcodebuild -version
xcode-select -p
swift --version
/usr/bin/xcrun --show-sdk-path --sdk iphoneos
# 明示的 DerivedData(自組織の repo/branch 規約に置き換え)
DERIVED="$HOME/DerivedData/${REPO_SLUG}/${BRANCH_SAFE}"
mkdir -p "$DERIVED"
xcodebuild -scheme "App" -destination 'platform=iOS Simulator,name=iPhone 16' \
-derivedDataPath "$DERIVED" build
ヒント: SwiftPM と Xcode を併用する場合は swift package resolve の出力やロックファイルのハッシュも記録し、「同一グラフ」がリゾルバキャッシュのドリフトを隠さないようにする。
多くのヘッドレス署名失敗は「証明書が悪い」のではなく、キーチェーンの見え方やアンロック方針が無人パスで一度も実行されていないことが原因です。必要最小限とは露出を狭める、対話デバッグをクリティカルパスから外す、リリースを分離することです。
GUI デバッグとランナーが同一ハードを共有する必要がある場合は、ラベルや時間帯で隔離し、一回限りの VNC 承認を文書化する。SSH/VNC チェックリストで VNC 面を絞るのと同じ発想です。
警告: 共有リモートの世界読み取り可能な場所に配布用秘密鍵を置き続けない。別アカウント・別ノード・別キーチェーンファイルを優先し、人員異動時にローテーションする。
以下のレンジは公開ドキュメントと現場の慣行に基づきます。関係者の合意形成に使い、請求と実フットプリントは契約で検証してください。
xcodebuild -version を付けるのはコンパイル時間に対し通常数秒だが、トリアージの回収は大きい。ノート PC や「借り物」の Mac は短期的なコスト削減になる一方、スリープ方針、アップデート促し、混在セッションでフィンガープリントとキーチェーン統制が崩れます。Linux VPS 上のネスト macOS は Metal と署名の安定性を犠牲にしがちです。iOS CI/CD と自動化エージェントで24/7 予測可能な環境、監査可能な隔離、契約可能なディスクが欲しければ、専用リモート Macの方が本番現実に近いことが多いです。NodeMini クラウド Mac mini レンタルはそのフットプリットに合います。リージョンとディスクを選び、自動化向けに SSH を固め、フィンガープリントとキャッシュ方針を引き継ぎ可能な運用資産として扱ってください。