第07章:Dockerfileの順序:最重要の黄金ルール 🥇⚡️
この章の狙いはシンプルです😊 「依存インストール(npm ci)が毎回走って遅い…」を、Dockerfileの並び替えだけで“激減”させること!🚀
1) まず結論:黄金ルールはこれだけ 🥇✨
**Dockerfileは「変わりにくいもの → 変わりやすいもの」の順に書く!**🧠
理由は、Dockerのビルドが“層(レイヤ)”で積み上がってて、途中の層が変わると、その後ろ全部やり直しになるからです😇
(なので、重い npm ci を「変わりやすいCOPY」の後ろに置くと毎回地獄…🔥)(matsuand.github.io)
さらに最近のDockerは BuildKit が標準で、キャッシュをかなり賢く扱います。だからこそ「順序」が効きます💪(Docker Documentation)
2) “遅いDockerfile”あるある 😭🐢
たとえばこう👇(よく見る形)
FROM node:24-bookworm-slim
WORKDIR /app
COPY . .
RUN npm ci
CMD ["npm", "run", "dev"]
**何がダメ?**😵💫
COPY . . はソースを全部入れるので、TypeScriptの1行を変えただけでもこの層が変わりがち。
すると その後ろの RUN npm ci が毎回やり直しになります💥
(Dockerは COPY / ADD の入力が変わるとキャッシュを無効化し、後続も再実行になります)(matsuand.github.io)
3) “速いDockerfile”の王道:依存ファイルだけ先にCOPY 📦➡️⚡️
依存は「依存ファイルだけ」を先に入れて、そこでインストールします😎
FROM node:24-bookworm-slim
WORKDIR /app
## ① 依存定義だけ先に入れる(ここが黄金!)
COPY package.json package-lock.json ./
## ② 依存インストール(重い処理はキャッシュに乗せたい)
RUN npm ci
## ③ そのあとにソースを入れる(ここは頻繁に変わる)
COPY . .
CMD ["npm", "run", "dev"]
これで、ソースだけ変えたビルドなら
✅ COPY package*.json は変わらない → ✅ RUN npm ci がキャッシュヒット
になりやすいです🎉(Docker Documentation)
ちなみにNodeは v24 が Active LTS なので、教材例として
node:24-...は今どきの選び方です🧠 (公式のリリース表で v24 が Active LTS、v22 は Maintenance LTS になっています)(Node.js)node:24-bookworm-slimみたいなタグは公式イメージ側で提供されています📦(Docker Hub)
4) 図でイメージ:どこでキャッシュが壊れる?🧱💥
- レイヤA:
COPY package.json package-lock.json - レイヤB:
RUN npm ci(超重い) - レイヤC:
COPY . .(ソース)
ここで、ソース編集で変わるのは レイヤC。 だから レイヤBはやり直さないで済む可能性が高い、という仕組みです😊(Docker Documentation)
5) 🧪ミニ演習:キャッシュが効いてるか計測してみよう ⏱️📊
手順A:まず“冷えた状態”でビルド🥶
PowerShellで👇
Measure-Command { docker build -t cache-test . }
手順B:もう一回ビルド(ここで速くなるのが理想)🔥
Measure-Command { docker build -t cache-test . }
手順C:TypeScriptのソースを1行だけ変更 → 再ビルド✍️
例:src/index.ts に1行ログを足す
Measure-Command { docker build -t cache-test . }
期待する挙動🎯
RUN npm ciが CACHED っぽい扱いになって、時間がほぼ増えない- もし毎回
npm ciが走るなら、次の「チェックリスト」を見ます👀
参考:
npm ci自体も「自動環境向けのクリーンインストール」として公式に説明されています(Dockerビルドと相性がいい)(docs.npmjs.com)
6) “キャッシュが効かない”ときのチェックリスト ✅🕵️♂️
✅1) ロックファイル、入れてる?(超重要)🔒
- npmなら
package-lock.json - pnpmなら
pnpm-lock.yaml - yarnなら
yarn.lock
これが変わると依存層が変わるので、当然 npm ci はやり直しになります💡
✅2) COPY package*.json の“範囲”がズレてない?📁
ありがちなのは、
COPY package.json ./だけで lockをコピーしてない → 依存が安定しづらい&キャッシュ効きにくい
✅3) .dockerignore で不要物を混ぜてない?🧹
ここまでで作った .dockerignore が効いてないと、
ビルド入力がデカくなってキャッシュが壊れやすいです😵💫(Docker Documentation)
✅4) package.json の version を毎回変えてない?🔁
自動でバージョンを書き換える運用だと、依存が同じでも package.json が変わるので
→ npm ci が毎回やり直しになります😭
✅5) COPY . . の前に「生成物を作ってない?」🏗️
たとえば RUN npm run build を先にやって、dist/ を巻き込む…みたいな順序だとカオスになりがち。
“依存 → ソース → ビルド” の並びを守るのが安定です✨(Docker Documentation)
7) 🤖AI活用:Dockerfile順序レビューの“型”🧰✨
Copilot / Codex / ChatGPT みたいなAIに、こう投げると強いです👇(コピペOK)
プロンプト①:キャッシュが壊れる箇所を特定してもらう🕵️♀️
このDockerfileで「キャッシュが無効化されやすい命令」を3つ指摘して。
理由も「どのレイヤが変わって後続が再実行されるか」で説明して。
最後に、改善したDockerfileを提示して。
プロンプト②:Node/TS向けの“依存先出しCOPY”に書き換え🛠️
Node.js + TypeScriptのDockerfileです。
「依存は先にCOPYしてnpm ciをキャッシュに乗せる」方針で、
差分(before/after)で書き換えて。さらに注意点を5つ箇条書きで。
プロンプト③:自分のプロジェクト専用に最適化🎯
このリポジトリ構成(ツリー)に合わせて、DockerfileのCOPY順と .dockerignore を提案して。
依存が変わらない限り npm ci が再実行されないことを最優先にして。
※注意:.npmrc やトークンなど 秘密情報は貼らないでくださいね🙅♂️🔑(AIに渡すのは設計だけ!)
8) まとめ:この章の“持ち帰り”✅🎁
- **Dockerfileは「変わりにくい → 変わりやすい」**🥇
- 依存ファイルだけ先にCOPY →
npm ciをキャッシュに乗せる📦⚡️ - ソースをいじっても 依存が同じなら速いのが正解🎉
- もし遅いなら、まずは lockファイル・COPY範囲・dockerignore を疑う🕵️♂️
次の章(第8章)では、この形をさらに固めて **「ソース変更では絶対に依存インストールが走らない」**状態に仕上げていきますよ〜😆🔥