第12章:Dockerビルドを速くする“基本の型”⚡🧠
この章のテーマはシンプルです👇
「ソースをちょっと直しただけなのに、毎回 npm ci で数分待つ…」を卒業すること!😆🚀
1) まず結論:速いDockerfileには“型”がある🧩✨
Dockerのビルドは、ざっくり言うと Dockerfileの1行ずつが「積み木(レイヤー)」 です🧱 そして 前回と同じ積み木は再利用(キャッシュ) されます♻️
でも逆に言うと…
- ある積み木が変わる → その上に積んだ全部が作り直し 😇💥
だから「変わりやすいもの(ソースコード)」と「変わりにくいもの(依存関係)」を分けて積むのが勝ち筋です🏆✨
2) キャッシュが死ぬ“ありがちなDockerfile”😱
悪い例(よく見るやつ)👇
ソースを先に COPY . . しちゃうと、ソースを1行変えただけで依存インストールまで巻き込まれます💣
FROM node:24-bookworm-slim
WORKDIR /app
COPY . . # ← ここで全部コピー(毎回変わりやすい)
RUN npm ci # ← 毎回やり直しになりがち 😭
CMD ["npm", "run", "start"]
3) キャッシュが効く“基本の型”✅⚡
ポイントはこれだけ👇
- 依存定義(package.json)だけ先にCOPY*
- npm ci を先に実行
- 最後に ソースコードをCOPY
こうすると、ソースだけ変えた時は 依存インストールのレイヤーがキャッシュで再利用されます♻️✨
FROM node:24-bookworm-slim
WORKDIR /app
## ① 依存の定義ファイルだけ先にコピー
COPY package.json package-lock.json ./
## ② lockfile前提でクリーンインストール(再現性&キャッシュに相性◎)
RUN npm ci
## ③ 最後にソースをコピー(ここはよく変わる)
COPY . .
CMD ["npm", "run", "start"]
この「型」が効く理由は、依存が変わらない限り npm ci の行が“前回と同じ”扱いになって再実行されにくいからです🧠✨
ちなみに npm ci は lockfile必須で、package.json とズレてたらエラーで止めてくれる(=再現性に強い)仕様です🧼📦 (docs.npmjs.com)
4) 体感しよう:キャッシュが効くか“目で見る”実験🔬👀
4-1) まず1回ビルド(初回は遅くてOK)🐢
PowerShellで👇
docker build --progress=plain -t myapp:dev .
--progress=plain を付けると、ビルドログが追いやすくなります🧾✨(DockerのCLIオプションとして用意されています)(docs.docker.jp)
4-2) 次に「ソースだけ」ちょい変更✏️
例:src/index.ts のログ文だけ変える、とかでOK🙆♂️
4-3) もう1回ビルド(ここが本番)⚡
docker build --progress=plain -t myapp:dev .
ここで理想は👇
COPY package*.jsonはキャッシュRUN npm ciもキャッシュ(または一瞬)COPY . .以降だけが更新
ログ上で CACHED みたいな表示が出て、体感で速くなります😆🚀
5) さらに速くする“現代の裏技”:BuildKitのキャッシュマウント🧠⚡⚡
ここからは「効いたら気持ちいいやつ」😎✨ BuildKitには、ビルド中だけ使える 永続キャッシュ置き場を作る機能があります(cache mount)♻️
Dockerの公式ドキュメントでも、npm install / npm のキャッシュを RUN --mount=type=cache で使う例が紹介されています📘 (Docker Documentation)
しかもBuildKit自体、Docker Desktopではデフォルト、Docker Engineでも 23.0以降はデフォルトです🧰✨ (Docker Documentation)
5-1) こう書く(npmのダウンロードを再利用しやすくする)📦⚡
FROM node:24-bookworm-slim
WORKDIR /app
COPY package.json package-lock.json ./
## BuildKitのキャッシュ領域をnpmキャッシュとして使う
RUN --mount=type=cache,target=/root/.npm npm ci
COPY . .
CMD ["npm", "run", "start"]
これの嬉しさは👇 「依存レイヤーが作り直しになったとしても、ダウンロード済みのnpmキャッシュが残ってて速い」になりやすい点です🏎️💨 (Docker Documentation)
6) “速くならない”ときのチェックリスト🧯✅
A. package-lock.json をコピーしてない / 更新されてない📌
package-lock.jsonがないとnpm ciは成立しません(または怒られます)😇- lockと
package.jsonがズレてるとnpm ciは止まります(それが正しい)🧼 (docs.npmjs.com)
B. 依存が毎回変わってる(例:package.json を頻繁に触ってる)🌀
- 依存を変えたら、当然
npm ciはやり直しになります - 「ソースだけ変更」のときに速くなるのが主目的です🎯
C. 何かおかしい時の“強制リセット”🧨
キャッシュが原因か切り分けたいときは👇
docker build --no-cache --progress=plain -t myapp:dev .
7) ミニ理解テスト(3問)📝✨
COPY . .をnpm ciより前に置くと何が起きやすい?😱- 依存が変わってないのに毎回
npm ciが走るとしたら、どのレイヤーが毎回変わってそう?🔍 - BuildKitの
--mount=type=cacheは何を“永続化”してくれる?♻️
8) この章のゴール(できた判定)🏁🎉
次を満たせたら勝ちです🙌
- ソース1行だけ変更して
docker buildしたときにnpm ciがほぼ走らない(キャッシュになる) ✅ --progress=plainのログで「どの行がキャッシュされたか」説明できる✅ (docs.docker.jp)- (おまけ)BuildKitのcache mountで 依存再構築でも速くなるのを体感できた✅ (Docker Documentation)
次の第13章は .dockerignore で「送るファイルを減らして地味に爆速」🚀🧹に入ります。
第12章の“キャッシュの型”ができてると、第13章がさらに気持ちよく効きますよ〜😆✨