メインコンテンツまでスキップ

第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 ciCACHED っぽい扱いになって、時間がほぼ増えない
  • もし毎回 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章)では、この形をさらに固めて **「ソース変更では絶対に依存インストールが走らない」**状態に仕上げていきますよ〜😆🔥