Dockerfile マルチステージビルド入門

はじめに

Docker を使った開発に慣れてくると、多くの人が次のような壁にぶつかります。

  • Dockerfile は書けるが、イメージサイズが異常に大きい
  • 本番環境に「本当に必要なのか分からないツール」が大量に入っている
  • セキュリティレビューで Dockerfile を指摘される
  • CI/CD のビルド時間がどんどん長くなっていく

これらの問題は、Docker の使い方が間違っているというより、Dockerfile の設計が「開発止まり」になっていることが原因です。

そこで登場するのが
Dockerfile のマルチステージビルド(Multi-stage Build) です。

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

  • Docker イメージの軽量化
  • セキュリティリスクの低減
  • 本番運用に耐える Dockerfile 設計
  • CI/CD の効率改善

を同時に実現できる、実務レベルでは必須のテクニックです。

この記事では、
「なぜマルチステージビルドが必要なのか」から始め、
仕組み・書き方・ハンズオン・アンチパターンまでを網羅的に解説します。


マルチステージビルドとは何か?

マルチステージビルドとは、
1つの Dockerfile の中で複数の FROM を使い、役割の異なるビルド工程を分離する仕組みです。

FROM node:20 AS build
# ビルド専用ステージ

FROM node:20-alpine
# 実行専用ステージ

Dockerfile を読むときのポイントはシンプルです。

  • 最初のステージ:
    ビルド・コンパイル・テストなど「作るための環境」
  • 最後のステージ:
    本番で実行するための「最小限の環境」

最終的な Docker イメージには、最後のステージしか含まれません。

この性質が、軽量化・セキュリティ・可読性のすべてにつながります。


なぜ通常の Dockerfile では不十分なのか?

単一ステージ Dockerfile の典型例

FROM node:20

WORKDIR /app
COPY . .
RUN npm install
RUN npm run build

CMD ["node", "dist/index.js"]

一見すると、特に問題はなさそうに見えます。
実際、多くのチュートリアルはこの形で紹介されています。

しかし、この Dockerfile には次のような課題があります。

問題点①:不要なツールが残る

  • npm
  • 開発用ライブラリ(devDependencies)
  • ビルド用スクリプト

これらは 本番実行には不要 です。


問題点②:イメージサイズが大きくなる

  • ソースコード
  • テストコード
  • 設定ファイル

すべてが最終イメージに含まれます。


問題点③:セキュリティリスクが増える

  • 攻撃対象領域が広がる
  • 脆弱性を含むパッケージが残る

「動く Dockerfile」と「安全な Dockerfile」は別物です。


マルチステージビルドで何が改善されるのか?

マルチステージビルドを使うと、Dockerfile の役割が明確になります。

Before(単一ステージ)

  • イメージサイズ:大
  • 不要なファイル:多い
  • セキュリティ:低
  • 本番適性:△

After(マルチステージ)

  • イメージサイズ:小
  • 不要なファイル:ほぼゼロ
  • セキュリティ:高
  • 本番適性:◎

「開発用」と「実行用」を分離するだけで、品質が大きく変わる
これがマルチステージビルドの本質です。


マルチステージビルドの基本構文

FROM node:20 AS build
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build

FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
CMD ["node", "dist/index.js"]

構文のポイント解説

  • AS build
    → ステージに名前を付ける
  • --from=build
    → 指定したステージから必要なファイルだけコピー
  • 最終ステージのみが実行対象

Dockerfile が 「工程ごとの設計書」 のように読めるようになります。


ハンズオン①:単一ステージ Dockerfile を体験する

サンプルアプリ構成

app/
├─ Dockerfile
├─ package.json
├─ src/
│  └─ index.js

Dockerfile(単一ステージ)

FROM node:20
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/index.js"]

ビルド

docker build -t app-single .
docker images

ここで確認してほしいのは イメージサイズ です。
多くの場合、数百MBになることも珍しくありません。


ハンズオン②:マルチステージビルドへ改善する

Dockerfile(マルチステージ)

# ===== Build Stage =====
FROM node:20 AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# ===== Runtime Stage =====
FROM node:20-alpine
WORKDIR /app
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/index.js"]

再ビルド

docker build -t app-multistage .
docker images

イメージサイズが大幅に小さくなっている
この差が、そのまま運用コストとリスクの差になります。


マルチステージビルドとセキュリティの関係

マルチステージビルドは、単なる軽量化テクニックではありません。

セキュリティが向上する理由

  • ビルドツールが本番に存在しない
  • 不要なファイルが存在しない
  • 攻撃に使えるコマンドが少ない

さらに、

USER node

を組み合わせることで、
侵入されても被害を最小限に抑える構成になります。


よくあるアンチパターン

すべてをコピーしてしまう

COPY --from=build /app /app

→ 不要なファイルまで含まれる


最終ステージで再インストール

RUN npm install

→ マルチステージの意味が消える


マルチステージビルドが特に効果的なケース

  • Node.js / フロントエンドビルド
  • Go / Rust のバイナリ生成
  • Java(Maven / Gradle)
  • CI/CD パイプライン

「ビルド工程があるアプリケーション」では、ほぼ必須です。


まとめ

Dockerfile のマルチステージビルドは、

  • 軽量化
  • セキュリティ強化
  • 本番運用への適応

を同時に実現する、実務で避けて通れない技術です。

「とりあえず動く Dockerfile」から
「本番で安心して使える Dockerfile」へ

その境界線が、マルチステージビルドです。


投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です