Envoy 的 bzlmod 模块依赖图解析:从 envoy_toolshed 到各下游模块的发布拓扑
2026/9/15 16:33:08 网站建设 项目流程

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)、谁是核心模块(envoyenvoy_api)、哪些下游项目消费这些模块(移动端、文档站、示例工程与仓库内测试工程)。读者读完本文后,将能对照仓库内的MODULE.bazelMODULE.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 记录的核心内容。

从仓库结构看,各模块与代码目录的对应关系为:

图中节点模块名仓库内对应位置
toolshedenvoy_toolshed独立发布的构建基础设施模块(版本 0.4.15.envoy)
apienvoy_apiapi/MODULE.bazel,对应api/目录
envoyenvoyMODULE.bazel,对应仓库根目录
mobileenvoy_mobilemobile/MODULE.bazel,对应mobile/目录
docsenvoy-docsdocs/MODULE.bazel,对应docs/目录
examplesenvoy-examples仓库外独立发布的示例工程模块
filter_ccenvoy-example-filter-cc仓库外发布的 C++ 过滤器示例模块
wasm_ccenvoy-example-wasm-cc仓库外发布的 Wasm 过滤器示例模块
ext_testenvoy_externalbazel/tests/external/MODULE.bazel

二、依赖图全景:节点角色与连线语义

bazel/dep-graph.md以 Mermaidgraph TD形式完整绘制了这张已发布(published)模块图,全文如下:

三类角色

图中通过classDef定义了三种视觉角色,语义非常明确:

  1. root(绿色填充):仅toolshedenvoy_toolshed)一个节点。它是整张图的依赖源头,不依赖图中任何其他模块,只被上游消费。绿色语义即"根"——整棵依赖树的起点。
  2. core(蓝色填充)envoyapi两个节点。它们是 Envoy 生态最核心的构建模块:envoy是主代理实现,envoy_api提供全部 API 定义(proto 契约)。二者互相支撑(apienvoy依赖),并共同向外辐射到所有下游模块。
  3. consumer(白色虚线框)ext_testbazel/tests/external)一个节点。它位于图的最末端,专门用于验证外部消费者视角下模块是否能正确解析构建。

实线与虚线的区别

图中大部分连线为实线-->,表示普通的 Bazel 模块依赖关系(即下游模块在MODULE.bazel中以bazel_dep声明依赖上游模块)。唯一的虚线envoy -.-> ext_test连接主模块与ext_test,暗示这是一种"特殊"关系:bazel/tests/external是仓库内的测试工程而非独立发布模块,它的作用是从外部消费者视角反向测试envoyenvoy_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_libstsan_libs供内存/线程消毒器构建;
  • 覆盖率工具:grcov 覆盖率采集器;
  • V8 预编译库wee8_prebuilt_x86_64wee8_prebuilt_aarch64等;
  • libc++ 与最小化 LLVM 工具链:用于跨平台(linux/macOS,x86_64/arm64)的 LLVM 编译器栈;
  • PGP 签名工具链register_toolchains("@envoy_toolshed//pgp:sq_toolchain")

同时,envoy_toolshed也被envoy_apibazel/tests/external直接依赖,是三条独立链路共同的根。图中toolshed --> apitoolshed --> 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/configapi/envoy/extensionsapi/envoy/serviceapi/envoy/type等),是 Envoy 全部配置与数据面协议的类型源头。

从图中可见envoy_api扮演双重角色:

  1. 被核心模块依赖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", )
  1. 直接供应示例模块api --> filter_cc。C++ 过滤器示例模块envoy-example-filter-cc直接以envoy_api为依赖,说明该示例既消费 Envoy 主模块的运行框架,也直接使用 API 类型定义。

五、核心模块之二:envoy 主模块及其庞大的依赖面

envoy主模块位于图中心,向外辐射出mobiledocsexamplesfilter_ccwasm_ccext_test六条边。其自身依赖清单在根 MODULE.bazel 中极为庞大,涵盖:

  • 协议与传输grpcnghttp2quiche(HTTP/3)、c-aresbrotlizstdzlib-ng
  • TLS/加密boringsslboringssl-fipsboringssl-sourceopenssl(供兼容构建)、tcmallocjemalloc
  • 执行引擎v8(Wasm)、wasmtimewamrproxy-wasm-cpp-hostproxy-wasm-cpp-sdkproxy-wasm-rust-sdk
  • 可观测性opentelemetry-cppopentelemetry-protozipkin-apiprometheus-metrics-modelperfetto
  • 规则与编译体系rules_ccrules_gorules_javarules_rustrules_pythonrules_protorules_swifttoolchains_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的依赖边:移动端库构建在核心envoyenvoy_api之上,同时直接依赖envoy_toolshedenvoy_build_config以及 Android/iOS 相关规则(rules_androidrules_applerules_kotlinrules_swiftrules_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 --> examplesenvoy-examples依赖主模块(官方示例配置均针对envoy构建);
  • envoy --> filter_ccapi --> filter_ccenvoy-example-filter-cc(C++ 扩展过滤器示例)同时依赖主模块与 API 模块;
  • envoy --> wasm_ccenvoy-example-wasm-cc(Wasm 过滤器示例)依赖主模块;
  • filter_cc --> exampleswasm_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_overrideenvoyenvoy_apienvoy-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. """, )

其实现流程为:

  1. 读取根 MODULE.bazel.lock 中的registryFileHashes字段;
  2. 解析其中指向 Bazel 模块仓库(/modules/<name>/<version>/source.json)的 URL,还原出每个模块的module_nameversionregistry
  3. 将解析结果编码为@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.lockmoduleExtensions/modules段的记录。

八、如何核对与扩展这张依赖图

若读者希望基于当前仓库验证或更新这张图,可遵循以下路径:

  1. 核对节点声明:逐个打开 MODULE.bazel、api/MODULE.bazel、mobile/MODULE.bazel、docs/MODULE.bazel、bazel/tests/external/MODULE.bazel,确认module(name=...)bazel_dep(...)是否与图中边一致;
  2. 核对版本一致性:图中envoyenvoy_apienvoy_mobileenvoy-docs均围绕1.40.0-dev版本发布,envoy_toolshed固定为0.4.15.envoy,示例模块envoy-examples0.2.6.envoy,可在各MODULE.bazel中逐一比对;
  3. 查看解析结果:以根 MODULE.bazel.lock 与 bazel/tests/external/MODULE.bazel.lock 为准,确认 lockfile 中记录的模块依赖与发布图吻合;
  4. 理解扩展生成物:结合 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作为根提供工具链地基,envoyenvoy_api作为核心模块向外供给能力,envoy_mobileenvoy-docsenvoy-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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询