薄いブログ

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

CIにおけるMulti-stage Buildsのcache

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

CIにおけるMulti-stage Builds

Multi-stage Buildsについては以下の記事を参照すると良いと思います.

docs.docker.com

Multi-stage Buildsは最終イメージサイズを簡単に小さくするために導入された機能です.

イメージサイズを小さくするだけではなく様々な活用方法が生み出されました.

medium.com

speakerdeck.com

今では効率的なdocker buildにはMulti-stage Buildsは欠かせないものになっています.

Multi-stage Builds以前のCI環境では1 Dockerfile 1 Cacheの考え方で問題なかったのですが, Multi-stage Builds環境では問題が起こります.

ローカルで実行する分には何も問題は起きませんがdockerdが毎度変わる状況, つまりCI環境やDocker In Docker(dind)などの状況においてです.

最終イメージの中にbuild processのすべてが含まれていれば1 Dockerfile 1 Cache, つまり単純な--cache-fromを指定するだけで良いです. しかし複数ステージにまたがる場合は最終イメージに含まれない部分はcacheできず, Multi-Stage Buildsの意義的には最終イメージは小さくなりcacheするべき情報は殆ど含まれていないはずです. つまり意味のないcacheになってしまいます.

cacheしたいステージを明示的に--targetで指定してbuildされたイメージを外部に記憶してもらう必要があります.

いろんなやり方がありますがdocker saveした結果をobject storageにuploadしたり, registryにtagをつけてpushしてdocker registryをobject storageの代わりに使うものがあります.

object storageを新しく用意しなくて良い分, stageごとにtagをつけてregistryにpushする手法が始めやすくて良いと思っています.

しかしstageが増えれば増えるほどbuild processが変わったり, cache-fromに指定するものが増えたりするので人間がやるのが厳しくなってしまいます.

そこを簡単にするためのツールをPoC的に作ってみました.

github.com/orisano/castage

github.com

これはDockerfileを入力として与えるとstageをtagをつけながらbuildしてpushまでするshell scriptを生成します.

これによりCI環境下においても適切にcacheできる様になります. build processにbuild用のスクリプトを生成する部分を作ってしまえばあとは好きにstageを追加することができます. Dockerfileの改善活動を行っているとstageを追加したりすることが頻繁にあり, そのたびにpipelineを書き換えるのは非常に億劫です. pipelineを書き換えるのが億劫なのでDockerfileの改善活動のハードルになるのはおかしいので今回作成しました.

ぜひ使ってみて良いと思ったらGitHubでstarしていただけると嬉しいです. また使ってみてのフィードバックやPRは大歓迎です.

今回書いた内容は以下のスライドにも書いてあるのでぜひ読んで見てください.

speakerdeck.com