リンドくんたなべ先生、Dockerでイメージを作ったら、すごく大きくなっちゃいました...
たなべそれ、よくあるんだよね。でもマルチステージビルドを使えば、イメージを10分の1くらいに小さくできるよ!
Dockerを使い始めると、コンテナイメージのサイズが大きくなりすぎて困ることがあります。
開発用のツールまで全部入れてしまうと、数GBになることも珍しくありません。
この問題を解決するのがマルチステージビルドです。
ビルドに必要なツールと、実行に必要なファイルを分けることで、イメージサイズを大幅に削減できます。
この記事では、マルチステージビルドの基本から実践的な使い方まで、初心者の方にもわかりやすく解説していきます。
マルチステージビルドとは
リンドくんマルチステージビルドって、どういう仕組みなんですか?
たなべ簡単に言うと、1つのDockerfileの中で複数の工程を分ける仕組みだよ。
最初の工程でビルドして、次の工程では実行に必要なファイルだけをコピーするんだ。
基本的な考え方
マルチステージビルドは、Dockerfileの中で複数のFROM命令を使う方法です。
- ビルドステージ → コンパイルやビルドを実行する
- 実行ステージ → ビルド結果だけをコピーして軽量なイメージを作る
これにより、最終的なイメージには実行に必要な最小限のファイルだけが含まれます。
なぜ必要なのか
マルチステージビルドを使うメリットはこちらです。
- イメージサイズの削減 → 数百MBから数GBの削減が可能
- セキュリティ向上 → ビルドツールを本番イメージから除外できる
- デプロイの高速化 → イメージが小さいので転送が速い
特にクラウド環境では、イメージが小さいほどコストも時間も節約できます。
基本的なマルチステージビルドの書き方
リンドくん実際にはどう書けばいいんですか?
たなべまずは一番シンプルな例から見てみようか。
Go言語での例
# ===== ビルド用 =====
FROM golang:1.25 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# ===== 実行用 =====
FROM alpine:latest
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]ポイントは以下の3つです。
- AS builder → 最初のステージに名前をつける
- COPY --from=builder → 前のステージからファイルをコピー
- alpine:latest → 軽量なベースイメージを使う(約5MB)
Node.jsでの例
# ===== ビルド用 =====
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ===== 実行用 =====
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]Node.jsの場合は、開発用の依存関係を除外して、ビルド済みファイルだけをコピーします。
Pythonでの例
# ===== ビルド用 =====
FROM python:3.14 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
# ===== 実行用 =====
FROM python:3.14-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]イメージサイズの比較
実際にどれくらいサイズが変わるか見てみましょう。
従来の方法
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/index.js"]イメージサイズ: 約1.2GB
マルチステージビルド
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]イメージサイズ: 約120MB
10分の1以下になりました!
よくある失敗と対処法
失敗1 パスの指定ミス
# 間違い
COPY --from=builder /dist ./dist
# 正しい
COPY --from=builder /app/dist ./distWORKDIRを考慮してパスを指定しましょう。
失敗2 依存関係の不足
# 問題あり
FROM scratch
COPY --from=builder /app/myapp .
# 改善版
FROM alpine:latest
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/myapp .実行に必要なライブラリを忘れずに。
失敗3 キャッシュが効かない
# 非効率
COPY . .
RUN npm ci
# 効率的
COPY package*.json ./
RUN npm ci
COPY . .変更の少ないファイルを先にコピーすると、キャッシュが効きやすくなります。
まとめ
リンドくん意外とシンプルですね!早速試してみます!
たなべそうだね!まずは2ステージから始めて、慣れてきたら最適化していくといいよ。
マルチステージビルドを使えば、Dockerイメージを大幅に軽量化できます。
重要なポイントをおさらいしましょう。
- 1つのDockerfileで複数のステージを使い分ける
- ビルド用と実行用でイメージを分ける
- イメージサイズを10分の1以下にできる
- セキュリティも向上する
マルチステージビルドは、最初は難しく感じるかもしれませんが、基本を押さえれば誰でも使えます。ぜひ自分のプロジェクトで試してみてください。





