第45章:RUN(依存インストールの基本)📥
(Todo API を Dockerfile で動かすための “依存インストール回” だよ!😆)
この章のゴール🏁
- Dockerfile の
RUNが「ビルド中に実行されて、レイヤー(キャッシュ)になる」感覚をつかむ🧠✨ - Node/TS の依存を 速く・再現性高く 入れられるようになる(=
npm ciを使いこなす)🚀 - 「なぜ毎回依存の再DLが起きるの?」を卒業する🧯🙂
1) RUN って何者?🤔⚙️
RUN は イメージを作る最中(docker build中)に コマンドを実行する命令だよ💡
しかも RUN の結果は レイヤーとして保存されて、次回ビルドのキャッシュになるのが超重要!🔥
RUN:ビルド時に実行(依存インストール、ビルド、OSパッケージ追加など)🧱CMD:コンテナ起動時に実行(起動コマンド)▶️(これは次章でやる!)
2) まず “正しい型” を覚える:依存は 先に 入れる📦➡️
Dockerfileの依存インストールで一番効くコツはこれ👇
✅ 依存ファイル(package.json / lock)だけ先にCOPY
✅ そこで npm ci してキャッシュを効かせる
✅ 最後にソースコードをCOPY
こうすると「コードだけ変えた」ビルドで、依存が再インストールされにくくなる🎉
(Docker公式ブログでも、package*.json を先にCOPYして npm ci のレイヤーをキャッシュに乗せる流れが紹介されてるよ)(Docker)
3) npm install じゃなくて npm ci を使う理由🧪✅
結論:Dockerビルドでは npm ci が強い💪✨
npm ci はこんな性質👇
package-lock.json(またはshrinkwrap)が必須(docs.npmjs.com)- lock と package.json がズレてると 失敗して止まる(勝手に直さない)(docs.npmjs.com)
- 既存の
node_modulesがあれば 消してからクリーンに入れ直す(docs.npmjs.com)
つまり、毎回“同じ依存”を入れやすい=Docker向き🥳
4) ハンズオン:Todo API 用 Dockerfile(依存インストールの基本形)🛠️🐣
✅ いちばん素直な例(npm + lockfile)
## syntax=docker/dockerfile:1
FROM node:22-slim
WORKDIR /app
## 1) 依存ファイルだけ先に入れる(ここがキャッシュの要)
COPY package.json package-lock.json ./
## 2) 依存インストール(再現性優先)
RUN npm ci
## 3) その後でソースを入れる
COPY . .
## (CMDは次章で詳しく!ここでは仮)
CMD ["npm", "run", "dev"]
ポイントは # syntax=... の1行!
これを入れると BuildKit が 最新安定の Dockerfile 構文を使ってくれる(後で出てくる RUN --mount=... も安定しやすい)(Docker Documentation)
5) ビルド爆速化:BuildKit のキャッシュマウントを使う⚡🧠
依存のDL(npmが落としてくるキャッシュ)を、ビルド間で使い回すと体感が変わるよ😳✨
Dockerfile では RUN --mount=type=cache が使える!(Docker Documentation)
✅ npm のダウンロードキャッシュを残す例
## syntax=docker/dockerfile:1
FROM node:22-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
npm ci
COPY . .
CMD ["npm", "run", "dev"]
target=/root/.npmは npm のキャッシュ置き場(DLしたtgz等)- 「毎回ネットから取り直す」を減らせるから速い🏎️💨 (キャッシュ最適化の考え方自体も Docker Docs にまとまってるよ)(Docker Documentation)
6) devDependencies どうする?(本番だけ軽くしたい時)🎭📦
「本番イメージは devDependencies いらん!」ってなるよね🙂
npm には “dev を省く” --omit=dev があるよ(npm docsに omit の説明あり)(docs.npmjs.com)
✅ 本番向けの依存だけ入れる
RUN --mount=type=cache,target=/root/.npm \
npm ci --omit=dev
⚠️ただし注意:TSのビルドやlintをコンテナ内でやる設計なら、ビルド段階では devDependencies が必要になりがち。 ここは次章以降の「開発用と本番用を分ける」回でキレイに整理できるよ😉🎯(Dockerのマルチステージ推奨もその流れで効いてくる)(Docker Documentation)
7) よくある失敗あるある🪤😵💫 → 即効で直す
あるある①:npm ci が「lockfile無いよ!」って怒る😢
原因:package-lock.json が無い(またはコミットされてない)
対処:ローカルで一度 npm install して lock を作り、lockも一緒に管理しよう✅
(npm ci は lockfile 前提)(docs.npmjs.com)
あるある②:npm ci が「package.json と lock がズレてる!」で落ちる💥
原因:誰かが package.json だけ変えて lock を更新してない、など
対処:ローカルで npm install して lock を同期 → その結果をコミット✅
(ズレてたら npm ci はエラーで止まる仕様)(docs.npmjs.com)
あるある③:ネイティブ依存(node-gyp系)でビルド失敗🤯🔧
症状:g++ とか make とか言い出す
対処:OSパッケージを RUN apt-get ... で入れる(必要な時だけ!)
BuildKitのキャッシュマウントは apt にも使えるよ🧊(Docker Documentation)
例(必要なときだけね!)👇
## syntax=docker/dockerfile:1
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && apt-get install -y --no-install-recommends \
python3 make g++ \
&& rm -rf /var/lib/apt/lists/*
8) 章末ミッション(手を動かそう)🕹️🔥
ミッションA:依存キャッシュが効いてるか確認👀
- Dockerfile をこの章の形にする✍️
- ビルドする(例)
docker build -t todo-api:run45 .
- もう一回ビルドする(速くなるのが理想⚡)
srcの中身だけ少し変えてビルド → 依存のステップがキャッシュされてるか確認🎯
9) AI活用(この章に効くやつ)🤖✨
- 「このDockerfileでキャッシュが効かない原因トップ3を挙げて、修正案も出して」🧠
- 「
npm ciのエラー文貼る→原因と直し方を “初心者向けに3行で”」🧯 - 「Todo APIの依存を本番向けに削るなら、dev/prod分離の作戦を2案」🎭
まとめ🎉
RUNは ビルド時に実行され、レイヤーになって キャッシュが命🧱- 依存は
COPY package*.json→RUN npm ciの形が基本形✅(Docker) - さらに速くするなら
RUN --mount=type=cache(BuildKit)でDLキャッシュを使う⚡(Docker Documentation) - 本番だけ軽くしたいなら
npm ci --omit=devも選べる📦(docs.npmjs.com)
次は第46章で CMD をちゃんと理解して「起動コマンド設計」に入ろうね▶️😆