2026 共有リモート Mac CI での SwiftPM と CocoaPods Package.resolved · Bundler 分離 · DerivedData のディスク管理

共有または専用のリモート Macでは、SwiftPMCocoaPods を同時に動かすと、Package.resolvedGemfile.lockDerivedData がディスク上限と衝突し、並行ジョブが同じパスを踏みつけます。本稿はプラットフォームチーム向けの承認チェックリストです。7 つの見えにくいコスト、SPM のみ・Pods のみ・混在スタックの比較表、ディスクとキャッシュの 6 ステップ Runbook、および 再現可能なビルドセルフホスト Runnerスナップショットと長寿命ノードの各ガイドとの読み合わせ方をまとめます。

01

スタックを混在させる前に:共有リモート Mac CI でロックファイルとディスクを壊す 7 つの見えにくいコスト

Linux では依存キャッシュとビルド成果をボリュームごとに分けます。共有 macOS ホストでは SwiftPM のチェックアウト、Pods ツリー、DerivedData が既定では 1 つのホーム配下に集まりがちです。並列リポジトリが加わると、CPU より前にディスクまたは inode 圧力が来ます。以下 7 項は事前レビュー用です。

  1. 01

    Package.resolved とブランチ方針のずれ:ブランチごとのバケットがないと、解決は成功しても誤った成果物にリンクする場合があります。

  2. 02

    CocoaPods の Ruby エコシステムのずれ:システム Ruby、rbenv、Bundler を混在させると pod の版がばらつき、「ローカルは緑、CI は不安定」になります。

  3. 03

    DerivedData ルートの共有:複数ジョブが 1 つの -derivedDataPath に書き込むとモジュールキャッシュやインデックスが踏みつけられ、依存破損のように見えます。

  4. 04

    Pods と SPM でのサードパーティ重複:同一ライブラリが二重になるとダウンロード量と解決時間が倍増し、アーキレビューで見落とされがちです。

  5. 05

    稼働中キャッシュを消すクリーンアップ:経過日数だけをキーにした cron は、キュー待ちの成果物まで削除し連鎖障害を招きます。

  6. 06

    CDN/ミラー方針の不統一:pod repo update と SPM の解決が別の出口を使うと、ジッターが「CI が不安定」として観測されます。

  7. 07

    ディスク水位の契約欠如:スケジュール停止や読み取り専用への切り替えの閾値がないと、誰も気づく前にディスク満杯になり復旧コストが膨らみます。

共通の原因は、Linux VPS の「単一リポジトリ・単一パイプライン」という頭の中のモデルをマルチテナント Mac に持ち込むことです。名前空間化されたキャッシュとロックファイルが必要で、ディスクを大きくするだけでは足りません。プラットフォーム台帳に記録したうえで、次の表でスタックを収束させるか、厳格なディレクトリ境界付きで混在を受け入れるかを決めます。

SwiftPM は Package.resolved にコンパイラ連動の解決結果を書きます。CocoaPods は Ruby に結びつき、企業では多くの場合 Bundler です。最悪は、CI 上の対話シェルからグローバル gem を書き換え、共有ホストすべてにエントロピーを注入することです。コミット済みの Gemfile.lockbundle exec pod install のみ、消してよいパーティション上の vendor/bundle を推奨します。

再現可能なビルドと併せてください。フィンガープリントには swift package resolve のチェックサムと pod --version を含め、Xcode だけにしないでください。Runner と併せてください。共有ボリュームにキャッシュをマウントする場合はリポジトリ配下でスコープし、全員共用の巨大 DerivedData は避けます。

ネットワークと CDN の制御はセクション 4 で Bundler の横に再度登場します。比較表で議論をパーティションルールに落とし込みます。

02

SwiftPM のみ、CocoaPods のみ、または混在:共有リモート Mac 上のディレクトリとリスクのトレードオフ

万能解はありません。SPM のみはパスが揃いやすい一方、レガシー ObjC では依然 Pods が必要なことがあります。Pods のみは馴染み深いですが Ruby と CDN 運用のコストが増えます。レビューに 3 つの SLA を書きます。解決の再現性、ディスクピーク、失敗の説明可能性です。

