マルチステージ build とは?より小さいイメージ、よりクリーンな出力
マルチステージ build は使い捨ての stage でコンパイルし、完成した artifact だけを小さな最終 stage にコピーします - そのためイメージは toolchain ではなく出力を出荷します。
build ツール、コンパイラ、dev 依存関係は artifact を生成するのに必要ですが、それを実行するのには不要です。マルチステージ Dockerfile では、重い builder stage を使ってから、出荷するものだけを含む新しく最小限の最終 stage を開始できます。その結果、劇的に小さく安全なイメージが得られます。
中心となる考え方
1 つの Dockerfile に複数の FROM stage を宣言します。前段の stage が重労働を行い、最終 stage はクリーンに始まり COPY --from=<stage> でコンパイル済みの出力だけを引き込みます。前段の stage に残されたものはすべて破棄されます。
Go の例
stage 1:
FROM golang:1.22 AS build
WORKDIR /src
COPY . .
RUN go build -o app .
stage 2:
FROM gcr.io/distroless/static
COPY --from=build /src/app /app
ENTRYPOINT ["/app"]
最終イメージにはバイナリだけがあり、他には何もありません。
なぜイメージがこれほど小さくなるのか
Go の toolchain イメージは数百メガバイトですが、最終的な distroless イメージは数メガバイトです。COPY --from の artifact だけが最終 stage に着地するため、その build の重さはすべて決して出荷されません。
その他の利点
- パッケージが少ないことは、実行中のイメージの脆弱性が少ないことを意味します。
- build 中に使う secret は builder stage に留めておけます。
- 1 つのファイルから複数の最終 stage(例: test と prod)をターゲットにできます。
CI におけるマルチステージ build
マルチステージ build は各 stage をキャッシュするため、変更のない builder ステップはスキップされます。キャッシュが温まったマネージド runner では、高コストなコンパイル stage が job 間で再利用され、最終コピーだけが再実行されます。
重要なポイント
- マルチステージ build は build ツールを最終イメージから締め出します。
- COPY --from は完成した artifact だけをクリーンな最終 stage に引き込みます。
- 結果は toolchain の重さのない、はるかに小さく安全なイメージです。