薄いブログ

技術の雑多なことを書く場所

Docker Imageを小さくするために

CIの時間を短くする活動を行っており, 特にその一部のアプリケーションコンテナの継続的 docker buildの改善について書きたいと思います.

Docker Imageを小さくするために

CIにおけるdocker build改善活動の一環でなぜdocker imageを小さくするのか. それはシンプルでdocker pull / pushのコストを減らすためです.

CIにおけるdocker buildでは特にcache-fromのためにpullすることが結構あります. pushする機会は当たり前のようにあります.

では実際にどうやって小さくしていくか

よくインターネット上で見られる方法として

  • baseイメージを小さいものにする
    • Alpine Linux
      • Alpine Linuxベースのイメージは割とスタンダードになってきていますが, glibcではなくmuslなのでglibcでしか動かないソフトウェアやmuslが嫌いな人間は使わない感じになっています.
    • Distroless
      • こっちはglibcなどをgoogleがメンテナンスしてくれる軽量の実行環境のみが存在するイメージです. 基本的にタグは打たれずlatestのみのような運用がなされています. 思想に共感できたり, glibcを使いたい場合などに使う感じです.
  • apk --no-cacheをつけたり/tmpを最後に消すようにしたり, apk add --virtual fooを使ってコマンドの最後に削除したりする
  • Multi-stage Buildsを使う
  • レイヤーの数を少なくする

などがありました. でもなんか何故小さくなるか書かれたものは少なかったです.

baseイメージを小さくするというのは簡単にできる解決策ですがそれ以上工夫できる余地はありません. これは基本的にやることになります.

apk --no-cacheなどは環境ごとのパッケージマネージャーのキャッシュをオフにするオプションは毎回調べるなり覚えることになります. こういうオプションがないときってどうするんですかね?

Multi-stage Buildsを使う. Multi-stage Buildsは意外と知名度が低い問題があって悲しいですが, これを使うことで成果物だけ別のイメージにCOPYすることができます. これは最終イメージを小さくすることにかなり寄与するんですが, 上に乗るアプリケーションによって使いづらかったりします. シングルバイナリになるGoなどは相性が良いですが. しかしこれもdocker build cacheの観点で見ると最終ステージ以外も小さくしないといけないので本質な問題は解決しません.

レイヤーの数を少なくする. これは少し前まで結構見た言説ですがこれは本当なんでしょうか.

Docker Imageが大きくなる理由の調査のためにdocker historyを使って説明しているものがありました. RUNを2つ書いたものとRUNを1つにまとめたもののdocker historyの結果を見比べて小さくなっていますねみたいなものや,パッケージのinstallをしている部分が大きくなっているのでcacheが作られてそうというところからオプションをつけるみたいな事例がありました.

あまりDocker Imageのサイズに興味がない人が多いし, そんなにメリットもないので原因を突き詰めないのは仕方のないことかもしれません.

それはそうとdocker historyは非常に有用なツールですがどのレイヤーが重そうかのあたりをつけるくらいにしか使えません.

そもそもDocker Imageがどの様に保持されているかを知っているとなぜ重いかの理解が捗ります.

moby/v1.md at master · moby/moby · GitHub

上のリンクの中身を見ればわかりますが, Docker Imageは差分により構成されていることがわかります. イメージとして以下のような感じになります.

http://docs.docker.jp/engine/userguide/storagedriver/aufs-driver.html#deleting-files-with-the-aufs-storage-driver

つまりどこの差分がなぜ重くなっているか知ることでより本質的な改善が行なえます.

自分がそこで困っていたのでそのためのツールを作りました.

github.com

レイヤーごとに差分のサイズとファイル名が出力されるだけのツールですがDocker Imageを小さくする際に力を発揮します. 不明なcacheファイルが残っていることや, 不要なツール, 重複して作られているファイルの存在の認識ができます.

実際にこれでGoの公式イメージサイズを小さくすることに成功したりしました.

ちゃんと改善活動をするときは原因特定ができる状況を作ってからにしましょう.

ぜひdlayerを使ってDocker Imageを小さくしてみてください!

余談

このツールが出た少しあとに以下のツールが爆発的に盛り上がりました.

github.com

非常に見やすく上位互換って感じがしますね...