はじめに
以下の記事にてコンテナイメージを作成する手法の一つとしてDockerfileを利用する方法について説明しました。
今回は、従来のDockerfileを利用した手法からDockerイメージのサイズを削減する機能であるmulti-stage buildについて解説します。主にライブラリ依存周りで利用されますが、もっとイメージしやすい簡単な例を用意しました。
想定ケース
例えばイメージに以下のように特定コマンド(今回はtree)の実行結果が欲しいとします。
$ tree / > /root/tree.txt
しかし初期イメージに入っていなければ、Dockerfileに以下のように書いてもコマンドがないため失敗します。
FROM ubuntu RUN tree / > /root/test.txt
よって以下のようにすることで必要コマンドがインストールでき
FROM ubuntu RUN apt-get update RUN apt-get install -y tree RUN tree / > /root/tree.txt
このDockerfileにて
$ docker build -t ubuntu/tree:1 .
treeの実行結果が格納されたイメージが作成できました。
想定ケースのイメージを削減する技がある
イメージのサイズを見ていきます。
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu/tree 1 XX XX 92.8MB ubuntu latest XX XX 64.2MB
当たり前ですがapt-getの分だけ元のイメージよりサイズが大きくなっています。
この例にて欲しいのはtreeコマンドの結果のみであった場合に、いわゆる冒頭でエラーとなった
FROM ubuntu RUN tree / > /root/test.txt
だけを実現した小さなイメージは作成できないのでしょうか?
それを実現するのがmulti stage buildです。
Multi Stage Buildのやり方
結論から言うとDockerfileに以下のように書きます。
FROM ubuntu as test RUN apt-get update RUN apt-get install -y tree RUN tree /root > /root/tree.txt FROM ubuntu COPY --from=test /root /root COPY --from=test /usr/bin/tree /usr/bin/tree
上で分かる通り、testという仮のイメージを作成しそこから/rootディレクトリだけをコピーしています。これがmulti-stage buildになります。
今回はついでにtreeコマンドもそのまま持ってきてみました。
それを実行すると以下のようになります。
$ docker build -t ubuntu/treeonly:1 . .... Successfully built ... Successfully tagged ubuntu/treeonly:1
確かにイメージファイルのサイズを確認すると
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu/treeonly 1 xyz XX 64.3MB ubuntu/tree XX XX 92.8MB ubuntu latest XX XX 64.2MB
かなり小さくなってます。
もちろんそのイメージからコンテナを起動すると、必要な結果ファイルは格納されておりtreeコマンドも利用できます。
$ docker run -t -i xyz root@xyz:~# ls /root/ tree.txt root@xyz:~# which tree /usr/bin/tree
終わりに
コンテナの起動速度はイメージの大きさに依存します。
例えばコンパイル前のファイルが巨大ではあるもののコンパイル後のファイルだけイメージにとり入れたい場合など、応用例は多い機能なので覚えておくとどこかで役立つと思います。
ご参考になれば幸いです。