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

  • 368
    いいね
  • 0
    コメント

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 イメージにも適用できるかと問われると、なんとなくですが難しいケースも多々ある気がします。とはいえ、試して見る価値は、十分にあると思います。