Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

Rustでdocker build時に依存ライブラリの再ビルドを避ける

Rust で書かれたアプリをビルドするための docker image は以下で公開されている。

hub.docker.com

しかし、ここに出ているように COPY . . なんてやっていると、 src/main.rs を触るだけで毎回 cargo install 時に依存するライブラリをすべてダウンロードしてきてコンパイルしてしまい、恐ろしく効率が悪い。

これを避けるには、アプリをビルドする前に依存だけをビルドするレイヤを作っておき、その上に自分のアプリをビルドするレイヤを載せられるといい。しかし、残念なことに、現在の cargo には依存クレートだけをビルドする仕組みがない。じゃあどうするかというのが、以下のエントリに書かれている。

whitfin.io

要点だけ説明すると、まず cargo new --bin my_project とこれからビルドするプロジェクトと同名のダミーの空のプロジェクトを用意し、そこに Cargo.tomlCargo.lock のみを配置して cargo build --release する。その後 src/*.rs を本物に差し替えて、もう一度 cargo build --release すれば良い。ただし、自分で試してみたところなぜか 2 度目の cargo build が動いてくれなかったので、 touch src/main.rs をするなどの処理をおまけで入れておいた。

さて、手元での実行はこれで良いが、 Cloud Build: serverless CI/CD platform  |  Google Cloud を使うと、前回ビルド済のレイヤを参照できるわけではないのでキャッシュが効いてくれない。 --cache-from を使う方法もあるが、マルチステージビルドとだいぶ相性が悪い。というのも、ビルドに使ったイメージも破棄せず docker push しなければならないので。じゃあどうするかというのは、以下のエントリに書かれている。

qiita.com

kaniko を使えば、 cloudbuild.yaml は本当に大丈夫かいなってくらい恐ろしくシンプルになる。それでも動かしてみるときちんとキャッシュをする動きになっていて、初回実行が 18M52S かかる cargo build が2度目の実行が 1M25S で済んだ。すばらしい。