Alpine LinuxでDockerコンテナ開発を加速する

docker

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。 Docker公式のベースイメージをAlpine LinuxにするPRによって、にわかにAlpine Linuxへの注目が集まっていますね。

いつか来るかも知れない(笑)Alpine Linux必須の時代に備えるべく、DockerでAlpine Linuxをどう扱っていくのかまとめてみました。

Alpine Linux概要

Alpine Linuxは、軽量なLinuxディストリビューションの一つです。最新バージョンは、3.3(2016/02/12現在)です。特にDocker向けというわけではないのですが、ベースイメージのフットプリントのサイズが非常に小さいことと、独自のパッケージ管理システムAPKがDockerfileの記法とマッチすることからDocker界隈で注目されているようです。

ベースDockerイメージはDocker公式版とGliderLabs版の2種類

現在利用できるAlpine LinuxのDockerベースイメージには、プレフィックス名なしのDocker公式版alpineとGliderLabs版のgliderlabs/alpineの2種類があります。ドキュメントによると、差異は以下2点とのことです。

  • AlpineのパッケージミラーがFastly CDNでホストされ、世界中からスピーディーにインストールを実行できる。
  • apk-installスクリプトが利用できる(後述)

試しに以下のDockerfileでどれくらい時間差が出るか、検証してみました。

FROM alpine:3.3 # 2回目はgliderlabs/alpine:3.3に変更
RUN apk --no-cache add nodejs
$ time docker build -t takipone/alpine-node .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM alpine:3.3
 ---> 14f89d0e6257
Step 2 : RUN apk --no-cache add nodejs
 ---> Running in 05e174d8076b
fetch http://dl-4.alpinelinux.org/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://dl-4.alpinelinux.org/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
(1/4) Installing libgcc (5.3.0-r0)
(2/4) Installing libstdc++ (5.3.0-r0)
(3/4) Installing libuv (1.7.5-r0)
(4/4) Installing nodejs (4.2.4-r1)
Executing busybox-1.24.1-r7.trigger
OK: 29 MiB in 15 packages
 ---> f66fb1d769d8
Removing intermediate container 05e174d8076b
Successfully built f66fb1d769d8

real	1m56.365s
user	0m0.023s
sys	0m0.026s
$
$ time docker build -t takipone/alpine-node .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM gliderlabs/alpine:3.3
 ---> 169fc2bfcef7
Step 2 : RUN apk --no-cache add nodejs
 ---> Running in 4dabb895e0b1
fetch http://alpine.gliderlabs.com/alpine/v3.3/main/x86_64/APKINDEX.tar.gz
fetch http://alpine.gliderlabs.com/alpine/v3.3/community/x86_64/APKINDEX.tar.gz
(1/4) Installing libgcc (5.3.0-r0)
(2/4) Installing libstdc++ (5.3.0-r0)
(3/4) Installing libuv (1.7.5-r0)
(4/4) Installing nodejs (4.2.4-r1)
Executing busybox-1.24.1-r7.trigger
OK: 29 MiB in 15 packages
 ---> d0efae9d2278
Removing intermediate container 4dabb895e0b1
Successfully built d0efae9d2278

real	0m7.301s
user	0m0.018s
sys	0m0.011s
$

公式版のリポジトリdl-4.alpinelinux.orgは米国南部にあるようで、日本からのアクセスだとかなり差が出ました。特別な理由がない限り、GliderLabs版をお奨めします。

なお、差が出るのはあくまでパッケージリポジトリへのアクセスです。docker pullでイメージをダウンロードする場合はどちらも同じDocker Hubからになるので速度は変わりません。といっても5MB程度しかないので、どちらにしろあっという間にベースイメージをPullすることができ、快適です。

差し当たっての注意点はパッケージマネージャとDNS

Dockerfileを作成するにあたり、やはりディストリビューションのお作法を理解しておく必要があります。
Alpine Linuxは多くのディストリビューションと同じく、バイナリパッケージを検索/ダウンロードするパッケージマネージャ を利用します。パッケージは以下のサイトで検索することができます。

ソースからプログラムをビルドするのであれば、ヘッダファイルを含む<パッケージ名>-devパッケージ、特に標準ライブラリのヘッダファイルを含むmusl-devパッケージを憶えておきましょう。ベースイメージにはそれらのパッケージが含まれていないので、何も考えずにdocker buildすると以下のエラーに出くわすことうけあいです。

Release/obj/gen/sqlite-autoconf-3090100/sqlite3.c:9457:19: fatal error: stdio.h: No such file or directory

メジャーどころのパッケージは一通り押さえている感じがしましたが、パッケージ名の規則は特にどのディストリビューションに合わせているわけでもなさそうです。他のディストリビューションのDockerfileからAlpineベースに移行する場合、パッケージ名の照合は数が多いと骨の折れる作業かもしれません。今回試した中では、UbuntuのgpgパッケージがAlpineではgnupgパッケージが対応していました。

また、ドキュメントにあるようにresolv.confdomain行とsearch行を読まないので、クラスタ構成などでショートホスト名を前提に組んでいる場合など注意が必要です。

パッケージマネージャのオプションがDockerfileに向いている

パッケージマネージャAPKのオプションは、元々キャッシュをローカルに持たないように設計されているためDockerイメージと相性が良いです。いくつかバリエーションがありますが、キャッシュを残さない--no-cacheオプションとパッケージをグループ化する--virtualオプションを押さえておけば良いでしょう。GliderLabs版に含まれるapk-installスクリプト(apk --no-cache addと同等)が、最もシンプルに書ける記法だと思います。

Dockerfileの例

ちなみに、オプションを指定しないapk addではリポジトリに問い合わせに行かないのでパッケージが見つからずエラーになるので注意しましょう(従来のイメージでapt-get updateを実行しないときと同等)。

$ docker images
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
takipone/alpine-ghost   latest              3b7b8caa2eef        5 seconds ago       171.1 MB
takipone/ghost          0.7.6               849f9983543b        2 days ago          352 MB
gliderlabs/alpine       3.3                 169fc2bfcef7        3 weeks ago         4.794 MB
node                    4.2-slim            1716606794de        4 weeks ago         205.3 MB

上の2つがアプリのインストール済みイメージ、下2つがその前のベースイメージです。奇数行がAlpineベース、偶数行がUbuntuベースです。Alpineのベースイメージが非常に小さいことがわかる反面、今回のアプリはNode.jsなのでアプリの増分がそのままベースに乗っかる形になっていること読み取れます。

まとめ

Alpine LinuxのイメージをDockerでどう扱うかをご紹介しました。ベースイメージの小ささはdocker pullをはじめとするDockerイメージのオペレーションにかかる時間を劇的に短くするので、体感すると結構感動しますよ。 徐々に実績も増えていくと思いますので、注目していきましょう!

ひとまず、個人のブログを実行するDockerイメージはAlpineベースに移行済みで、ここ数日は安定稼働しているようです。