読者です 読者をやめる 読者になる 読者になる

技術備忘記

日々調べたこととかとりとめなく

docker-slimによるImageの簡単ダイエット

Docker Container Imageのダイエット

先日こちらに参加してきました。非常に興味深い内容ばかりだったのですが、その中でもこのスライドの内容はとても印象に残りました。

私自身は残念ながら今の職場がオンプレミス環境(一部ハイブリッド)なこともあり、Dockerの本番運用は出来ていないのですが、 Dockerを使ったImmutable Infrastructureな環境下では、Dockerレジストリからpullする際の時間の割合がDeployの多くを占めること、 その時間を短縮することが重要であることは容易に想像がつきます。

サーバー - レジストリの物理的な距離によるレイテンシは自前でレジストリを建てるなり、 AWSではAmazon EC2 Container Registryを利用するなりで解決できる問題ですが、 Container Imageのサイズに関しては、作る際に必要に応じて容量の圧縮(ダイエット)を行う必要があります。

上記スライドにもある通り、基本的には地道に頑張るのが王道だとは思いますが、 怠惰な私からすると非常に辛い作業に映ったので(ディスっているわけではありません。念のため) 何か良いものがないのかを探してみたところ、良さそうなものを見つけましたのでご紹介します。

docker-slim

docker-slim は、 定期的に開催されている Global Docker Hack Day で生まれたプロジェクトですが、 その後も継続的にOSSとして開発が進められているようです。

詳細はREADMEとDemoのビデオを見てもらえればおおよそのイメージはつかめると思いますが、 特徴をいくつかご紹介します。

  • Go製のDocker Container Imageサイズ圧縮自動化ツール
  • 静的(Dockerfile)及び動的(各レイヤーでのプロセスの起動情報など)な解析による最適化
  • ダイエットしたImageだけではなくDockerfileも作成してくれる(リバースエンジニアリング)
  • デモではnode.jsのイメージが431.7MBから14.22MB(約97%削減!)

動かしてみる

インストール手順などは割愛します。GithubのREADMEをご覧ください。

デモと同じことをしても面白くないのでイメージを別で用意して動かしてみました。 今回は公式の golang 1.5のイメージを使用します。 github.com

FROM buildpack-deps:jessie-scm
# gcc for cgo
RUN apt-get update && apt-get install -y --no-install-recommends \
        g++ \
        gcc \
        libc6-dev \
        make \
    && rm -rf /var/lib/apt/lists/*
ENV GOLANG_VERSION 1.5.3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 43afe0c5017e502630b1aea4d44b8a7f059bf60d7f29dfd58db454d4e4e0ae53
RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz \
    && echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - \
    && tar -C /usr/local -xzf golang.tar.gz \
    && rm golang.tar.gz
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/src" "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin/

まず普通にbuildします

$ mkdir go-wrapper
$ docker build -t docker-slim-test .
Sending build context to Docker daemon 15.36 kB
Sending build context to Docker daemon
・
・
Successfully built 6feb0104128c

725.1MBでした。

$ docker images | grep slim
docker-slim-test              latest              6feb0104128c        40 seconds ago      725.1 MB

docker-slimを実行してみます

注意: サンプル通りdocker-slim実行ファイル直下で行わないと動作しません

$ ./docker-slim build docker-slim-test
docker-slim: [build] image=docker-slim-test http-probe=false remove-file-artifacts=false
INFO[0000] docker-slim: inspecting 'fat' image metadata...
・
・

作成されたイメージを見てみると・・99%以上削減されています。マジか。。

$ docker images | grep slim
docker-slim-test.slim   latest              910ea500b774        5 seconds ago       3.476 MB
docker-slim-test        latest              fcb17a5be00b        47 minutes ago      725.1 MB

DockerFileを見てみます

FROM scratch
COPY files /
WORKDIR /go
ENV PATH /go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ENV GOLANG_VERSION 1.5.3
ENV GOLANG_DOWNLOAD_URL https://golang.org/dl/go1.5.3.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 43afe0c5017e502630b1aea4d44b8a7f059bf60d7f29dfd58db454d4e4e0ae53
ENV GOPATH /go
CMD ["/bin/bash"]

まずベースのイメージが上のスライドでも紹介されていた超軽量イメージのscratchに置き換わっています。 まあここは予想通りでした。

あとはオリジナルの方で行っているGoのSDKのダウンロードがバッサリ消されていますね。 おそらく動的な解析の結果、これらのファイルを利用しているレイヤーが無いため不要と判断しているのだと思います。

docker exec /bin/bash でログインして何らかのプロセスを立ち上げる、みたいなコンテナには使用できませんね。 (まあ本番利用ではほぼありえないと思いますが)

まとめ

今回はちょっとサンプルが良くなかった気がしますが、、コード自体もslimで素晴らしいプロダクトだと思います。 Docker Imageのダイエットにお悩みの方は、ぜひ導入ご検討されてみては如何でしょうか。