Edited at

Alpine Linux で Docker イメージを劇的に小さくする

More than 3 years have passed since last update.

Docker イメージを小さく作るテクニックって、いろいろありますよね。不要なファイルやディレクトリを削除したり、複数の RUN 命令をひとつにまとめたりなどなど。

ところが、ベースイメージに Alpine Linux を使う(FROM alpine とする)と、Docker イメージのサイズを 劇的に小さくできる ことがわかりました。

いままで、Docker イメージのサイズを小さくするために、ちまちまとやってきたことは、なんだったんだろうという感じです。まあ、それはそれで組み合わせて使いますが . . . なんとも . . . ねえ(笑)


Alpine Linux とは



  • Alpine Linux は、セキュアで軽量な Linux ディストリビューション


  • musl libcBusyBox をベースに構成されている

  • 組込み系に適した Linux ディストリビューション

  • パッケージ管理は、APK と呼ばれる独自のシステムを使用


実際どれくらい小さくなるのか

Ruby を組み込んだ「Ubuntu ベースの Docker イメージ」と「Alpine ベースの Docker イメージ」で、そのサイズを比較してみました。

Ubuntu ベース、Alpine ベースそれぞれの Dockerfile は、次のとおりです。


ubuntu-ruby.dockerfile

FROM ubuntu:xenial-20160525

RUN apt-get update && apt-get install -y ruby && rm -rf /var/lib/apt/lists/*


alpine-ruby.dockerfile

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 がインストールされるようです。より新しいバージョンをインストールしたい場合や、欲しいパッケージが用意されていない場合は、このソースからコンパイルしてインストールする方法が参考になるかと思います。)


alpine-nginx.dockerfile

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.2alpine:3.3NGINX_VERSION 1.9.7NGINX_VERSION 1.10.0

2016/06/04 変更: alpine:3.3alpine:3.4NGINX_VERSION 1.10.0NGINX_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 pulldocker pushdocker build も超高速です。これは、嬉しかったですね。

ただし、どのような Docker イメージにも適用できるかと問われると、なんとなくですが難しいケースも多々ある気がします。とはいえ、試して見る価値は、十分にあると思います。