Vuncloud ブログ
← フィールドノートに戻る

GitHub Actions の iOS CI が遅い理由:CocoaPods / SPM / DerivedData キャッシュ最適化(2026)

フィールドノート · GitHub Actions で CocoaPods / SPM / DerivedData をキャッシュ · workflow 例付き ·約 12 分

GitHub Actions iOS CI キャッシュ最適化:CocoaPods SPM DerivedData Xcode ビルド遅延
TL;DR · まず結論

GitHub Actions の iOS CI が遅いとき、犯人は CPU ではなくcache がない・key がズレていることが多い。当たり所は三つ:

  • CocoaPodsPods/ 未キャッシュ → 毎回 pod install から
  • Swift Package Manager(SPM):依存グラフを毎回 resolve、.build が job ごとに消える
  • Xcode DerivedData:コールドビルドで Swift 全量コンパイル・モジュール再構築

CocoaPods / SPM / DerivedData の cache を正しく配線すると、warm ビルドの壁時計はよく30%–60% 短くなる(Shadow 対照は ウォーターフォール拆解)。

30–60%
warm ビルド時間の典型的な短縮幅
3
CocoaPods · SPM · DerivedData
1–5 分
cache だけでよく見る節約(レイヤー単位)

1. GitHub Actions iOS CI が遅く感じる理由

まず出る声はだいたいこうです:「macos-latest が貧弱?」「M4 か上位機に乗り換える?」

現場の Xcode CI 遅延では、ボトルネックは CPU より見えにくい三つのコストに寄ることが多いです:

  1. 依存の再 resolve(CocoaPods / SPM)
  2. DerivedData のコールドスタート(全量コンパイル)
  3. actions/cache のミス——毎回が初回ビルドみたいになる

GitHub Actions はこれを増幅します。runner は使い捨て(job ごとにクリーンディスク)、cache は勝手に残らない、多ブランチ・多 job で key が汚れやすい。同じ commit なのに速い run と遅い runを追っているなら、まず cold / warm を分けてから、この記事の cache 設計に当ててください。

2. 壁時計が消える場所

2.1 CocoaPods(Pods cache)

典型的なコールドコスト:pod install およそ 3–8 分

本質:毎 CI で pod install を最初から——resolve、ダウンロード、統合を全部やり直し。

対処:actions/cachePods/ を保存。key は Podfile.lock ハッシュ + github.ref + arm64。CI では pod install --deployment

2.2 Swift Package Manager(SPM)

典型的なコスト:パッケージグラフの resolve で 1–5 分

本質:毎 run で再 resolve、.build 消去、Package.resolved が key に入っていない。

対処:~/Library/Caches/org.swift.swiftpm.build を cache。key に Package.resolved ハッシュ(§3.2)。

2.3 Xcode DerivedData

典型的なコールド増分:全量〜準全量コンパイルで 5–15 分

本質:DerivedData 未再利用 → Swift 全量コンパイル、アセット再処理、モジュール再構築。

対処:xcodebuild -derivedDataPath DerivedData でパスを固定し、そのパスを cache(§3.3)。

チームが GitHub Actions workflow をレビュー:CocoaPods・SPM・DerivedData cache と iOS CI 最適化

3. 動く GitHub Actions iOS CI cache 設定

runs-on: macos-latest 向け。下の三ブロックを同一 job に、pod install / xcodebuild の前へ(保存は actions/cache@v4 が自動)。

3.1 CocoaPods cache(必須)

CocoaPods cache · GitHub Actions
- name: Restore Pods cache
  uses: actions/cache@v4
  with:
    path: Pods
    key: pods-arm64-${{ github.ref }}-${{ hashFiles('**/Podfile.lock') }}
    restore-keys: |
      pods-arm64-${{ github.ref }}-

- name: Pod install
  run: pod install --deployment

3.2 SPM cache(必須)

SPM cache · iOS CI
- name: Restore SPM cache
  uses: actions/cache@v4
  with:
    path: |
      ~/Library/Caches/org.swift.swiftpm
      .build
    key: spm-arm64-${{ github.ref }}-${{ hashFiles('**/Package.resolved') }}
    restore-keys: |
      spm-arm64-${{ github.ref }}-

3.3 DerivedData cache(インパクト大)

DerivedData cache · xcodebuild
- name: Restore DerivedData cache
  uses: actions/cache@v4
  with:
    path: DerivedData
    key: dd-arm64-${{ github.ref }}-${{ hashFiles('**/Podfile.lock') }}
    restore-keys: |
      dd-arm64-${{ github.ref }}-

- name: Build iOS
  run: xcodebuild -scheme MyApp -derivedDataPath DerivedData ...

ステップ時間を比べる前に、ログで Cache hit occurred を確認。ミスなら先に key と path——Xcode バージョンのせいにしない。

4. cache key 設計(ここを飛ばさない)

iOS CI 最適化が runner ではなく key で落ちるケース、現場では珍しくありません。