次元SwiftPM 優先CocoaPods 優先混在(レガシーでよくある)
ロックファイルと再現性Package.resolved がリゾルバ/コンパイラとの結合を記録Podfile.lock に加え Ruby/Bundler を固定ロックファイルとキャッシュが二系統。重複依存とパス衝突に注意
ディスク像チェックアウトと SPM キャッシュで比較的予測しやすいPods が大きく、Ruby ツールチェーンも重いピークが積み上がる。DerivedData を明示的にバケット化
並行性ディレクトリ分離がしやすく並列に向くpod install がロックを握ることがあるためキューするジョブ作業ディレクトリを分割し、1 パスに二つの書き手を置かない
運用レバーXcode ツールチェーンと整合しフィンガープリントに合うgem ソース、CDN、Bundler キャッシュ方針を維持Runbook は最長だが、現実のアプリは多くここに着地
ゴールデンイメージSPM キャッシュ層を事前温めRuby と既知 Pods をベースラインに焼き込むことが多いイメージが肥大化。ツールチェーン/依存/可変層に分割

依存層で Mac を「VPS のように」借りるとは、予測可能なディレクトリ契約と水位を買うことであり、「ノート PC のディスクがなんとかなる」ことではありません。SPM と Pods のキャッシュはテナントとして扱い、背景ノイズにしないでください。

エンタープライズビルドプールを運用するなら、「依存解決」ジョブと「署名とリリース」ジョブを分けます。前者は積極的なクリーンアップに耐えられますが、後者は実験的な Bundler 状態とホームを共有すべきではありません。スナップショットと長寿命ノードでは、混在スタックを長寿命ホストで回すなら週次クリーンアップと水位が必要で、スナップショット基準線は Bundler と SPM キャッシュの層状プレヒートに向きます。

「まだ Pods を捨てられない」という決定のときは、どのサードパーティを SPM のみ/Pod のみに固定するか(例:クローズドソースのバイナリ)を規定し、同一モジュールを両経路に載せないでください。リンク時に代償が出ます。テンプレートリポジトリから最小の Gemfile.bundle/config の断片を配布し、チームごとに別々に発明させないようにします。

03

「共有リモート Mac で SPM と Pods」を引き渡し可能な Runbook にする 6 ステップ

順序は重要です。まずパーティション、次に解決、最後にキャッシュヒットです。再現可能なビルドのフィンガープリントと揃え、依存層が第二の未文書化環境を増やさないようにします。

  1. 01

    作業ルートとブランチバケットをリポジトリごとに固定:/ci/work/<repo>/<branch-hash>。SPM のチェックアウト、Pods、DerivedData をそのバケット配下に置き、既定の ~/Library には戻しません。

  2. 02

    Bundler と CocoaPods を固定:CI イメージまたはブートスクリプトでは bundle exec のみとし、BUNDLE_PATH をバケット内の vendor/bundle に向けます。

  3. 03

    SwiftPM の resolve をビルドから分離して観測:resolve に時間を計測し、失敗時は .build 近傍のログを残し、リゾルバのエラーとコンパイルエラーを混同しないようにします。

  4. 04

    ジョブごとに DerivedData を分離:上記の作業ルートと組み合わせ、xcodebuild には常に明示的な -derivedDataPath を渡します。

  5. 05

    クリーンアップ方針を定義:水位でトリガーし、アイドル時に実行し、最も使われていないものから退避します。rm -rf ~/Library の一括削除は行いません。

  6. 06

    Runner ラベルを配線:重い pod install ジョブは Runner の記事に従い専用ラベルでスロットルし、コンパイル偏重のジョブを飢餓状態にしません。

bash · 作業バケット環境の例(プロジェクトに合わせて調整)
export CI_WORK_ROOT="/ci/work/${REPO_SLUG}/${BRANCH_KEY}"
export DERIVED_DATA="${CI_WORK_ROOT}/DerivedData"
export PODS_ROOT="${CI_WORK_ROOT}/Pods"
export BUNDLE_PATH="${CI_WORK_ROOT}/vendor/bundle"
mkdir -p "$DERIVED_DATA"
bundle config set path "$BUNDLE_PATH"
bundle exec pod install --deployment
swift package resolve
info

ヒント:同一ホストで Fastlane リリースも動かすなら、リリース用バケットと CI の解決用バケットを分け、Bundler と App Store Connect 周りのツールが交差汚染しないようにします。

