ビルドキャッシュを再利用する - buildx cache
BuildKit のキャッシュを CI で再利用すると、ビルド時間を大幅に短縮できる。GitHub Actions の `gha` キャッシュやレジストリ型キャッシュを使い分ける。
概念図
構文
cache-from / cache-to: type=gha | type=registry | type=local | type=inline実例
GitHub Actions 組み込みのキャッシュストレージを使う最も手軽な構成。
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/acme/app:latest
cache-from: type=gha
cache-to: type=gha,mode=maxレジストリ自体をキャッシュストアにする。複数 CI / ローカルからも共有可能。
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ghcr.io/acme/app:latest
cache-from: type=registry,ref=ghcr.io/acme/app:buildcache
cache-to: type=registry,ref=ghcr.io/acme/app:buildcache,mode=maxなぜキャッシュが要るのか
毎回クリーンな Runner 上で docker build すると、ベースイメージの pull、パッケージのインストール(npm ci / pip install / go mod download 等)、ビルド本体のすべてがやり直しになります。
実アプリでは 1 ビルド 5〜15 分が普通で、1 日に何十回と push される開発現場では支払いも待ち時間も馬鹿になりません。
BuildKit はレイヤー単位のキャッシュを持っており、「変わっていない部分」は再計算しません。
CI の Runner は毎回新品なので、そのキャッシュを外部ストレージ(GHA キャッシュ、レジストリ、S3 等)に保存し、次の run で pull して reuse する、という運用をします。
キャッシュバックエンドの種類
| type | 保存先 | 向く場面 |
|---|---|---|
gha |
GitHub Actions の組み込みキャッシュ | GitHub で閉じるプロジェクト。導入が最も簡単 |
registry |
任意の OCI レジストリ | GHA 外にも共有したい/複数 CI で共有したい |
s3 / gcs / azblob |
各クラウドのオブジェクトストレージ | 独自 Runner で細かく制御したい |
local |
Runner のローカルディレクトリ | self-hosted runner で永続ボリュームがある場合 |
inline |
イメージ自体のレイヤーに埋め込む | 追加ストレージを用意できない/小規模なケース |
mode=max を付けると中間レイヤーまで全部キャッシュし、mode=min(デフォルト)だと最終イメージに関わる分だけキャッシュします。
速度を取るなら max、容量を抑えるなら min です。
キャッシュが使われにくい Dockerfile の書き方
キャッシュはあくまで「命令と入力ファイルのハッシュ」で判定されます。
以下の 4 つは代表的なアンチパターンです。
COPY . .を依存解決の前に置く: ソース 1 文字の変更でnpm installまで再実行されるRUN apt-get update && apt-get install ...を 2 命令に分ける:updateだけ走り直して古いパッケージを掴む--build-argにタイムスタンプを毎回渡す: 以降の全レイヤーが無効になるADD <url>で動的なリソースを取りに行く: 外部が変わるたびに差分扱いになる
順番は「OS パッケージ → 依存ファイル (package.json 等) → 依存インストール → アプリソース」の 4 段階に整えると、ソース変更が多くても依存層まではキャッシュが残ります。
キャッシュサイズと有効期限
GHA キャッシュは 1 リポジトリあたり合計 10 GB の上限があり、古いものから自動的に evict されます。
巨大な node_modules や Python ホイールをそのまま入れると、すぐ枠が埋まります。
対処は 3 つ。
第一に .dockerignore で context を小さく保つ。
第二に、めったに変わらない重い依存は専用のベースイメージに切り出し、アプリ用キャッシュを軽く保つ。
第三に、registry 型キャッシュに移行して容量制約を回避する。
レジストリ型キャッシュは見かけ上レイヤーとしてプッシュされるため、古いタグは定期的に剪定(retention policy)しないと無限にストレージ代がかかります。
関連トピック
GitHub Actions- GitHub Actions はリポジトリのイベントに応じてワークフローを実行する CI/CD サービス。`docker/build-push-action` を組み合わせれば、数十行の YAML でビルドとプッシュまで自動化できる。 multi-arch- 1 つのイメージタグに amd64 と arm64 の両方を含めると、Apple Silicon や Graviton でも同じ pull で動く。Buildx のマニフェストリストで実現する。 registry push- ビルドしたイメージはレジストリに push して初めて本番で使える。GHCR・ECR・GAR・Docker Hub など目的地ごとに認証・命名・保管ポリシーが異なる。 