docker

Dockerイメージを軽くするために、オフィシャルのイメージがやってることを調べてみた

More than 1 year has passed since last update.

自分でカスタマイズしたDockerイメージを作成しようと思って、オフィシャルのDockerファイルを読み込んでみると変わった処理が行われていることに気づいた。

以下はredis3.0のオフィシャルイメージの一部(Redisイメージ)

RUN apt-get update && apt-get install -y --no-install-recommends \
        ca-certificates \
        wget \
    && rm -rf /var/lib/apt/lists/*

基本的には余計なものは入れない、要件が終わると削除するという精神で作成を行っています。
--no-install-recommands
を使うと「推奨」パッケージをインストールせずに必要最低限の依存パッケージをインストールしてくれます。(推奨パッケージなんてあったんですね汗:余談ですが、よくapt-getとaptitudeの比較が挙げられていますが、aptitudeは推奨パッケージも自動で入れてくれるそうです。)

rm -rf /var/lib/apt/lists/*
キャッシュのようなファイルが置かれているそう
apt-get updateを実行すれば、新しく作成されるので削除しても問題ないということです。
http://unix.stackexchange.com/questions/217369/clear-apt-get-list

最後にまとめて削除すればいいんじゃない?と思うかもしれないのですが、

それではダメなんです

容量の大きなファイルを作成して、一行のRUNに収める場合と2行のRUNに収める場合で検証してみます。
Aパターン

FROM ruby:2.1.7

RUN dd if=/dev/zero of=/10megafile bs=1M count=10
RUN rm /10megafile

Bパターン

FROM ruby:2.1.7

RUN dd if=/dev/zero of=/10megafile bs=1M count=10 && rm /10megafile

Aからdocker build split .でイメージを作成
Bからdocker build same .でイメージを作成して、docker imagesで容量を確認します。

% docker images
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
same                             latest              bc928bf2446f        7 seconds ago       718.2 MB
split                            latest              53e3478f8d2d        2 minutes ago       728.7 MB

ちょうど10MBの差が確認できました。

このことからもわかるのですが、Dockerfileのコマンドはそれぞれレイヤーを作成します。
イメージの容量はすべてのレイヤーの合計になることがわかりました。

Dockerイメージがどのようなレイヤーで構成されているかは
docker history REPOSITORY
コマンドで見ることができます。

AパターンとBパターンでは

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
53e3478f8d2d        8 minutes ago       /bin/sh -c rm /10megafile                       0 B
933d9d0cda06        8 minutes ago       /bin/sh -c dd if=/dev/zero of=/10megafile bs=   10.49 MB

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
bc928bf2446f        3 minutes ago       /bin/sh -c dd if=/dev/zero of=/10megafile bs=   0 B

このような違いが出ます。
イメージのレイヤーをわかりやすく表示してくれるサービスもあるようです。
例えばredis3.0
https://imagelayers.io/?images=redis:3.0.0

あと、ひとつのRUNに詰め込みすぎじゃない?って思う方もいらっしゃると思いますが、これにも理由があって、レイヤーが127階層までしか作れないからだそうです。

まとめ
Dockerのイメージを軽くするためには、

  • よけいなものをインストールしない
  • 使ったら同じレイヤーの中で消す

ということでした。