
2025/12/19 4:50
**Bazelでコンテナイメージを作成する高速化手法**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
要約
rules_img は、コンパイル時にイメージデータをメタデータとして扱い、プッシュまたはロードが必要になったときのみブロブを移動することで Docker‑image のビルド方法を再考した Bazel ルールセットです。 rules_oci が OCI レイアウト全体をローカルディスクにダウンロードするのに対し、 rules_img は小さなマニフェスト(約10 KB)だけを取得し、各レイヤーの tarball とそのディスクリプタを Bazel の Content‑Addressable Storage (CAS) に書き込みます。実際のレイヤーブロブはユーザーが bazel run を実行するまでレジストリに残ります。その時点で pusher は既存レイヤーをレジストリから照会し、欠けているものだけを CAS からストリームして最終イメージをプッシュします。コンテナd や Docker にイメージをロードする場合も同様にインクリメンタルで、ローカルに既に存在しないレイヤーだけがストリームされます。
使用するには、
MODULE.bazel に bazel_dep(name = "rules_img", version = "<version>") を追加し、次に image_layer と image_manifest を定義します。オプションの最適化としては、レイヤー内でハードリンクによる重複排除やシーク可能レイヤー用の eStargz サポートがあります。
結果としてデータ移動が劇的に削減されます:大きなベースイメージを数秒でプルでき、インクリメンタル Docker ロードはミリ秒単位で完了し、Remote Build Execution (RBE) 上のマニフェスト組み立ても高速化します。これにより帯域幅使用量が減少し、リモート実行トラフィックが抑えられ、CI パイプラインが迅速化され、コンテナ中心の DevOps ワークフロー全体の生産性が向上します。
本文
タイトル: Bazel がビルド時に数ギガバイトのベースイメージデータをダウンロードする理由
サブタイトル:
rules_img で問題を解決する方法
問題点
- Bazel でウェブアプリをビルド(すでに Bazel によってコンパイル済み)します。
- それを Docker イメージにパッケージ化し、適切なベースレイヤーと設定を持たせる必要があります。
- コンテナイメージ構築を追加すると:
- CI が遅くなる(毎回大きなベースイメージをダウンロードするため)。
- プッシュ操作が遅いと感じられる。
主な関係者
| 関係者 | 役割 |
|---|---|
| レジストリ (Docker Hub, gcr.io) | コンテナイメージを保管。ベースをプルし、ビルド済みイメージをプッシュします。 |
| ローカルマシン | / が実行される場所。 |
| リモート実行 & キャッシュ | アクションを実行し結果を保存するリモートマシン(Aspect, BuildBuddy など)。 |
コアの葛藤
ベースイメージを拡張したイメージをビルドするには、そのベースに関する情報が必要です:
- どれだけの情報?
- それはどこにある?
現在の方法:rules_oci
rules_ociデータフロー
# ベースイメージをプル pull( name = "ubuntu", image = "index.docker.io/library/ubuntu:24.04", digest = "...", ) # イメージをビルド oci_image( name = "app_image", base = "@ubuntu", # 完全なローカルディレクトリ tars = [":app_layer.tar"], entrypoint = ["/app/bin/server"], ) # レジストリへプッシュ oci_push( name = "push", image = ":app_image", repository = "gcr.io/my-project/app", )
転送の概要
| 送信元 → 先 | データ |
|---|---|
| レジストリ → ローカルマシン | 完全なベースイメージ(数百 MB) |
| ローカルマシン → リモートキャッシュ | 完全なベースイメージ |
| リモートキャッシュ → 実行者 | 完全なベースイメージ |
| リモートキャッシュ → ローカルマシン | 完全なベースイメージ |
| ローカルマシン → レジストリ | 欠落しているレイヤーのみ |
改善された方法:rules_img
rules_imgデータフロー
# ベースイメージをメタデータだけでプル pull( name = "ubuntu", registry = "index.docker.io", repository = "library/ubuntu", tag = "24.04", digest = "...", ) # レイヤーをビルド image_layer( name = "app_layer", srcs = { "/app/bin/server": "//cmd/server", "/app/config" : "//configs:prod", }, ) # イメージを組み立て(メタデータのみ) image_manifest( name = "app", base = "@ubuntu", # メタデータだけ layers = [":app_layer"], entrypoint = ["/app/bin/server"], ) # 実行時にプッシュ image_push( name = "push_app", image = ":app", registry = "ghcr.io", repository= "my-project/app", tag = "latest", )
転送の概要
| 送信元 → 先 | データ |
|---|---|
| レジストリ → ローカルマシン | マニフェスト + コンフィグ(約10 KB) |
| ローカルマシン → リモートキャッシュ | メタデータのみ |
| リモートキャッシュ → ローカルマシン → レジストリ | 欠落しているブロブだけ(通常は新しいレイヤーのみ) |
ベースレイヤーはほとんどローカルマシンやリモート実行者を通過しません。
重要性
- イメージの組み立ては主に JSON と数個のチェックサムです。
- 本当に大切なのは 正しいタイミングでバイト列を適切な場所へ移動させる ことです。
はまずメタデータを転送し、バイト列は境界(エッジ)だけで転送するため、不必要なダウンロードとアップロードを排除します。rules_img
歴史的背景
– すべての言語を統合しようとして保守が難しくなる。rules_docker
– ディスク上で完全な OCI レイアウトを使用。ローカルでは動くが、リモート実行時に問題が生じる。rules_oci
– まずメタデータを扱い、必要に応じてバイト列のみストリームする。rules_img
主な設計決定
| 決定 | 効果 |
|---|---|
| マニフェスト & コンフィグだけをプル | ローカルマシンを軽量化し、レイヤーのダウンロードを実行時に遅延させる。 |
| CAS にブロブを保存 | リモート実行者は全レイヤーをダウンロードする必要がない。 |
| メタデータ専用プロバイダー | アクションは迅速にスケジュールされ、キャッシュも効率的。 |
| 遅延プッシュ戦略 | レジストリへまず問い合わせてから、欠落しているブロブだけをストリーム。 |
追加のパフォーマンス向上
- ハードリンクによる重複除去(レイヤー内)。
- オプションで eStargz を使用しシーク可能レイヤー化。
- Containerd と統合して incremental
が実現。docker load
すぐに始める例
# MODULE.bazel bazel_dep(name = "rules_img", version = "<latest>") pull = use_repo_rule("@rules_img//img:pull.bzl", "pull") pull( name = "ubuntu", registry = "index.docker.io", repository = "library/ubuntu", tag = "24.04", digest = "...", ) # BUILD.bazel load("@rules_img//img:layer.bzl", "image_layer") load("@rules_img//img:image.bzl", "image_manifest") image_layer( name = "app_layer", srcs = { "/app/bin/server": "//cmd/server", "/app/config" : "//configs:prod", }, compress = "zstd", ) image_manifest( name = "app_image", base = "@ubuntu", layers = [":app_layer"], )
高速化のため
.bazelrc を追加する場合:
common --@rules_img//img/settings:compress=zstd common --@rules_img//img/settings:estargz=enabled common --@rules_img//img/settings:push_strategy=lazy
まとめ
- メタデータ優先 + バイトオンデマンド = CI の高速化、ノートパソコンの負荷低減、ビルドグラフのスケーラビリティ。
はベースイメージのダウンロードを数分から数秒へ短縮し、プッシュ時の不要な往復通信を排除します。rules_img- プロジェクトに導入してみてください。うまくいった点やまだ課題が残る点を共有しましょう。