
HackerNoonが2026年9月4日に公開した「Docker Build Cache Explained: How to Cut Build Times」は、Dockerビルドキャッシュの内部構造と短縮手法を体系的に整理した解説である。同記事は、本来40秒で終わるビルドが8分要する場合、ほぼ確実にキャッシュ順序の問題であると指摘する。LaravelプロジェクトでDockerfileを書く際にも、composer install層のキャッシュ破りは頻繁に遭遇する論点であり、個人開発環境でのビルド時間短縮は投資対効果が高い。
レイヤーキーの連鎖構造
Dockerの各命令はレイヤーを生成し、各レイヤーのキャッシュキーには直前レイヤーのキーが含まれる。3番目のレイヤーを更新した瞬間、4番目以降の内容変更の有無に関わらず全て無効化される。この連鎖構造がキャッシュ機構の全体であり、任意の層で命令順序を見直せば改善余地が見つかる。
RUN apt-get updateは文字列そのもののみでキャッシュされ、Dockerはアップストリームのパッケージインデックス更新を検知しない。結果として6週間前のレイヤーがそのまま再利用されることがある。updateとinstallは同一命令内に記述しなければならない。Laravelの公式ベースイメージにおいてもこの原則はPHP拡張のインストールにそのまま適用され、apt-get updateだけを独立した行に書くのは典型的なアンチパターンである。
COPY . .はソースツリー全体を含むため、Bladeテンプレートを1行修正しただけでも後続のcomposer installが再実行される。頻繁に変更されるソースを後に回し、変更頻度の低いマニフェストを前に置く順序設計がキャッシュ効率の核心である。ソース編集で無効化されるのは末尾2層のみとなり、依存関係インストール層への波及を防げる。
言語別の定石として、Pythonではrequirements.txt、Goではgo.modとgo.sum、RubyではGemfileとGemfile.lock、Javaではpom.xmlをソースコードより前に配置する。Laravel/PHPの場合はcomposer.jsonとcomposer.lockをPHPソースより前に配置する形となる。Dockerfile内でこの順序さえ守れば、ソース編集時に依存関係ダウンロードが再実行される頻度は劇的に下がる。
コンテキスト肥大と.dockerignore
.dockerignoreは二つの役割を持つ。ビルドコンテキストの縮小と、無関係なファイルによるキャッシュ破壊の防止である。
COPYキーはファイルメタデータを含むため、再生成されたnode_modules、.gitディレクトリ、ビルド成果物がキャッシュを破壊する可能性がある。Laravelプロジェクトではstorage配下のフレームワークキャッシュやログ、vendor配下のautoload生成物、テスト用フィクスチャ、PailやTelescopeが生成する一時ファイルなどが該当することが多い。
同記事は1.2GBのコンテキストが.git履歴だけで構成されていた事例を挙げている。大規模リポジトリでは.dockerignoreの欠落がビルド時間増大の主要因となる。逆に.dockerignoreを正しく設定することで、ビルドコンテキスト送信コスト(多くの場合ビルドの最遅段階)を削減できる。
コンテキストが数百MBを超える場合は.dockerignoreの見直しを最優先で行う。.dockerignoreが欠落しているか、誤って設定されている可能性が高い。
BuildKitとCIでのキャッシュ戦略
ARGは初回使用以降の全レイヤーを無効化する。ビルドごとに変化するARGを先頭に置くと、ファイル全体のキャッシュが事実上機能しなくなる。ビルド引数の設計は慎重に行う必要がある。固定のビルド引数のみを先頭に置き、可変な引数は後段に配置する原則が推奨される。
BuildKitでは永続キャッシュディレクトリをマウントできる。レイヤーに含まれず、ビルド間を跨いで存続する。Composerのキャッシュをこの永続マウントに逃がす構成が考えられる。composer installが再リンクのみを行い、数分単位の再インストールが秒単位に短縮される。レイヤー自体が破棄されてもダウンロード済みtarボールを再利用でき、フル再インストールと比較して改善幅は大きい。
CI環境では各ランが新ランナーで開始されるためローカル層が保持されない。mode=maxを指定して中間層もエクスポートすることで、キャッシュが部分リビルドで機能する。デフォルトのmode=minは最終層のみをエクスポートするため、CIでの活用には不向きである。
ただし、arm64でビルドされたレイヤーはamd64では再利用されない。Apple Siliconの開発機とx86_64のCIランナー間では、この不一致が頻出する。exec format errorの原因がここに集約される。ローカルとCIでアーキテクチャを揃えるか、マルチアーキテクチャビルドを前提とした構成にする必要が生じる。
設計チェック項目
- 命令順序: composer.json/lockをPHPソースより前に配置する
- .dockerignore: .git、vendor、storage配下の生成物、テスト用ファイルをコンテキストから除外する
- BuildKit: 永続キャッシュマウントでComposerダウンロードを再利用する
- エクスポートモード: CIでは
mode=maxで中間層を有効化する - 注意点: ビルドごとに変化するARGを先頭に置かない
- 注意点: arm64とamd64間ではキャッシュが共有されない