1. asakaguchi

    Posted

    asakaguchi
Changes in title
+Alpine Linux で Docker イメージを劇的に小さくする
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,159 @@
+Docker イメージを小さく作るテクニックって、いろいろありますよね。不要なファイルやディレクトリを削除したり、複数の RUN 命令をひとつにまとめたりなどなど。
+
+ところが、ベースイメージに Alpine Linux を使う(`FROM alpine` とする)と、Docker イメージのサイズを **劇的に小さくできる** ことがわかりました。
+
+いままで、Docker イメージのサイズを小さくするために、ちまちまとやってきたことは、なんだったんだろうという感じです。まあ、それはそれで組み合わせて使いますが . . . なんとも . . . ねえ(笑)
+
+
+## Alpine Linux とは
+- [Alpine Linux](http://alpinelinux.org) は、セキュアで軽量な Linux ディストリビューション
+- [musl libc](http://www.musl-libc.org) と [BusyBox](http://www.busybox.net) をベースに構成されている
+- 組込み系に適した Linux ディストリビューション
+- パッケージ管理は、[APK](http://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management) と呼ばれる独自のシステムを使用
+
+
+## 実際どれくらい小さくなるのか
+Ruby を組み込んだ「Ubuntu ベースの Docker イメージ」と「Alpine ベースの Docker イメージ」で、そのサイズを比較してみました。
+
+Ubuntu ベース、Alpine ベースそれぞれの Dockerfile は、次のとおりです。
+
+```dockerfile:ubuntu-ruby.dockerfile
+FROM ubuntu
+RUN apt-get update && apt-get install -y ruby && rm -rf /var/lib/apt/lists/*
+```
+
+```dockerfile:alpine-ruby.dockerfile
+FROM alpine
+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 VIRTUAL SIZE
+ubuntu-ruby latest b8a544695602 27 minutes ago 205.2 MB
+alpine-ruby latest e4d3bd3fa20b 42 minutes ago 17.89 MB
+```
+
+なんと!!! Alpine Linux ベースの Docker イメージは、17.89MB に!!!
+Ubuntu ベースの Docker イメージは、205.2MB ですから、この差はデカイです!
+
+
+## この差はなにか
+ベースイメージを変えただけで、なぜ、こんなにも差が出るのでしょうか。
+
+まあ、答えは簡単ですよね。ベースイメージの大きさの差がそのまま結果に表れているということですね。
+
+ベースイメージでよく使われていると思われる Ubuntu、Debian および CentOS と Alpine で、その大きさを比較してみました。
+
+```
+REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
+debian latest a604b236bcde 12 days ago 125.1 MB
+ubuntu latest e9ae3c220b23 3 weeks ago 187.9 MB
+centos latest e9fa5d3a0d0e 7 weeks ago 172.3 MB
+alpine latest 8a648f689ddb 11 weeks ago 5.249 MB
+```
+
+Alpine のサイズは、驚きの 5.249MB !!!
+
+Ubuntu、Debian、CentOS がいずれも 100MB を超えているので、その差は本当に大きいですね。
+
+ただ、あまりの小ささに少し不安になりますよね。本当に大丈夫なのかと。なので、いくつかの Docker イメージを作って、試してみました。本格的に使用しているわけではありませんが、まずまずちゃんと動いているようです。
+
+そのいくつか試した中から、Nginx の例を載せておきます。参考にどうぞ。
+
+
+## Nginx サンプル
+パッケージのインストールは、[APK](http://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management) を使います。APK は、Alpine Linux のパッケージ管理システムです。APK は、同種の APT や Yum と同じような感じで使えます。次の Dockerfile のサンプルで、APK の使い方を確認してみましょう。
+
+なお、利用できるパッケージの一覧は、[Alpine Linux package index](https://pkgs.alpinelinux.org/packages) で確認できます。
+
+
+### Dockerfile
+ここでは、Nginx をソースからコンパイルしてインストールする方法を紹介します。APK は、Nginx ソースの入手と、コンパイル&インストールに必要なパッケージのインストールで使用しました。
+
+(APK で、Nginx をインストールすると、stable 版の v1.8.0 がインストールされるようです。より新しいバージョンをインストールしたい場合や、欲しいパッケージが用意されていない場合は、このソースからコンパイルしてインストールする方法が参考になるかと思います。)
+
+```dockerfile:alpine-nginx.dockerfile
+FROM alpine:3.2
+
+ENV NGINX_VERSION 1.9.7
+
+RUN apk add --update 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;"]
+```
+
+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 イメージにも適用できるかと問われると、なんとなくですが難しいケースも多々ある気がします。とはいえ、試して見る価値は、十分にあると思います。