薄いブログ

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

orisano/minid の話

github.com

上のツールを作ったので紹介の記事です.

背景

僕はアプリケーションエンジニアとしてDockerfileをそこそこ書くことがあるのですが,

巷にあふれるDockerfileがRUN一つにまとめられているのがずっと不思議に思っていました.

見栄えも悪いし, これってメンテナンス可能なんだろうか. そもそもなぜやっているんだろうと.

docs.docker.com

In older versions of Docker, it was important that you minimized the number of layers in your images to ensure they were performant. The following features were added to reduce this limitation:

In Docker 1.10 and higher, only the instructions RUN, COPY, ADD create layers. Other instructions create temporary intermediate images, and do not directly increase the size of the build.

In Docker 17.05 and higher, you can do multi-stage builds and only copy the artifacts you need into the final image. This allows you to include tools and debug information in your intermediate build stages without increasing the size of the final image.

上の記事を見ると, 古いバージョンのDockerにおいては, イメージのレイヤー数を最小化することが重要だったと書いてあります.

  • Docker 1.10 より前のバージョンのRUN, COPY, ADD以外の命令でもビルドのサイズが大きくなってしまう問題点
  • Docker 17.05 より前のバージョンではmulti-stage buildsが使用できない故に, イメージが大きくなりがちな問題, ツールを入れて使うのに気を使わないといけない問題

以上の問題点により, レイヤーの数がどうこうというよりイメージのサイズについて触れられていることが多いです.

17.05以降のバージョンを使える環境においてはRUN, COPY, ADDの数がレイヤーの数になりますし, multi-stage buildsを活用することでイメージのサイズは小さくできますのでレイヤー数がどうこうみたいなことは考えなくて良いと思います.

ちなみになぜイメージのサイズを意識するかというとpull, pushの速度に寄与するからだと思っています.

もしそのほかの観点でイメージのサイズを小さくする理由があるという方は教えていただけると幸いです.

orisano/minid

github.com

このツールは上の背景について理解してなかった僕が作った連続しているRUN, COPY, ADDを結合してくれるやつです.

機械的にRUN, COPY, ADDを結合することでイメージのサイズを小さくすることができます. しかし,レイヤー数が減るからイメージサイズが減るわけではないです.

厳密には違うのですが以下のページの図を参照していただけるとわかりやすいと思います.

AUFS ストレージ・ドライバの使用 — Docker-docs-ja 17.06.Beta ドキュメント

Dockerのイメージはファイルシステムの差分で構成されており, ファイルの削除はWhiteoutファイルで表現され, 移動などはOpaqueファイルで表現されています.

Dockerfileのすべてのレイヤーで独立なファイルを作成, 変更していればほとんど無駄がないので問題ありません.

しかし, RUNで実行されたコマンドがどういったファイルを作ったり変更したりするかをすべて把握しているかと聞かれれば怪しいと思います. (特にcache周りなど)

機械的にRUNをまとめることで, 自分が意識しないうちにレイヤーを跨いで触れているファイル分のサイズが小さくなります. これがサイズが小さくなる原理です.

また差分で保持しているという前提を知らなくても連続している場合のみ回避することができます.

一番重要なメリットしては, 人間が && を無限に書かなくても良くなるところです.

minidではbuildkitの内部にあるDockerfileのパーサを使用しASTを取得し, ランレングス圧縮の要領でまとめているだけです.

github.com

Dockerfileのparserは意外と簡単に使えるので使っておもちゃを作ってみると面白いかも知れません.

ぜひ面白いおもちゃができたときは教えてください.

終わりに

個人的にこのツールのあまり見ない点は, Dockerfileを受け取ってDockerfileを返す点だと思っています.

開発者が書きやすいDockerfileと小さく最適なDockerfileは別物だと思っていて,前者から機械的に後者を作れると信じているのでDockerfileを加工するシンプルなツールを作っています.

それをCI上でPipelineにすることで開発者の負荷を下げ, 高速なbuild, 高速なdeployの実現を夢みてやっています.

ツールが良いと思ったらGitHubでStarしてくれると励みになります.