Carpe Diem

備忘録

Bazelを使ってみる その5(リモートキャッシュ)

概要

Bazel解説第5弾です。

Bazelを使ってみる その1(Goのビルド) - Carpe Diem
Bazelを使ってみる その2(protobufのビルド) - Carpe Diem
Bazelを使ってみる その3(docker imageのビルド) - Carpe Diem
Bazelを使ってみる その4(gRPCのビルド) - Carpe Diem

今回はリモートキャッシュについて説明します。

環境

  • Bazel v4.2.2

Bazelのキャッシュ機構

Bazelにはリモートキャッシュの仕組みがあります。これはキャッシュをGCS(Google Cloud Storage)などの外部ストレージに置き、ビルド時にそのキャッシュをダウンロードして利用する仕組みです。

これにより、CIであったり初めてリポジトリをビルドするメンバーに対して

  • ビルド時間を短縮することができる
  • ビルド時にコンピューティングリソースをできるだけ使わせない

といったメリットがあります。

フロー

リモートキャッシュを利用する場合、以下のフローを踏みます。

f:id:quoll00:20220109103930p:plain

  1. Bazelはビルドする必要のあるターゲットのグラフを作成し、必要なアクションのリスト(inputとoutputのファイル名を含む)を作成する
  2. ローカルマシンで既存のビルドoutputがある場合はそれを再利用する
  3. 次にリモートキャッシュをチェックし既存のビルドoutputを探す。もしoutputが見つかればそれを取得する(=キャッシュヒット)
  4. outputが見つからず、かつ必要なアクションについては、Bazelはローカルでアクションを実行し必要なビルドoutputを作成する
  5. 新しいビルドoutputがリモートキャッシュにアップロードされる

Disk Cache

リモートキャッシュのストレージ先として、ローカルのディスクストレージも指定することができます。これをDisk Cacheと呼びます。

ビルド時に--disk_cacheを指定することでそちらを利用するようになります。

$ build --disk_cache=/path/to/build/cache

リモートキャッシュの優先度としては

  1. Disk Cache
  2. GCSなどの外部ストレージ

となるので、別のマシンからGCS側のキャッシュを更新してもDisk Cacheが残っていればそちらを使ってしまうので注意してください。

まとめると以下のようになります。

名前 説明 場所 優先度 bazel cleanで消える?
local cache プロジェクト固有のキャッシュ ~/.cache/bazel on Linux
/private/var/tmp on macOS
1 消える
disk cache —disc_cacheで指定したローカルディスクキャッシュ —disk_cacheで指定したpath 2 消えない
remote cache GCSなど指定したサーバでキャッシュ GCSなど 3 消えない

GCSを使ったリモートキャッシュ

今回はGCSを使ったリモートキャッシュ環境を用意します。

設定

バケットの用意

GCSでリモートキャッシュのデータを保存するバケットを用意します。

.bazelrc

.bazelrcに以下を追記します。

build --remote_cache=https://storage.googleapis.com/バケット名 --google_default_credentials

以下のコマンドはすべてbuildを継承しているので、別で追記する必要はありません。

  • test
  • run
  • clean
  • mobile-install
  • info
  • print_action
  • config
  • cquery
  • aquery

クレデンシャルについては--google_default_credentialsオプションでgcloud auth application-default login時に生成されたデフォルトのクレデンシャルを利用するか、--google_credentialsオプションで直接指定するようにしてください。

動作確認

ビルド1回目

初回はキャッシュがないのでremote cache hitの文言が出ません。

$ bazel build //server
INFO: Invocation ID: 691ceb2c-7754-429a-a939-f6e913e3ff05
INFO: Analyzed target //server:server (140 packages loaded, 9306 targets configured).
INFO: Found 1 target...
Target //server:server up-to-date:
  bazel-bin/server/server_/server
INFO: Elapsed time: 93.774s, Critical Path: 43.32s
INFO: 341 processes: 13 internal, 328 darwin-sandbox.
INFO: Build completed successfully, 341 total actions

フロー通りGCSにはアップロードされていました。

f:id:quoll00:20220109133140p:plain

f:id:quoll00:20220109133224p:plain

ビルド2回目

ローカルのキャッシュをクリアして再度実行してみます。

$ bazel clean
INFO: Invocation ID: a860e2e3-25f8-42b8-b9d3-f485f87dc35b
INFO: Starting clean.

$ bazel build //server
INFO: Invocation ID: 0ba70b5f-183f-4030-9f72-c476e2a2a612
INFO: Analyzed target //server:server (140 packages loaded, 9306 targets configured).
INFO: Found 1 target...
Target //server:server up-to-date:
  bazel-bin/server/server_/server
INFO: Elapsed time: 14.279s, Critical Path: 8.67s
INFO: 341 processes: 328 remote cache hit, 13 internal.
INFO: Build completed successfully, 341 total actions

INFO: 341 processes: 328 remote cache hit, 13 internal.

とあるように、341工程中328でリモートキャッシュが利用できていることが分かります。

またビルド時間も93秒から14秒と非常に短縮できています。

サンプルコード

今回のサンプルコードはこちら

github.com

まとめ

Bazelのリモートキャッシュについて説明しました。

CIでBazelを利用する際はぜひ活用したいですね。

参考