✔ 入れるべきもの ❌ よくあるミス
アーキテクチャ(arm64 arm64 / x86 を分けない——runner を替えると全部ミス
ブランチ(github.ref ロックファイルだけ——DerivedData がブランチ横断で汚染
ロックファイルのハッシュ restore-keys が広すぎ(例:dd- だけ)→ 誤ヒット
restore-keys のフォールバック

ロックファイルが変わったとき、dd-arm64-${{ github.ref }}- のような接頭辞で一部再利用できる。複数 scheme なら key に ${{ matrix.scheme }}。同一 runner で並列 job が DerivedData ルートを共有しない——${{ github.run_id }} サブディレクトリで隔離。

5. self-hosted / Cloud Mac(上級)

Mac mini や Cloud Mac の self-hosted runner なら、actions/cache だけに縛られません——ディスクが残り、warm が安定しやすい:

  • DerivedData パスを固定
  • Pods ディレクトリを固定
  • オンディスク warm cache(job あたり 30–90 秒のアップロード/ダウンロードを省略)
self-hosted 固定パス
export DERIVED_DATA=/Volumes/Data/DerivedData/App-${{ github.run_id }}
export PODS_ROOT=/Volumes/Data/Pods/${{ github.ref_name }}

job 全文と 1 TB データディスクのメモ:下の workflowCI/CD 導入 FAQ

self-hosted · 固定 DerivedData + Pods
env:
  DERIVED_DATA: /Volumes/Data/DerivedData/App-${{ github.run_id }}
  PODS_ROOT: /Volumes/Data/Pods/${{ github.ref_name }}

jobs:
  build:
    runs-on: [self-hosted, macos-m4-ios]
    steps:
      - uses: actions/checkout@v4
      - name: Prepare dirs
        run: mkdir -p "$DERIVED_DATA" "$PODS_ROOT"
      - name: Pod install
        run: pod install --deployment
      - name: xcodebuild
        run: xcodebuild -scheme MyApp -derivedDataPath "$DERIVED_DATA" build

6. cache ミス ≠ 遅い runner(よくある誤読)

GitHub Actions iOS CI が遅いと、runner や Xcode 版のせいにしがちです。実際はこちらが多い:

見える現象 よりありそうな原因
突然ビルドが遅くなる cache ミス
P95 が揺れる cold ビルドが warm 統計に混ざる
ランダムに遅くなる 並列 job の DerivedData 争奪
依存がゼロから再ビルド cache key の誤設定

iOS CIが遅い?GitHub Actionsでxcodebuildがブレる理由と併読:cold / warm 分離 → cache 調整 → そのあとハード評価(2026 年、なぜ iOS CI/CD は Mac mini M4 で回すのか)。

7. 実測での改善幅

cache だけ直したときの典型的な節約:

レイヤー コールドミス時の上乗せ cache 配線後
CocoaPods 3–8 分 warm ではよく <30 秒–3 分
SPM 1–5 分 ヒット時は resolve が大幅短縮
DerivedData 5–15 分 warm はほぼ増分コンパイル

14 日間の Shadow では、cache 最適化だけで warm 壁時計がおよそ −1:40。キュー排除と self-hosted 固定ディスクを重ねると warm P95 は 14:12 → 6:05(−57%)——GitHub Actions macOS ランナー最適化を参照。

8. FAQ

GitHub Actions の iOS CI はなぜ遅い?

CPU より、CocoaPods / SPM / DerivedData が未キャッシュか key がズレていることが多い。使い捨て runner がミスを増幅します。

GitHub Actions で CocoaPods を cache するには?

Pods/ を cache。key:pods-arm64-${{ github.ref }}-${{ hashFiles('**/Podfile.lock') }}§3.1 参照。

iOS CI で SPM を cache するには?

swiftpm グローバルディレクトリと .build を cache。key は Package.resolved にバインド。§3.2 参照。

DerivedData cache の path はどうする?

actions/cachepathxcodebuild -derivedDataPath と一致させる。システムデフォルトは不要。

cache が大きすぎる?

GitHub はエントリあたり約 10 GB 上限。DerivedData は scheme ごとに key を分割するか、self-hosted で固定ディスクに置いてアップロードを省略。

macos-latest と self-hosted の違いは?

託管は actions/cache のみ、job 間で消えることも。self-hosted は /Volumes/Data 固定で warm が安定。GitHub Actions macOS ランナー最適化で対照。

9. まとめと関連ガイド

iOS CI 最適化で ROI が高いのは、チップ交換の前に CocoaPods・SPM・DerivedData の cache を配線すること——workflow は今日から試せます。

同シリーズ:

DerivedData と Pods のパスを固定したい?

Vuncloud Cloud Mac M4 Pro は 1 TB データディスク付き——self-hosted iOS CI 向け。actions/cache の往復を減らし、warm を安定させやすい構成です。

Cloud Mac プランを見る · CI/CD 導入 FAQ

フィールドノート · iOS CI

GitHub Actions iOS CI が遅い?まずこの3つのキャッシュ

CocoaPods · SPM · DerivedData · workflow 例

ウォーターフォール −1:40
期間限定 プランを見る