第13章 pnpm × キャッシュマウントの定番レシピ 🍳⚡️📦
この章は「pnpm install が毎回やり直しで遅い😵💫」を、BuildKit のキャッシュマウントで一気に軽くする回だよ!🚀 ポイントは pnpm の“ストア”をキャッシュすること。pnpm 公式もこの方針で例を出してるよ。(pnpm.io)
1) まず結論:キャッシュするのは「pnpmストア」🧠✨
pnpm は、ダウンロードしたパッケージを ストアに貯めて再利用する思想(≒同じものは何度も落とさない)だから、Docker ビルドではそのストアを RUN --mount=type=cache で“ビルド間で持ち越す”のが超効く!💥
BuildKit のキャッシュマウントは「ビルドのたびに積み上がるレイヤキャッシュ」と違って、レイヤが壊れても“ダウンロード済み資産”を再利用できるのが強みだよ。(Docker Documentation)
2) 定番レシピ:最小で効く Dockerfile(まずはこれ)🧩
ここでは pnpm 公式例と同じく、ストアを /pnpm/store に置いてキャッシュします。(pnpm.io)
## syntax=docker/dockerfile:1
FROM node:24-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /app
## 依存関係だけ先にコピー(ここがキャッシュの命🔥)
COPY package.json pnpm-lock.yaml ./
## pnpmストアをキャッシュマウントして install を高速化⚡️
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
pnpm install --frozen-lockfile
## ここから先でソースをコピー(依存レイヤを壊しにくくする)
COPY . .
## 例:TypeScriptをビルドするなら
RUN pnpm run build
3) ここが大事!レシピの“効きポイント”解説 🔍✨
✅ (A) COPY package.json pnpm-lock.yaml を先にする理由 📌
ここを先にしておくと、普段の編集(src/ いじるだけ)では依存レイヤが壊れにくくなる!
つまり「毎回 install 😭」が「install スキップ😎」になりやすい。
✅ (B) --mount=type=cache の意味(ざっくり)🧠
RUN の間だけ、指定ディレクトリに“永続っぽいキャッシュ”を付けてくれる。
BuildKit はこのキャッシュをビルド間で再利用できるので、再ビルドでも 変更分だけDL になりやすい。(Docker Documentation)
✅ (C) --frozen-lockfile を付ける理由 🔒
ロックファイルを勝手に書き換えない=ビルドが再現しやすい。 (「動いたり動かなかったり」事故が減る👍)
4) “効いてるか”の確認方法(超だいじ)👀⏱️
① 2回ビルドして差を見る 🏎️💨
1回目は当然遅い(初回DLだから) 2回目が 目に見えて速くなるのが理想!
docker build --progress=plain -t myapp:cachetest .
docker build --progress=plain -t myapp:cachetest .
② ログで「また落としてない」感を探す 🔎
2回目、pnpm のダウンロード量が減ってたり、インストール時間が短くなってたら勝ち!🎉 (全部がゼロにはならないこともあるけど、体感で軽くなればOK)
5) ありがちな落とし穴 🕳️😵💫(ここで詰まりやすい)
❌ 落とし穴1:COPY . . を先にやっちゃう
ソース更新のたびに依存レイヤまで巻き添えで壊れがち。 👉 依存ファイルだけ先に COPY が鉄則!
❌ 落とし穴2:キャッシュの“場所”がズレてる
キャッシュマウントしてるのに、pnpm がそこを使ってないと意味ゼロ😂
この章のレシピは、pnpm 公式例と同じ target=/pnpm/store で揃えてるからまず安心。(pnpm.io)
❌ 落とし穴3:並列ビルドでキャッシュが競合する(たまに)⚔️
複数ビルドが同じキャッシュを同時に触ると、ツールによっては壊れることがある。
BuildKit には sharing=locked で「順番待ち」にする考え方があるよ(apt の例)。(Docker Documentation)
pnpm で問題が出る場合は、次みたいに“ロック付き”を試す価値あり👇
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store,sharing=locked \
pnpm install --frozen-lockfile
⚠️ 注意:CI だと効かないことがある
pnpm 公式も「CI は環境が使い捨てで、キャッシュマウントが期待通り残らないことがある」って注意してる。(pnpm.io)
その場合の“別解”が次章の pnpm fetch につながるよ(ここでは「そういう世界もある」だけ覚えればOK😉)
6) 🧪 ミニ演習:キャッシュ有/無で比較して“勝ち筋”を掴む 🏁📊
演習1:わざとキャッシュ無しにして時間を測る😈
--mount=type=cache を一旦消してビルド → 時間をメモ
戻してビルド → 時間をメモ
差が出たら成功!🎉
演習2:依存が変わらない編集をして再ビルド✍️
src/ の1行だけ変えて再ビルド。
install が走らない/軽いなら設計勝ち!🥇
7) 🤖 AI活用プロンプト(コピペOK)🧰✨
① キャッシュが壊れる原因を見つける
「この Dockerfile のどの行がキャッシュを壊しやすい?理由もセットで3つ教えて。改善案も出して」
② pnpmストアの最適 target を点検
「pnpm のキャッシュ/ストアの保存先がこの Dockerfile で正しいかチェックして。ズレてたら修正案を出して」
③ “変更頻度”で COPY を再設計
「変更頻度が低い順に COPY と RUN を並び替えて、ビルドが速くなる Dockerfile を提案して(理由つき)」
この第13章が終わると、“pnpm install が重い”の最短ルートが手に入るよ 😆⚡️
次の第14章(pnpm fetch)は、CIでも速くしたい人向けの必殺技に繋がる!🔪✨