Dockerレイヤーcacheの解説: CIでのより速いイメージbuild
Dockerはイメージをcacheされたレイヤーの積み重ねとしてbuildする。めったに変わらない部分が先に来るようDockerfileを並べれば、ほとんどのbuildがほぼすべてを再利用する。
Dockerfileの各命令はレイヤーを生成する。入力が変わっていなければ、Dockerは前のbuildのレイヤーを再利用できる - だが1つの早期の変更が、その後のすべてを無効化する。並べ順がすべてだ。
レイヤーがどうcacheされるか
Dockerは各命令とその入力をhashする。hashがcacheされたレイヤーに一致すれば、stepを再実行せずにそれを再利用する。あるレイヤーの入力が変わった瞬間、そのレイヤーとその下のすべてのレイヤーが再buildされる - cacheは選択的にではなく、下方向に無効化される。
cache hitのために並べる
安定した命令を先に、変わりやすいものを最後に置く。依存関係のマニフェストをcopyし、アプリケーションのsourceをcopyする*前*に依存関係をインストールして、コード変更が依存関係インストールのレイヤーを壊さないようにする。
Cache-friendly ordering
COPY package*.json ./
RUN npm ci # cached unless deps change
COPY . . # changes often; only this layer rebuilds
RUN npm run buildCIがcacheをよく外す理由
- エフェメラルrunnerは、実行ごとにローカルのイメージcacheなしで始まる。
- 外部cacheバックエンドが設定されておらず、何も復元されない。
- depsをインストールする前にsourceをcopyし、commitごとにdepsを無効化する。
- ファイル上部近くの変わるbuild argumentがすべてを壊す。
CI実行をまたぐcache
エフェメラルrunnerにはローカルcacheがないため、外部cacheが必要だ: BuildKitのregistryバックのcache(--cache-from / --cache-to)はレイヤーをregistryに保存し、次の実行がそれらを復元する。それなしでは、あらゆるCIのbuildは事実上cold buildだ。
重要なポイント
- 各Dockerfile命令はレイヤー; 1つの変更がその下のすべてを無効化する。
- 安定したstepを先に、変わりやすいstep(sourceのcopy)を最後に並べる。
- 確実なhitのために、アプリのsourceをcopyする前に依存関係をインストールする。
- エフェメラルCIは、そもそもhitするために外部(registryバックの)cacheが必要だ。
関連ガイド
Dependency Caching Strategies for Faster CIRe-downloading dependencies every run is wasted time. Learn what to cache, how to key it on a lockfile, and t…
Cache Key vs Restore Key: How CI Cache Lookups WorkA cache key is the exact entry to save and look up; restore keys are prefix fallbacks for a near-miss. Learn…
CI Caching Explained: Speed Up Pipelines Without Breaking ThemHow CI caching works, what to cache (dependencies, build outputs, Docker layers), how cache keys and restore…