使用 OpenTelemetry Collector Builder 定制 Jaeger 发行版:components/ 公共 API 与 ocb 装配实战
【免费下载链接】jaegerCNCF Jaeger, a Distributed Tracing Platform项目地址: https://gitcode.com/GitHub_Trending/ja/jaeger
Jaeger V2 已全面基于 OpenTelemetry Collector 构建,而components/目录正是面向外部开发者开放的一组公共 API,用于通过 ocb(OpenTelemetry Collector Builder)自由拼装属于自己的 Jaeger 发行版。本文将围绕 components/README.md 展开,深入解读目录布局、双重派发模式与第三方组件别名机制,并结合 cmd/jaeger/builder.yaml 与 cmd/jaeger/internal/components.go 的源码证据,给出从零编写 builder.yaml 到产出可运行二进制的完整实战方案。
components/ 目录的定位:自定义发行版的公共 API
Jaeger 的“定制发行版”(custom distribution)机制由来已久,其设计决策记录在 docs/adr/011-custom-distributions.md 中。简单来说,Jaeger 希望开发者不必 fork 整个仓库、不必改动 Jaeger 核心代码,就能通过一份清单文件把需要的组件(receiver、processor、exporter、extension、connector、telemetry)组装成一个全新的、可独立发布的二进制。
components/目录就是这个机制对外暴露的唯一公共面。正如其 README 开头所写,该目录提供的是"构建自定义 Jaeger 发行版的公共 API",核心工具是 ocb(OpenTelemetry Collector Builder)。ocb 读取一份builder.yaml清单,自动生成并编译一个仅包含清单中所列组件的 Collector 二进制——Jaeger V2 的默认发行版正是用同一套流程产出的。
与这一目标相对应,components/目录内部刻意做了职责切分:
- 顶层包(
extension/、exporter/、processor/、telemetry/):Jaeger 专属组件,即只存在于 Jaeger 生态、由 Jaeger 自己维护实现的组件; ext/:第三方 OTel Collector 组件,来自 otel-contrib 与 collector core,仓库内只保留"一行别名"式的转发声明;cmd/jaeger/components/:位于cmd/jaeger子树内的桥接层,负责突破 Gointernal包访问限制(详见下文"双重派发"一节)。
目录布局解读:两层结构,各司其职
顶层包:Jaeger 专属组件与双重派发模式
顶层包包括components/extension/、components/exporter/、components/processor/、components/telemetry/,容纳的是 Jaeger 自研组件,例如:
extension/jaegerstorage:接入 Jaeger 存储后端(Cassandra、Elasticsearch、Badger 等)的扩展;extension/jaegerquery:提供 Jaeger Query 服务的扩展;extension/remotesampling:远程采样策略管理扩展;extension/expvar:暴露 Goexpvar指标;extension/remotestorage:远程存储服务扩展;exporter/storageexporter:通用的"写入 Jaeger v1 spanstore.SpanWriter"导出器;processor/adaptivesampling:自适应采样处理器;telemetry:Jaeger 的遥测工厂。
这些组件之所以需要一套特殊的"双重派发"(double-dispatch)结构,根因是Go 语言的internal包访问限制:只有位于cmd/jaeger/子树内的代码才能导入cmd/jaeger/internal/,而公共的components/目录在该子树之外,无法直接引用内部实现。为此,仓库在cmd/jaeger/components/下放置了一层桥接包,每个包只有一个小小的factory.go,例如 cmd/jaeger/components/extension/jaegerstorage/factory.go:
package jaegerstorage import impl "github.com/jaegertracing/jaeger/cmd/jaeger/internal/extension/jaegerstorage" var NewFactory = impl.NewFactory而公共门面(facade)再对这一桥接层做一次别名转发,例如 components/extension/jaegerstorage/factory.go:
package jaegerstorage import impl "github.com/jaegertracing/jaeger/cmd/jaeger/components/extension/jaegerstorage" var NewFactory = impl.NewFactory这样便形成了一条完整的调用链:公共门面 → 桥接层 → 内部实现。外部使用者只依赖components/下的公共包,内部实现细节则始终被internal规则保护。桥接层的设计说明完整记录在 cmd/jaeger/components/README.md 中。
ext/:第三方组件的一行别名
与 Jaeger 专属组件不同,来自 otel-contrib 与 collector core 的第三方组件完全绕开双重派发,通过components/ext/直接转发上游工厂。这些包同样是"一行别名",例如 components/ext/extension/healthcheckv2extension/factory.go:
package healthcheckv2extension import impl "github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckv2extension" var NewFactory = impl.NewFactory这种做法带来的关键收益是版本一致性:builder.yaml里所有第三方组件都可以通过同一个gomod条目(github.com/jaegertracing/jaeger)被引用,而无需逐个锁定上游组件的版本。各第三方组件的真实版本由 Jaeger 自己的go.mod传递解析,从而保证整个发行版内组件的版本互相兼容、同步升级。
用 ocb 构建发行版:builder.yaml 的写法
最小示例:公共 API 的使用方式
在自定义发行版的builder.yaml中,只需按 ocb 的清单格式引用上述公共包即可。以下示例摘自 components/README.md:
extensions: - gomod: github.com/jaegertracing/jaeger v2.19.0 import: github.com/jaegertracing/jaeger/components/extension/jaegerstorage - gomod: github.com/jaegertracing/jaeger v2.19.0 import: github.com/jaegertracing/jaeger/components/ext/extension/healthcheckv2extension两个字段的含义:
gomod:ocb 生成 go.mod 时使用的模块标识与版本。所有组件统一指向github.com/jaegertracing/jaeger及其某个发布版本(如v2.19.0),第三方组件的实际版本由此传递解析;import:该组件的 Go 导入路径,即上文components/下对应包的路径。
完整参考清单:cmd/jaeger/builder.yaml 逐节解析
cmd/jaeger/builder.yaml 是官方提供的完整参考清单,它精确复刻了 Jaeger 默认生产发行版的组件集合,同时充当文档与 CI 校验产物。其头部注释明确说明:清单中的组件列表与标准二进制使用的internal.Components()完全一致;而像storagecleaner这类仅用于测试的组件则两者都不包含,由 cmd/jaeger/internal/integration/jaeger-e2e 单独注册。
清单的顶层结构如下:
| 区块 | 说明 | 组件数量 |
|---|---|---|
dist | 发行版自身的模块名、二进制名、输出路径 | 1 |
telemetry | 遥测工厂 | 1 |
extensions | 扩展(含认证、健康检查、存储、采样等) | 10 |
receivers | 接收器(OTLP、Jaeger、Kafka、Zipkin 等) | 5 |
exporters | 导出器(调试、OTLP、Kafka、Prometheus、存储等) | 7 |
processors | 处理器(批处理、内存限制、尾采样、自适应采样等) | 6 |
connectors | 连接器(forward、spanmetrics) | 2 |
replaces | 仓库内构建时的本地替换指令 | 1 |
各区块的完整内容(已按官方清单整理):
dist: module: github.com/jaegertracing/jaeger/cmd/jaeger/ocb-build name: jaeger description: Jaeger - distributed tracing platform output_path: ./cmd/jaeger/_build telemetry: gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/telemetry extensions: - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/extension/healthcheckv2extension - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/extension/pprofextension - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/extension/zpagesextension - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/extension/basicauthextension - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/extension/sigv4authextension - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/extension/jaegerquery - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/extension/jaegerstorage - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/extension/remotesampling - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/extension/expvar - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/extension/remotestorage receivers: - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/receiver/otlpreceiver - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/receiver/nopreceiver - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/receiver/jaegerreceiver - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/receiver/kafkareceiver - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/receiver/zipkinreceiver exporters: - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/exporter/debugexporter - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/exporter/otlpexporter - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/exporter/otlphttpexporter - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/exporter/nopexporter - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/exporter/storageexporter - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/exporter/kafkaexporter - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/exporter/prometheusexporter processors: - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/processor/batchprocessor - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/processor/memorylimiterprocessor - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/processor/tailsamplingprocessor - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/processor/attributesprocessor - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/processor/filterprocessor - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/processor/adaptivesampling connectors: - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/connector/forwardconnector - gomod: github.com/jaegertracing/jaeger v0.0.0 import: github.com/jaegertracing/jaeger/components/ext/connector/spanmetricsconnector replaces: - github.com/jaegertracing/jaeger v0.0.0 => ../../../注意清单头部注释中的两个关键约定:
- 仓库内构建:所有组件使用
github.com/jaegertracing/jaeger v0.0.0作为gomod,配合replaces指令指向本地源码,这是为了在仓库内直接编译; - 外部使用:外部用户应把
v0.0.0替换为真实发布版本(例如v2.19.0),并删除replaces指令,让依赖从上游模块解析。
源码级装配原理:从清单到可运行二进制
builder.yaml描述的组件集合,与标准二进制实际注册的组件严格一一对应,这一对应关系在 cmd/jaeger/internal/components.go 的Components()函数中得到印证。该函数通过defaultBuilders().build()依次构造五类工厂映射:
- Extensions:标准部分(healthcheckv2、pprof、zpages)与"add-ons"(basicauth、sigv4auth、jaegerquery、jaegerstorage、remotesampling、expvar、remotestorage);
- Receivers:标准部分(otlp、nop)与 add-ons(jaeger、kafka、zipkin);
- Exporters:标准部分(debug、otlp、otlphttp、nop)与 add-ons(storageexporter——注释明确标注为"通用的 Jaeger v1 spanstore.SpanWriter 导出器"、kafka、prometheus),并保留了一行被注释掉的
elasticsearch.NewFactory(),说明该组件当前未纳入默认发行版; - Processors:标准部分(batch、memorylimiter、tailsampling、attributes、filter)与 add-ons(adaptivesampling);
- Connectors:标准部分(forward)与 add-ons(spanmetrics)。
所有工厂对象均来自components/公共包(import语句直接引用了github.com/jaegertracing/jaeger/components/...),这正验证了 README 所述——公共目录是唯一被内外共同消费的组件来源。ocb 生成的发行版在运行时按同样的工厂映射装配组件,只是入口从internal.Components()换成了清单驱动的代码生成。
构建命令与跨平台编译
参考清单的头部注释给出了完整的构建方式。在仓库内执行:
ocb --config cmd/jaeger/builder.yamlocb 会根据dist.output_path(./cmd/jaeger/_build)生成编译产物。跨平台编译通过 Go 标准的环境变量完成:
GOOS=linux GOARCH=arm64 ocb --config cmd/jaeger/builder.yamlocb 生成的二进制即为一个独立的 Jaeger 发行版,之后用 Jaeger V2 的配置文件(例如 cmd/jaeger/config.yaml)即可启动。仓库还提供了 cmd/jaeger/config-ocb-smoketest.yaml,用于对 ocb 产物做冒烟测试,可视为清单与配置联动的官方验证示例。
定制实战:如何添加自定义组件
ocb 清单的价值正在于"增删组件、重塑发行版"。官方推荐的做法是:复制 cmd/jaeger/builder.yaml,在相应区块末尾追加条目(extensions、receivers、exporters、processors、connectors 各有独立区块),然后运行 ocb 构建。
对于想深入了解"自定义组件长什么样"的读者,仓库内自带一个真实范例:components/extension/queryinterceptorexample/(含 factory.go、config.go、extension.go 及配套的 config-query-interceptor.yaml 与集成测试),演示如何编写一个拦截 Jaeger Query 请求的自定义扩展,是学习"如何为自定义发行版编写 Jaeger 专属组件"的最佳入门素材。
在动手定制时还需要留意以下事实(均可在清单注释与源码中验证):
- 若引入的是 Jaeger 自研组件,必须遵循
components/下的双重派发模式,确保内部实现不被internal规则阻断; - 若引入的是上游 OTel 第三方组件,应参照
components/ext/的别名写法,统一通过github.com/jaegertracing/jaeger这一个gomod条目引用,保持版本一致性; - 测试专用组件(如
storagecleaner)既不在builder.yaml也不在internal.Components()中,而是由 cmd/jaeger/internal/integration/jaeger-e2e 按需注册,因此生产发行版不应包含此类组件。
综上,components/目录 + ocb 的组合构成了 Jaeger 自定义发行版的完整工作流:公共 API 提供稳定的组件契约,ext/别名保证上游组件版本随 Jaeger 整体对齐,builder.yaml清单则让开发者用最少的配置组合出自己的分发二进制。无论是裁剪默认发行版、加入私有组件,还是构建面向特定存储与网络环境的专用版本,这套机制都能在不修改 Jaeger 核心的前提下完成。
【免费下载链接】jaegerCNCF Jaeger, a Distributed Tracing Platform项目地址: https://gitcode.com/GitHub_Trending/ja/jaeger
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考