1. 導入:なぜマルチステージビルドが重要なのか
現代のDevOpsにおいて、Dockerイメージの軽量化は単なる「節約」以上の意味を持ちます。イメージサイズが小さければデプロイ時の転送時間が短縮され、CI/CDのパイプラインは高速化します。また、ビルドツールやソースコードを含まない「実行専用」のイメージを作ることで、攻撃対象領域(アタックサーフェス)を最小限に抑え、セキュリティリスクを大幅に低減できます。本記事では、この必須テクニックであるマルチステージビルドを解説します。
2. 基礎知識:マルチステージビルドとは
マルチステージビルドとは、1つのDockerfile内で複数の「FROM」命令を使用する手法です。従来はビルド用コンテナと実行用コンテナを別々に管理する必要がありましたが、この手法を使えば、1つのDockerfileだけで「ビルドステージ」と「実行ステージ」を完結できます。これにより、ビルドに必要なコンパイラやライブラリを最終イメージに含めることなく、必要なバイナリや静的ファイルだけを次のステージへ引き継ぐことが可能になります。
3. 実装/解決策
実装のポイントは「AS」キーワードを使ってビルドステージに名前を付けることです。これにより、後続のステージからビルド成果物だけをピンポイントでコピー(COPY –from)できます。このプロセスにより、数GBあったイメージを数十MBまで削減することも珍しくありません。
4. サンプルプログラム:Go言語での実装例
以下は、Go言語のアプリケーションをマルチステージビルドで構築する実用的なDockerfileです。
ビルド用ステージ: 名前を「builder」と定義
FROM golang:1.21-alpine AS builder
作業ディレクトリの設定
WORKDIR /app
依存関係のダウンロード(キャッシュ効率を考慮)
COPY go.mod go.sum ./
RUN go mod download
ソースコードをコピーしてビルド実行
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o my-app .
実行用ステージ: 非常に軽量なscratch(またはalpine)を使用
FROM alpine:latest
ビルドステージからバイナリのみをコピー
COPY –from=builder /app/my-app /usr/local/bin/my-app
実行権限の付与と起動コマンド
RUN chmod +x /usr/local/bin/my-app
ENTRYPOINT [“my-app”]
5. 応用・注意点:現場で陥りやすい罠
実務で活用する際は、以下の点に注意してください。
キャッシュの活用順序: COPY命令は、変更頻度の低いファイル(go.modやpackage.jsonなど)を先に記述し、変更頻度の高いソースコードを後に記述することで、ビルドキャッシュを最大限に活用できます。
ライブラリの依存関係: CGOを使用する場合、動的リンクが必要なライブラリが実行用イメージに不足していると起動時にエラーになります。その場合は、ビルド時に「CGO_ENABLED=0」を指定して静的リンクにするか、実行用イメージにも必要な共有ライブラリをインストールしてください。
セキュリティの更なる向上: 実行ユーザーをrootから特定の一般ユーザーに変更する(USER命令の使用)ことで、万が一コンテナが乗っ取られた際の被害を最小化できます。これらを組み合わせることで、堅牢かつ軽量なコンテナ環境が構築可能です。

コメント