はじめに
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」へ
その境界線が、マルチステージビルドです。
コメントを残す