Docker Multistage Buildのユースケース
Multistage Build機能により、Dockerfileを非常に簡潔に書くことができるようになりました。
感動したのでユースケースごとに嬉しい点をまとめておきます。
なお、この内容のメモを書いてからかなり時間が経っているので、すごく今更な記事になってしまいました。Multistage Buildは2017/05にリリースされたバージョンから使えるようですので、1年近く経ってますね……。
また、GCPの公式ブログでMultistage Buildについての記事も上がっています。計測などもあり興味深い記事となっていますので、ぜひ先にご参照ください。本記事のユースケース1を詳細に説明している内容です。
ユースケース1: イメージサイズを減らす
これはMultistage Buildを語る上で欠かせないメリットですね。成果物(と必要なライブラリ)をコピーする事により、ビルドだけに必要なプログラムや余計なレイヤーをイメージから除外することができます。
上記は多くのコンテナで共通のメリットですが、特にGo言語のプログラムでは威力が大きいです。なぜなら、Goのプログラムは1バイナリをコピーするだけで動くため、極めて軽量なイメージにできるからです。
それまでは実現できなかった、数MB程度のイメージにすることができます。
before
FROM alpine:latest as builder
...
// build as command
CMD command
数百MB〜
after
FROM ... as builder
...
// build as command
FROM ...
COPY --from=build command command
CMD command
数MB〜
ユースケース2: 開発環境だけで使うプログラム
ホットリロードツールやデバッガなど、開発環境では重宝しますがリリース時には使いたくないプログラムがあります。
Multistage Buildが無い場合、2つのDockerfileを用意する必要がありました( Dockerfile.dev
と Dockerfile.prod
など)。ビルドのための準備はそれぞれのファイルで同じなため、両方変更する必要がありメンテナンス性を下げる原因となっていました。
Multistage Buildを使うことにより、ビルドをするコードはそのまま、開発環境だけで使うプログラムをイメージから除外することが単一のDockerfileで可能になります。docker-comopseから使う場合の修正も軽微です。
個人的には、Multistage Buildの最も便利な使い方だと思います。
before
Dockerfile.dev
FROM ...
// ビルド用の準備
// ビルド
// ホットリロードツールのインストール
CMD hot-reload command
Dockerfile.prod
FROM ...
// ビルド用の準備
// ビルド
CMD command
after
FROM ... as builder
// ビルド用の準備
// ビルド
// ホットリロードツールのインストール
CMD hot-reload command
FROM ...
COPY --from=build command command
CMD command
ユースケース3: リファクタリング
上記の2つを実行した副産物ですが、各ステップの依存関係がわかりやすくなります。
例えば2つのプログラムをビルドし、その成果物を使ってプログラムを動かす場合を考えます(プラグインのビルド、ローカル証明書の作成などがそれぞれのステージ)。従来ではイメージサイズを減らすため、Dockerfileの1レイヤーでひたすらビルドをし、最後に実行としていました。
Multistage Buildにより、依存関係をそれぞれのステージに切り出すことができ、よりわかりやすいDockerfileになります。
before
FROM ...
RUN apk pre-cmd1 pre-cmd2 cmd3 ... && \
build cmd1 ... && \
cd ... && \
build cmd2 ... && \
...
CMD cmd1 cmd2
after
FROM ... as cmd1
RUN apk pre-cmd1 ... && \
build cmd1 ...
FROM ... as cmd2
RUN apk pre-cmd2 ... && \
build cmd2 ...
FROM ...
COPY --from=build cmd1 cmd1
COPY --from=build cmd2 cmd2
CMD cmd1 cmd2
まとめ
Multistage Buildは複雑なDockerfileをシンプルにすることができるとても便利な機能です。軽量で分かりやすいDockerfileを目指して有効活用してゆきましょう。