Envoy 的 bzlmod 模块依赖图解析:从 envoy_toolshed 到各下游模块的发布拓扑
【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy
本篇技术指南围绕 Envoy 仓库中的 bazel/dep-graph.md 展开,系统解读 Envoy 在 Bazel bzlmod 模式下对外发布的模块依赖拓扑:谁在底层支撑(envoy_toolshed)、谁是核心模块(envoy与envoy_api)、哪些下游项目消费这些模块(移动端、文档站、示例工程与仓库内测试工程)。读者读完本文后,将能对照仓库内的MODULE.bazel、MODULE.bazel.lock与模块扩展代码,准确理解 Envoy 模块化构建体系的全貌,并能独立验证与扩展这张依赖图。
一、背景:Envoy 的 bzlmod 模块化发布体系
从 Bazel 6 开始,bzlmod(Bazel Module)取代传统 WORKSPACE 成为推荐的依赖管理方式。Envoy 主仓库在 MODULE.bazel 中声明:
module( name = "envoy", version = "1.40.0-dev", )即以独立 Bazel 模块(module)的身份对外发布,版本跟随仓库当前开发版本。与此同时,Envoy 还发布了多个配套模块,它们共同构成一张有向依赖图(dependency graph),这张图正是 bazel/dep-graph.md 记录的核心内容。
从仓库结构看,各模块与代码目录的对应关系为:
| 图中节点 | 模块名 | 仓库内对应位置 |
|---|---|---|
toolshed | envoy_toolshed | 独立发布的构建基础设施模块(版本 0.4.15.envoy) |
api | envoy_api | api/MODULE.bazel,对应api/目录 |
envoy | envoy | MODULE.bazel,对应仓库根目录 |
mobile | envoy_mobile | mobile/MODULE.bazel,对应mobile/目录 |
docs | envoy-docs | docs/MODULE.bazel,对应docs/目录 |
examples | envoy-examples | 仓库外独立发布的示例工程模块 |
filter_cc | envoy-example-filter-cc | 仓库外发布的 C++ 过滤器示例模块 |
wasm_cc | envoy-example-wasm-cc | 仓库外发布的 Wasm 过滤器示例模块 |
ext_test | envoy_external | bazel/tests/external/MODULE.bazel |
二、依赖图全景:节点角色与连线语义
bazel/dep-graph.md以 Mermaidgraph TD形式完整绘制了这张已发布(published)模块图,全文如下:
三类角色
图中通过classDef定义了三种视觉角色,语义非常明确:
- root(绿色填充):仅
toolshed(envoy_toolshed)一个节点。它是整张图的依赖源头,不依赖图中任何其他模块,只被上游消费。绿色语义即"根"——整棵依赖树的起点。 - core(蓝色填充):
envoy与api两个节点。它们是 Envoy 生态最核心的构建模块:envoy是主代理实现,envoy_api提供全部 API 定义(proto 契约)。二者互相支撑(api被envoy依赖),并共同向外辐射到所有下游模块。 - consumer(白色虚线框):
ext_test(bazel/tests/external)一个节点。它位于图的最末端,专门用于验证外部消费者视角下模块是否能正确解析构建。
实线与虚线的区别
图中大部分连线为实线-->,表示普通的 Bazel 模块依赖关系(即下游模块在MODULE.bazel中以bazel_dep声明依赖上游模块)。唯一的虚线envoy -.-> ext_test连接主模块与ext_test,暗示这是一种"特殊"关系:bazel/tests/external是仓库内的测试工程而非独立发布模块,它的作用是从外部消费者视角反向测试envoy及envoy_api等模块,因此用虚线区别于常规发布链路。
三、根节点:envoy_toolshed 提供的构建基础设施
envoy_toolshed(图中toolshed)是整张图的依赖根。它虽不依赖图中任何节点,但却是 Envoy 构建系统运转的地基。在根 MODULE.bazel 中可以清晰看到对它的密集使用:
bazel_dep(name = "envoy_toolshed", version = "0.4.15.envoy") # LLVM 交叉编译工具链 sysroot_ext = use_extension("@envoy_toolshed//sysroot:extensions.bzl", "sysroot_extension") sanitizer_ext = use_extension("@envoy_toolshed//compile:extensions.bzl", "sanitizer_extension") grcov_ext = use_extension("@envoy_toolshed//coverage/grcov:extensions.bzl", "grcov_extension") wee8_ext = use_extension("@envoy_toolshed//v8:extensions.bzl", "wee8_prebuilt_extension") libcxx_ext = use_extension("@envoy_toolshed//compile:extensions.bzl", "libcxx_extension") llvm_minimal_ext = use_extension("@envoy_toolshed//compile:extensions.bzl", "llvm_minimal_extension")具体而言,envoy_toolshed通过模块扩展(module extension)向 Envoy 注入:
- 系统根文件系统(sysroot):为
linux_amd64/linux_arm64提供构建用 sysroot; - Sanitizer 运行库:注入
msan_libs、tsan_libs供内存/线程消毒器构建; - 覆盖率工具:grcov 覆盖率采集器;
- V8 预编译库:
wee8_prebuilt_x86_64、wee8_prebuilt_aarch64等; - libc++ 与最小化 LLVM 工具链:用于跨平台(linux/macOS,x86_64/arm64)的 LLVM 编译器栈;
- PGP 签名工具链:
register_toolchains("@envoy_toolshed//pgp:sq_toolchain")。
同时,envoy_toolshed也被envoy_api与bazel/tests/external直接依赖,是三条独立链路共同的根。图中toolshed --> api、toolshed --> envoy两条边即对应 api/MODULE.bazel 与根 MODULE.bazel 中各自的bazel_dep(name = "envoy_toolshed", ...)声明。
四、核心模块之一:envoy_api 与它的"被依赖"地位
envoy_api是 Envoy 的 API 契约模块,在 api/MODULE.bazel 中声明:
module( name = "envoy_api", version = "1.40.0-dev", repo_name = "envoy_api", )其内容对应仓库api/目录下的大量 proto 定义(如api/envoy/config、api/envoy/extensions、api/envoy/service、api/envoy/type等),是 Envoy 全部配置与数据面协议的类型源头。
从图中可见envoy_api扮演双重角色:
- 被核心模块依赖:
api --> envoy。根 MODULE.bazel 第 33 行声明bazel_dep(name = "envoy_api", version = "1.40.0-dev"),并在仓库内通过local_path_override将其指向本地api/目录,保证主仓库构建时 API 与代理代码同步开发:
local_path_override( module_name = "envoy_api", path = "api", )- 直接供应示例模块:
api --> filter_cc。C++ 过滤器示例模块envoy-example-filter-cc直接以envoy_api为依赖,说明该示例既消费 Envoy 主模块的运行框架,也直接使用 API 类型定义。
五、核心模块之二:envoy 主模块及其庞大的依赖面
envoy主模块位于图中心,向外辐射出mobile、docs、examples、filter_cc、wasm_cc、ext_test六条边。其自身依赖清单在根 MODULE.bazel 中极为庞大,涵盖:
- 协议与传输:
grpc、nghttp2、quiche(HTTP/3)、c-ares、brotli、zstd、zlib-ng; - TLS/加密:
boringssl、boringssl-fips、boringssl-source、openssl(供兼容构建)、tcmalloc、jemalloc; - 执行引擎:
v8(Wasm)、wasmtime、wamr、proxy-wasm-cpp-host、proxy-wasm-cpp-sdk、proxy-wasm-rust-sdk; - 可观测性:
opentelemetry-cpp、opentelemetry-proto、zipkin-api、prometheus-metrics-model、perfetto; - 规则与编译体系:
rules_cc、rules_go、rules_java、rules_rust、rules_python、rules_proto、rules_swift、toolchains_llvm等。
主模块还在 MODULE.bazel 末尾注册了若干仓库自身的模块扩展(见下文第七节),并配置了 GCC/LLVM 两套编译器工具链与 Python 3.12、Go 1.24.6、Rust 1.88.0 等多语言工具链。
六、下游消费模块:移动端、文档站与示例工程
6.1 envoy_mobile(移动端库)
envoy_mobile在 mobile/MODULE.bazel 中声明,版本同为1.40.0-dev,对应仓库mobile/目录(包含 Android Java/Kotlin、iOS Swift/Objective-C 的客户端封装)。其模块声明中:
bazel_dep(name = "envoy", version = "1.40.0-dev") bazel_dep(name = "envoy_api", version = "1.40.0-dev.20260903.16b0d47.envoy") local_path_override( module_name = "envoy", path = "..", )印证了图中envoy --> mobile的依赖边:移动端库构建在核心envoy与envoy_api之上,同时直接依赖envoy_toolshed、envoy_build_config以及 Android/iOS 相关规则(rules_android、rules_apple、rules_kotlin、rules_swift、rules_xcodeproj)。
6.2 envoy-docs(文档站)
envoy-docs在 docs/MODULE.bazel 中声明,对应docs/目录(Sphinx 文档站,含 496 个.rst文档)。其模块声明:
bazel_dep(name = "envoy") bazel_dep(name = "envoy_api", version = "1.40.0-dev.20260903.16b0d47.envoy") bazel_dep(name = "envoy-examples", version = "0.2.6.envoy") local_path_override( module_name = "envoy", path = "../", ) local_path_override( module_name = "envoy_api", path = "../api", )注意这里出现了一个跨模块依赖:envoy-docs依赖envoy-examples(版本 0.2.6.envoy),对应图中examples --> docs的边——文档站需要从示例工程提取可嵌入文档的示例配置,因此示例模块成为文档构建的依赖输入。
6.3 示例工程:envoy-examples、filter_cc 与 wasm_cc
图中右下区域描述了三个示例类模块之间的内部关系:
envoy --> examples:envoy-examples依赖主模块(官方示例配置均针对envoy构建);envoy --> filter_cc与api --> filter_cc:envoy-example-filter-cc(C++ 扩展过滤器示例)同时依赖主模块与 API 模块;envoy --> wasm_cc:envoy-example-wasm-cc(Wasm 过滤器示例)依赖主模块;filter_cc --> examples与wasm_cc --> examples:两个扩展示例均以envoy-examples为构建基础;wasm_cc --> docs:Wasm 示例同时被文档站消费。
这些模块对应仓库外独立发布的示例工程。从依赖结构看,Envoy 有意让示例工程分层:基础示例(examples)→ 带扩展代码的示例(filter_cc / wasm_cc)→ 文档站(docs),从而让下游开发者可以按"基础示例 → 扩展示例 → 文档"的递进路径学习。
6.4 bazel/tests/external:仓库内的消费者测试
ext_test节点对应 bazel/tests/external/MODULE.bazel,模块名为envoy_external。它是 Envoy 用来验证"外部消费者视角"的测试工程:把自己伪装成一个独立模块,通过local_path_override将envoy、envoy_api、envoy-docs指回仓库内路径:
module(name = "envoy_external") bazel_dep(name = "envoy") bazel_dep(name = "envoy_api", version = "1.40.0-dev") bazel_dep(name = "envoy-docs", version = "1.40.0-dev") bazel_dep(name = "envoy_toolshed", version = "0.4.15.envoy") local_path_override( module_name = "envoy", path = "../../../", ) local_path_override( module_name = "envoy_api", path = "../../../api", ) local_path_override( module_name = "envoy-docs", path = "../../../docs", )这正是图中envoy -.-> ext_test虚线边的含义:它不是常规的发布依赖,而是仓库内部为了持续验证"模块对外可解析、可构建"而设置的特殊消费链路,其 MODULE.bazel.lock 记录了完整的解析结果。
七、从 lockfile 到依赖元数据:envoy_module_graph_extension 的落地
依赖图不止停留在文档层面,仓库还提供了代码级的"图生成器"。在 bazel/extensions.bzl 中,Envoy 定义了一个模块扩展envoy_module_graph_extension:
envoy_module_graph_extension = module_extension( implementation = _envoy_module_graph_impl, doc = """ Extension that watches MODULE.bazel.lock and materializes resolved module dependency metadata as @envoy_mod_graph//:deps.json. """, )其实现流程为:
- 读取根 MODULE.bazel.lock 中的
registryFileHashes字段; - 解析其中指向 Bazel 模块仓库(
/modules/<name>/<version>/source.json)的 URL,还原出每个模块的module_name、version与registry; - 将解析结果编码为
@envoy_mod_graph//:deps.json文件(一个 JSON 依赖元数据产物)。
这一机制从锁定文件反推出"已解析依赖图",与dep-graph.md中人工绘制的"发布依赖图"形成互补:前者描述模块对外发布时的静态拓扑,后者反映真实构建时 lockfile 解析出的动态结果。在 bazel/BUILD 第 965 行,该元数据被进一步引用:
"@envoy_mod_graph//:deps.json",说明deps.json会被实际构建目标消费,例如用于生成依赖清单或审计工具。读者如需在本地复现依赖解析结果,可查看根 MODULE.bazel.lock 或bazel/tests/external/MODULE.bazel.lock中moduleExtensions/modules段的记录。
八、如何核对与扩展这张依赖图
若读者希望基于当前仓库验证或更新这张图,可遵循以下路径:
- 核对节点声明:逐个打开 MODULE.bazel、api/MODULE.bazel、mobile/MODULE.bazel、docs/MODULE.bazel、bazel/tests/external/MODULE.bazel,确认
module(name=...)与bazel_dep(...)是否与图中边一致; - 核对版本一致性:图中
envoy、envoy_api、envoy_mobile、envoy-docs均围绕1.40.0-dev版本发布,envoy_toolshed固定为0.4.15.envoy,示例模块envoy-examples为0.2.6.envoy,可在各MODULE.bazel中逐一比对; - 查看解析结果:以根 MODULE.bazel.lock 与 bazel/tests/external/MODULE.bazel.lock 为准,确认 lockfile 中记录的模块依赖与发布图吻合;
- 理解扩展生成物:结合 bazel/extensions.bzl 的
_envoy_mod_graph_repo_impl与 bazel/BUILD 对@envoy_mod_graph//:deps.json的消费,理解文档图之外还存在一份由 lockfile 机械生成的依赖元数据。
九、小结
bazel/dep-graph.md用一张 Mermaid 图浓缩了 Envoy 对外发布的 bzlmod 模块生态:envoy_toolshed作为根提供工具链地基,envoy与envoy_api作为核心模块向外供给能力,envoy_mobile、envoy-docs、envoy-examples及其子示例逐层消费,而bazel/tests/external以消费者测试的身份闭环验证整张图的可解析性。结合仓库内各 MODULE.bazel 声明、lockfile 与 bazel/extensions.bzl 的实现,这张图不仅是依赖关系的可视化,更是理解 Envoy 模块化构建、版本发布策略与下游生态入口的最佳起点。
【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考