GitHub Actions などでは「依存のインストール」と「ビルド/テスト」を分割し、キャッシュキーはブランチ名だけでなくロックファイルの内容に紐づけます。ワークスペースで SPM と Pods が混在するなら、xcodebuild -workspace の引数を固定し、GUI の習慣と CI が永遠に乖離しないようにします。

XCTest と Simulatorと併せてください。テストがコンパイル用 DerivedData を再利用するなら、読み取りと書き込みの範囲を明示します。さもないとテスト後片付けがコンパイルキャッシュを壊します。Linux のコンテナボリュームと同様に、「誰が何を削除してよいか」を文書化します。

04

Bundler、CDN、読み取り専用フォールバック:ネットワークのジッターを「コードが壊れた」と誤読しないために

企業の CocoaPods で最も多い本番インシデントは構文エラーではなく、解決時のネットワーク障害をアプリケーションの不具合と誤読することです。共有ホストには gem ミラー方針と Git 転送方針(HTTPS と SSH)を 1 つにし、ファイアウォールでメタデータのホスト名を許可し、ワークフローに pod install のタイムアウトとリトライを焼き込みます。

SwiftPM では、メジャーな Xcode アップグレード後に Package.resolved がリゾルバと一致するかを確認します。カナリジョブで swift package resolve と最小ビルドを通してから本番流量を開けます。再現可能なビルドと整合させ、ロックファイルの変更は共有の解決キャッシュの無効化が必要であることを警告し、静かな汚染を防ぎます。

warning

注意:ディスクが一杯の崖ぎわでもジョブ受け入れを続けないでください。読み取り専用フォールバック(スケジュール停止)に切り替えて先に掃除します。さもないと Xcode と git が半端な状態を書き残し、短いキュー停止より高くつきます。

マルチリージョンでは CDN ヒット率と解決レイテンシをチャート化し、P95 が跳ねたらミラーを疑ってから「3 回リトライ」を求めません。SSH チェックリストと併せてください。Bundler と pod の版は設定管理で配布し、SSH での場当たりアップグレードは避けます。

05

設計レビューに貼れる参照値

閾値は並列度とリポジトリサイズに合わせて調整してください。以下は合意形成用のアンカーです。

  • 共有システムボリュームの水位:空き容量 20%以上を維持し、それ未満では削除より先にスケジュールを止め、監査のために何を消したかを記録します。
  • 二系統のピーク:大規模 iOS アプリでは DerivedData、Pods、SPM チェックアウトが合わせて数十 GB に達することがあります。容量は単一ビルドのピークではなく、最重リポジトリ × 同時ジョブ × 安全係数で見積もります。
  • 解決の再現性プローブ:フィンガープリントに swift package resolve の終了コード、bundle exec pod --versionPodfile.lock のチェックサムをマージゲートに記録します。

ノート PC はスリープしツールチェーンがずれるため、依存の問題が不可解に見えがちです。純粋な Linux では Apple 公式の iOS スタックをホストできません。解決とビルドを専用かつ常時稼働でパーティション可能なリモート Mac に移すと、SwiftPM と CocoaPods を契約として扱えます。一回限りのハードウェアや不安定な共有ホスティングと比べ、NodeMini の Mac Mini クラウドレンタルは固定 SSH、明確なディスク段、再現可能なノードプロファイルを組み合わせ、プラットフォーム水準の依存ガバナンスに向きます。段階の比較は Mac Mini レンタル価格、オンボーディングは ヘルプセンターをご利用ください。

本 Runbook を社内の「依存変更レベル」に結びつけます。ロックファイルのパッチ、マイナー、メジャーで承認とキャッシュ無効化ルールを変えます。

FAQ

FAQ

推奨しません。リポジトリ/ブランチのバケットごとに -derivedDataPath を分け、Pods と Bundler の vendor パスも分離します。さもないと同時ジョブがキャッシュを踏みつけます。プラットフォームのガイダンスは ヘルプセンターを参照してください。

Ruby と Bundler のバージョン、Gemfile.lockpod install 用の CDN ミラー方針です。そのうえで共有ホストごとにクリーンアップの水位を設定します。ディスク段の比較は Mac Mini レンタル価格をご覧ください。

再現ビルドは Xcode のフィンガープリントと Keychain を扱い、Runner の記事はラベルとキャッシュマウントを扱います。本稿は SPM と Pods を混在させるときのディレクトリとディスクの契約を扱います。機械から依存まで一通りカバーするには 3 本を併読してください。