Dockerの登場によって「ビルド」の再考が求められている
2013年3月に登場したDockerによって、IaaS,PaaS, Linuxディストリビューション、プロビジョニングツール、など様々なものが、役割の再定義を迫られています。
コンパイル・ビルドという行為もまたその1つです。
伝統的な./configure && make && make installというお作法はDocker登場以前に考えられた方法なので、Docker Imageを構築する場合にいろいろ非効率なことがあります。
例えばファイルサイズです。
Docker Imageはレイヤーを重ねて構築されるので、ベースとなるイメージのサイズが大きいと、そこから派生する全てのイメージが肥大化してしまいます。
伝統的ビルド手法は、コンパイル時間の短縮や生成されたバイナリの実行速度向上に注力されることはあっても、生成物のファイルサイズにはわりと無頓着なことが多いのではないでしょうか。(make cleanがなかったり、あったとしてもmake cleanで不要なものが全部消えるわけではない)
今後ソフトウェアの配信方法としてDocker Image(またはその代替品)が主流になってくれば、ビルドは誰かが1回やったものを使い回せばよいので、ビルド時間よりも生成物のファイルサイズの方が重要になってくるかもしれません。
今まで全く意識されてこなかった「ビルド結果を小さくするノウハウ」が求められる時代が来ました。
では具体例をあげて、どうやってサイズを小さくするか考えてみましょう。
例:Perlをビルドしてみる
perlをビルドする素朴な例を考えてみました。
- Perl-Buildを使ってperlをビルド
- cpanmをインストール
- cartonをインストール
Dockerfileはこんな感じになるかと思います。
FROM centos:centos6
MAINTAINER DQNEO
# install required packages
RUN yum -y update; yum clean all
RUN yum -y install perl tar bzip2 gcc make; yum clean all
# install perl
RUN curl --silent https://raw.githubusercontent.com/tokuhirom/Perl-Build/master/perl-build | perl - 5.20.1 /opt/perl
# install cpanm
RUN curl -L http://cpanmin.us | /opt/perl/bin/perl - App::cpanminus
# install carton
RUN /opt/perl/bin/cpanm Carton
# show perl version
CMD /opt/perl/bin/perl -v
ごくごく普通のビルド手順だと思いますが、この方法でビルドするとImageサイズが401MBになります。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
dqneo/perl 0 42a948187215 30 minutes ago 401.2 MB
centos centos6 25c5298b1a36 7 days ago 215.8 MB
ビルド時に不要ファイルを削減してみる
さて、今度はビルド時にRUNの末尾で不要ファイルの削除をやってみましょう。
具体的には、manとか一時ファイルを削除します。
FROM centos:centos6
MAINTAINER DQNEO
# install required packages
RUN yum -y update; yum clean all
RUN yum -y install perl tar bzip2 gcc make; yum clean all
# install perl
RUN (curl --silent https://raw.githubusercontent.com/tokuhirom/Perl-Build/master/perl-build | perl - 5.20.1 /opt/perl ) \
&& rm -rf /opt/perl/man/
# install cpanm
RUN (curl -L http://cpanmin.us | /opt/perl/bin/perl - App::cpanminus) \
&& rm -rf /root/.cpanm/work/*
# install carton
RUN /opt/perl/bin/cpanm Carton \
&& rm -rf /root/.cpanm/work/*
# show perl version
CMD /opt/perl/bin/perl -v
docker buildして、生成物のサイズを見てみましょう。
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
dqneo/perl 1 5221cef3751e About a minute ago 372 MB
dqneo/perl 0 42a948187215 30 minutes ago 401.2 MB
centos centos6 25c5298b1a36 7 days ago 215.8 MB
イメージサイズが372MBに縮まりました。
rmコマンドを3回書くだけで20MB減リました。
もっとがんばってみる
さらに、perl-buildを使わずに素のtarballからの./Configure && make && make instalしてみます。
FROM centos:centos6
MAINTAINER DQNEO
# install required packages
RUN yum -y update; yum clean all
RUN yum -y install tar bzip2 gcc make; yum clean all
RUN mkdir /usr/src/perl
WORKDIR /usr/src/perl
RUN curl -SL https://cpan.metacpan.org/authors/id/S/SH/SHAY/perl-5.20.1.tar.bz2 -o perl-5.20.1.tar.bz2 \
&& tar --strip-components=1 -xjf perl-5.20.1.tar.bz2 -C /usr/src/perl \
&& rm perl-5.20.1.tar.bz2 \
&&./Configure -Dprefix=/opt/perl -Duse64bitall -des \
&& make -j$(nproc) \
# && TEST_JOBS=$(nproc) make test_harness \
&& make install \
&& make veryclean \
&& rm -rf /opt/perl/man \
&& rm -rf /usr/src/perl
# install cpanm
RUN (curl -L http://cpanmin.us | /opt/perl/bin/perl - App::cpanminus) \
&& rm -rf /root/.cpanm/work/*
# install carton
RUN /opt/perl/bin/cpanm Carton \
&& rm -rf /root/.cpanm/work/*
WORKDIR /root
CMD ["/opt/perl/bin/perl","-v"]
結果
$ docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
dqneo/perl 2 b598201ae1e0 About a minute ago 337.3 MB
今度は337MBになりました。
最初の素朴な例から、実に63MB削減できました。
これはやる意味のあることなの?バッドノウハウでは?
議論の分かれるところだと思いますが、
この程度のhackならやってもいいんじゃないかと思います。
この程度で可読性が損なわれるとは思いません。
ソフトウェアによっては、ドキュメントのサイズが大きい場合もあり、その場合は削除の効果が大きいでしょう。
不要なものを消すにはそのソフトウェアのビルドの内部動作を多少知っている必要があるので、逆に勉強になるというメリットもあります。
まとめ
いろんなものを小さくビルドするノウハウを共有しましょう!
参考
今回作ったDockerfile
https://github.com/DQNEO/docker-perl
Dockerイメージの最適化
http://wazanova.jp/items/1454