Docker イメージを小さく作るテクニックって、いろいろありますよね。不要なファイルやディレクトリを削除したり、複数の RUN 命令をひとつにまとめたりなどなど。
ところが、ベースイメージに Alpine Linux を使う(FROM alpine
とする)と、Docker イメージのサイズを 劇的に小さくできる ことがわかりました。
いままで、Docker イメージのサイズを小さくするために、ちまちまとやってきたことは、なんだったんだろうという感じです。まあ、それはそれで組み合わせて使いますが . . . なんとも . . . ねえ(笑)
Alpine Linux とは
- Alpine Linux は、セキュアで軽量な Linux ディストリビューション
- musl libc と BusyBox をベースに構成されている
- 組込み系に適した Linux ディストリビューション
- パッケージ管理は、APK と呼ばれる独自のシステムを使用
実際どれくらい小さくなるのか
Ruby を組み込んだ「Ubuntu ベースの Docker イメージ」と「Alpine ベースの Docker イメージ」で、そのサイズを比較してみました。
Ubuntu ベース、Alpine ベースそれぞれの Dockerfile は、次のとおりです。
FROM ubuntu:xenial-20160525
RUN apt-get update && apt-get install -y ruby && rm -rf /var/lib/apt/lists/*
FROM alpine:3.4
RUN apk --update add ruby && rm -rf /var/cache/apk/*
これを、次のコマンドで、それぞれビルドします。
docker build -f ubuntu-ruby.dockerfile -t ubuntu-ruby .
docker build -f alpine-ruby.dockerfile -t alpine-ruby .
ちゃんと動くか動作を確認しておきます。
docker run --rm ubuntu-ruby ruby -e 'puts "hello, world"'
docker run --rm alpine-ruby ruby -e 'puts "hello, world"'
それぞれ、hello, world と表示されれば、OK です(というか、表示されます)。
docker images
コマンドで、サイズを確認すると . . .
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine-ruby latest 1ac582156fbc 28 seconds ago 20.39 MB
ubuntu-ruby latest b90dadde262c 50 seconds ago 156.9 MB
なんと!!! Alpine Linux ベースの Docker イメージは、20.39MB に!!!
Ubuntu ベースの Docker イメージは、156.9MB ですから、この差はデカイです!
この差はなにか
ベースイメージを変えただけで、なぜ、こんなにも差が出るのでしょうか。
まあ、答えは簡単ですよね。ベースイメージの大きさの差がそのまま結果に表れているということですね。
ベースイメージでよく使われていると思われる Ubuntu、Debian および CentOS と Alpine で、その大きさを比較してみました(2016/06/04 時点)。
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine 3.4 f70c828098f5 32 hours ago 4.799 MB
centos 7 904d6c400333 34 hours ago 196.8 MB
ubuntu xenial-20160525 2fa927b5cdd3 7 days ago 122 MB
debian 8.4 1742affe03b5 11 days ago 125.1 MB
Alpine のサイズは、驚きの 4.799MB !!!
Ubuntu、Debian、CentOS がいずれも 100MB を超えているので、その差は本当に大きいですね。
ただ、あまりの小ささに少し不安になりますよね。本当に大丈夫なのかと。なので、いくつかの Docker イメージを作って、試してみました。本格的に使用しているわけではありませんが、まずまずちゃんと動いているようです。
そのいくつか試した中から、Nginx の例を載せておきます。参考にどうぞ。
Nginx サンプル
パッケージのインストールは、APK を使います。APK は、Alpine Linux のパッケージ管理システムです。APK は、同種の APT や Yum と同じような感じで使えます。次の Dockerfile のサンプルで、APK の使い方を確認してみましょう。
なお、利用できるパッケージの一覧は、Alpine Linux package index で確認できます。
Dockerfile
ここでは、Nginx をソースからコンパイルしてインストールする方法を紹介します。APK は、Nginx ソースの入手と、コンパイル&インストールに必要なパッケージのインストールで使用しました。
(APK で、Nginx をインストールすると、stable 版の v1.8.0 がインストールされるようです。より新しいバージョンをインストールしたい場合や、欲しいパッケージが用意されていない場合は、このソースからコンパイルしてインストールする方法が参考になるかと思います。)
FROM alpine:3.4
ENV NGINX_VERSION 1.11.1
RUN apk --update add pcre-dev openssl-dev \
&& apk add --virtual build-dependencies build-base curl \
&& curl -SLO http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz \
&& tar xzvf nginx-${NGINX_VERSION}.tar.gz \
&& cd nginx-${NGINX_VERSION} \
&& ./configure \
--with-http_ssl_module \
--with-http_gzip_static_module \
--prefix=/usr/share/nginx \
--sbin-path=/usr/local/sbin/nginx \
--conf-path=/etc/nginx/conf/nginx.conf \
--pid-path=/var/run/nginx.pid \
--http-log-path=/var/log/nginx/access.log \
--error-log-path=/var/log/nginx/error.log \
&& make \
&& make install \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
&& cd / \
&& apk del build-dependencies \
&& rm -rf \
nginx-${NGINX_VERSION} \
nginx-${NGINX_VERSION}.tar.gz \
/var/cache/apk/*
VOLUME ["/var/cache/nginx"]
EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]
※2016/05/22 変更: alpine:3.2
→ alpine:3.3
、NGINX_VERSION 1.9.7
→ NGINX_VERSION 1.10.0
※2016/06/04 変更: alpine:3.3
→ alpine:3.4
、NGINX_VERSION 1.10.0
→ NGINX_VERSION 1.11.1
APK コマンドの解説:
-
apk add
: 指定したパッケージをインストールします。-
--update
オプション: パッケージリストを更新します。最初のapk add
時に必要です。 -
--virtual
オプション: インストールするパッケージ群に名前をつけます。apk del
で使用します。
この例では、build-base と curl をひとつのグループとして扱い、build-dependencies と命名しました。
-
-
apk del
: 指定したパッケージをアンインストールします。
この例では、apk add
の--virtual
オプションで命名した build-dependencies を指定しました。これにより、build-dependencies に紐付いた build-base と curl をアンインストールします。
使い方の例
どこか適当なディレクトリで、上記 Dockerfile を alpine-nginx.dockerfile というファイル名で保存して、次のコマンンドを実行します。最後に、'hello, world' と表示されれば成功です。
docker build -f alpine-nginx.dockerfile -t nginx .
echo 'hello, world' > index.html
docker run -d -p 8080:80 -v $(pwd):/usr/share/nginx/html nginx
curl http://$(docker-machine ip default):8080
なお、Linux 環境の場合は、最後の curl コマンドは、curl http://localhost:8080
に読み替えてください。
まとめ
作成する Docker イメージのベースイメージに、Alpine Linux を指定すると、Docker イメージのサイズを劇的に小さくできることがわかりました。
これは、試していて実感したのですが、Docker イメージのサイズが小さいと、docker pull
も docker push
も docker build
も超高速です。これは、嬉しかったですね。
ただし、どのような Docker イメージにも適用できるかと問われると、なんとなくですが難しいケースも多々ある気がします。とはいえ、試して見る価値は、十分にあると思います。