CI/CD

buildx のキャッシュ戦略

buildx で使える 3 種類のキャッシュ(registry / gha / inline)の特徴と使い分け、そして CI のビルド時間を実際に短縮するためのコツ。

buildx のキャッシュ戦略 diagram

なぜ buildx のキャッシュが重要か

CI は毎回真っさらなランナーでビルドするため、ローカルの docker build のようなレイヤーキャッシュがそのまま使えません。

キャッシュを明示的に外部化しないと、毎回 npm install / pip install / go mod download をゼロからやり直すことになります。

buildx のキャッシュ機能を使うと、前回のビルドで作ったレイヤーを外部ストレージに保存し、次回ビルド時に再利用できます。

小〜中規模のプロジェクトで ビルド時間を 50〜80% 短縮 できることが多いです。

3 種類のキャッシュバックエンド

バックエンド 書式 保存先 向いている場面
gha type=gha,mode=max GitHub Actions のキャッシュストレージ(リポジトリに紐づく、上限 10GB) GitHub Actions 単独で完結させたい場合。セットアップが最も簡単
registry type=registry,ref=...:cache 任意のコンテナレジストリ 複数の CI 間で共有したい、GHA の 10GB 制限を超える大規模プロジェクト
inline type=inline イメージ本体にキャッシュメタを埋め込む レジストリキャッシュの簡易版。別タグを持たなくて良い反面、mode=min 相当で効果は限定的

マネージド CI(GitHub Actions)なら gha が第一選択。

レジストリ側にも制約がなく、複数マシンで共有したいなら registry に切り替えるのが定石です。

gha キャッシュの書き方

gha キャッシュは Actions の ACTIONS_CACHE_URL / ACTIONS_RUNTIME_TOKEN を内部で使います。

docker/build-push-action がこれらを自動的に渡してくれるため、指定は次の 2 行だけで足ります。

mode=max は全ステージのキャッシュを保存(マルチステージビルド全てを含む)、mode=min(デフォルト)は最終ステージだけ。

CI では max 推奨です。

bash
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

registry キャッシュの書き方

別タグ(例: :cache)としてキャッシュ用マニフェストを push します。

GHCR・ECR・Docker Hub などマニフェストリスト対応の OCI 互換レジストリならどこでも動きます。

mode=max 推奨です。

初回は完全にキャッシュミスしますが、2 回目以降の短縮効果が大きいのが特徴です。

また、本番イメージと同じレジストリに置けばネットワーク的にも近く、CI↔キャッシュの転送コストが小さくなります。

bash
      - uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
          cache-from: type=registry,ref=ghcr.io/${{ github.repository }}:buildcache
          cache-to: type=registry,ref=ghcr.io/${{ github.repository }}:buildcache,mode=max,compression=zstd

キャッシュ効果を最大化するコツ

  • Dockerfile のレイヤー順を見直す: 変わりにくいものを上に、変わりやすいものを下に。COPY package*.json ./ && npm ci を先、COPY . . を後に置くと、ソース変更時でも npm ci はキャッシュヒットする
  • .dockerignore を厳しくする: node_modules.git が入るとハッシュが毎回変わり、キャッシュがほとんど使えなくなる
  • --cache-from は複数指定できる: PR のキャッシュ(リリースブランチ)と main のキャッシュの両方を cache-from に列挙すると、ヒット率が上がる
  • マトリクスビルドでは branch 込みのキー: 別 OS / 別アーキのジョブがキャッシュを踏み潰さないよう、ref=.../buildcache-linux-amd64 のようにアーキ込みで命名する
  • mode=max のディスク使用量に注意: 10GB 制限を超えると古いキャッシュから順に evict される。巨大プロジェクトは registry への切り替えを検討
  • pull_request で cache-to を動かすときの注意: fork 元 PR では書き込み権限がないため失敗する。cache-to: ${{ github.event_name == 'push' && 'type=gha,mode=max' || '' }} のように push 時だけに制限するか、cache-from だけにする