はじめに
Dockerイメージをビルドする際、「毎回時間がかかる」と感じたことはありませんか?
その原因の多くは「ビルドキャッシュを活用しきれていない」ことにあります。
Dockerのビルドキャッシュは、以前のビルド結果を再利用し、
不要な再ビルドをスキップできる強力な仕組みです。
しかし、単に「キャッシュが効く・効かない」ではなく、
BuildKitを用いたキャッシュ制御や、キャッシュマウントの活用、
さらにはCI/CDでのリモートキャッシュ共有まで踏み込むと、
ビルド時間を数分の一に短縮できます。
この記事では、基本から実践、そしてCI/CD連携まで、
Dockerビルドキャッシュの高度な活用方法を体系的に解説します。
Dockerビルドキャッシュの基本概念
Dockerのビルドは「レイヤーキャッシュ」によって構成されています。
Dockerfile内の各命令(FROM
, RUN
, COPY
, ADD
など)はそれぞれ独立したレイヤーを形成し、
同じ命令・同じ入力なら、そのレイヤーは再利用されます。
たとえば以下のDockerfileを考えます。
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y curl
COPY . /app
CMD ["bash"]
1回目のビルドではすべての命令が実行されますが、
2回目以降に内容が変わらなければ、RUN apt-get ...
のレイヤーがキャッシュされ再利用されます。
キャッシュを無効化したい場合は、以下のように明示的に指定できます。
docker build --no-cache -t myapp:latest .
ただし、命令の順序やファイルの変更でもキャッシュは無効化されるため、
Dockerfileの命令順は慎重に設計することが重要です。
BuildKitによる高速ビルドとキャッシュ共有
Docker 18.09以降で利用できる新しいビルドエンジン「BuildKit」は、
キャッシュの扱いを劇的に改善しました。
BuildKitの有効化
export DOCKER_BUILDKIT=1
docker build -t myapp:buildkit .
BuildKitの主な利点
- 並列ビルド:複数レイヤーを同時処理
- キャッシュ共有:
--cache-from
/--cache-to
でリモートキャッシュを利用可能 - キャッシュマウント:
--mount=type=cache
で依存パッケージを再利用 - セキュアビルド:
--secret
で認証情報を安全に扱える
これらの機能を使いこなすことで、
従来のdocker build
よりもはるかに高速・柔軟なビルドが可能になります。
ハンズオン – キャッシュマウントを使ったnpm依存解決高速化
ここからは実践です。
BuildKitのキャッシュマウントを活用して、npm install
の依存関係インストールをキャッシュ化してみましょう。
ディレクトリ構成
myapp/
├── Dockerfile
├── package.json
├── package-lock.json
└── src/
Dockerfile
# syntax=docker/dockerfile:1.4
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
# npmキャッシュを再利用
RUN --mount=type=cache,target=/root/.npm \
npm ci
COPY . .
CMD ["node", "src/index.js"]
実行コマンド
DOCKER_BUILDKIT=1 docker build -t myapp:cache-demo .
初回は通常通り依存をダウンロードしますが、
2回目以降は /root/.npm
のキャッシュが再利用され、npm ci
の処理が一瞬で完了します。
この仕組みは、Pythonのpip
やGoのgo mod
にも応用可能です。
CI/CDでのキャッシュ共有
開発マシン上だけでなく、CI/CD環境でもキャッシュを共有できるのがBuildKitの強みです。
GitHub Actions例
- name: Build with cache
run: docker buildx build \
--cache-from=type=gha \
--cache-to=type=gha,mode=max \
-t myapp:latest .
type=gha
はGitHub Actionsの内部ストレージを利用する方式で、
異なるジョブ間でもキャッシュが引き継がれます。
CI/CDパイプラインの高速化において、
このキャッシュ共有は最も効果的なテクニックのひとつです。
マルチステージビルドとキャッシュ戦略の融合
マルチステージビルドを使うと、
「依存のビルド」と「本番用の軽量イメージ」を分離できます。
以下はその応用例です。
# syntax=docker/dockerfile:1.4
FROM node:20-slim AS build
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
RUN npm run build
FROM node:20-slim
WORKDIR /app
COPY --from=build /app/dist ./dist
CMD ["node", "dist/server.js"]
これにより、
ビルド段階で依存キャッシュを再利用しながら、
最終的な本番イメージは不要なファイルを含まず軽量化されます。
キャッシュの管理とトラブルシューティング
キャッシュの削除
キャッシュを削除したい場合は以下のコマンドを使います。
docker builder prune
docker system prune -a
キャッシュヒットを確認する
ビルドの進行状況を詳細表示し、どのレイヤーが再利用されたか確認できます。
docker build --progress=plain .
CACHED
と表示されている部分が再利用されたレイヤーです。
ハンズオンまとめ
機能 | コマンド・設定例 | 効果 |
---|---|---|
BuildKit有効化 | DOCKER_BUILDKIT=1 | 並列化・キャッシュ制御 |
キャッシュマウント | --mount=type=cache | npm / aptなどの依存を再利用 |
リモートキャッシュ | --cache-to/from | CI/CD高速化 |
マルチステージ | FROM ... AS build | 軽量かつ効率的なビルド |
次のステップ
- CI/CDパイプラインへの統合
- GitHub ActionsやGitLab CIで
buildx
を使ったキャッシュ共有を実装
- GitHub ActionsやGitLab CIで
- レイヤーサイズの最適化
- キャッシュを保ちつつ不要な依存を削除
- Docker Registryでのキャッシュ活用
--cache-from
を使いクラウドキャッシュを利用
- BuildKit + セキュリティ統合
- Trivyなどのスキャンを統合して安全な高速ビルドを実現
まとめ
Dockerのビルドキャッシュは、単なる時間短縮の仕組みではありません。
キャッシュを設計することが、開発スピードを設計することです。
BuildKit・キャッシュマウント・リモート共有を理解し活用すれば、
CI/CD全体の効率が飛躍的に向上します。
次は、あなたのプロジェクトで「キャッシュ戦略」を見直し、
最速のDockerビルドパイプラインを構築してみてください。
コメントを残す