フリーキーズ | 独学プログラミング

Dockerのマルチステージビルドで軽量イメージを作る!初心者向けガイド

リンドくん

リンドくん

たなべ先生、Dockerでイメージを作ったら、すごく大きくなっちゃいました...

たなべ

たなべ

それ、よくあるんだよね。でもマルチステージビルドを使えば、イメージを10分の1くらいに小さくできるよ!

Dockerを使い始めると、コンテナイメージのサイズが大きくなりすぎて困ることがあります。
開発用のツールまで全部入れてしまうと、数GBになることも珍しくありません。

この問題を解決するのがマルチステージビルドです。
ビルドに必要なツールと、実行に必要なファイルを分けることで、イメージサイズを大幅に削減できます。

この記事では、マルチステージビルドの基本から実践的な使い方まで、初心者の方にもわかりやすく解説していきます。

プログラミング学習でお悩みの方へ

HackATAは、エンジニアを目指す方のためのプログラミング学習コーチングサービスです。 経験豊富な現役エンジニアがあなたの学習をサポートします。

✓ 質問し放題

✓ β版公開中(2025年内の特別割引)

HackATAの詳細を見る

マルチステージビルドとは

リンドくん

リンドくん

マルチステージビルドって、どういう仕組みなんですか?

たなべ

たなべ

簡単に言うと、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 ./dist

WORKDIRを考慮してパスを指定しましょう。

失敗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以下にできる
  • セキュリティも向上する

マルチステージビルドは、最初は難しく感じるかもしれませんが、基本を押さえれば誰でも使えます。ぜひ自分のプロジェクトで試してみてください。

この記事をシェア

関連するコンテンツ