☰
OpenTelemetry Go 多模块发布流程全解:从 Semantic Convention 生成到 Tag 与 Release 的完整操作手册
2026/9/26 2:56:33 网站建设 项目流程
  • 操作系统
  • 云原生
  • 容器运行时

【免费下载链接】linuxkit

A toolkit for building secure, portable and lean operating systems for containers

项目地址:https://gitcode.com/gh_mirrors/li/linuxkit
点击查看免费下载

导读

本文以 OpenTelemetry Go 官方仓库的 RELEASING.md 为骨架,完整还原其多模块(multi-module)发布流程:包括 Semantic Convention 代码生成、Breaking Change 校验、Pre-Release 版本号变更、Git Tag 打标与 Release 创建,以及发布后的 contrib 仓库、官网文档与 Demo 仓库的联动更新。读完本文,你将掌握一套可复用的 Go 多模块仓库版本发布 SOP,并能理解Makefile、versions.yaml、CHANGELOG.md等文件在发布链路中的具体角色。

说明:本文所引用文档位于当前仓库的 vendored 依赖目录pkg/init/vendor/go.opentelemetry.io/otel/下,属于 OpenTelemetry Go 官方源码随依赖一并 vendored 进 linuxkit 仓库的产物。文中的路径均以仓库根目录为起点,读者可直接点击进入原文继续深入。


一、为什么要有一套专门的发布流程:多模块仓库的版本困境

OpenTelemetry Go(go.opentelemetry.io/otel)不是一个单一 Go module,而是一个由数十个 module 组成的仓库。在 versions.yaml 中可以看到,仓库按module set(模块集)组织版本线:

  • stable-v1:主版本线v1.31.0,包含核心go.opentelemetry.io/otel、sdk、sdk/metric、trace、metric以及各类 exporter(otlpgrpc / otlphttp / stdout / zipkin)等稳定模块;
  • experimental-metrics:v0.53.0,包含 prometheus exporter 等实验模块;
  • experimental-logs:v0.7.0,包含log、sdk/log等日志信号模块;
  • experimental-schema:v0.0.10,包含schema模块;
  • excluded-modules:internal/tools这类仅供仓库内部使用的模块不参与发布。

这种结构决定了发布动作必须一次性、原子性地作用于整个模块集,而不是单个包。Makefile 中几乎所有发布相关 target(prerelease、add-tags、gorelease)都依赖$(MULTIMOD)工具(go.opentelemetry.io/build-tools/multimod,见 Makefile)和verify-mods前置校验,目的就是保证模块集内所有 module 的版本一致、依赖互相指向新版本。

因此整个发布流程被拆成五个阶段:Semantic Convention 生成 → Breaking Change 校验 → Pre-Release → Tag → Release → Post-Release,每一步都有对应的 make target 和人工校验点。


二、Semantic Convention 生成:make semconv-generate

OpenTelemetry 语义约定(Semantic Conventions)是各语言 SDK 共享的规范。每当 OpenTelemetry Semantic Conventions 发布新版本,semconv包就需要重新生成,这是版本升级的前置步骤。

2.1 操作步骤(原文完整流程)

export TAG="v1.21.0" # 改为你要生成的目标语义约定版本 export OTEL_SEMCONV_REPO="/absolute/path/to/opentelemetry/semantic-conventions" docker pull otel/semconvgen:latest make semconv-generate # 使用上面导出的 TAG 和 OTEL_SEMCONV_REPO

具体三步为:

  1. 将 OpenTelemetry Semantic Conventions 仓库检出(checkout)到目标 release tag 的本地副本;
  2. 拉取最新otel/semconvgen镜像:docker pull otel/semconvgen:latest;
  3. 在本仓库执行make semconv-generate ...。

执行成功后会在semconv下生成一个新的子包(按版本号命名)。提交 Pull Request 前务必人工核对生成结果是否正确。

2.2 源码级解读:Makefile 中发生了什么

在 Makefile 中,semconv-generate的实际逻辑是:

SEMCONVPKG ?= "semconv/" .PHONY: semconv-generate semconv-generate: $(SEMCONVGEN) $(SEMCONVKIT) [ "$(TAG)" ] || ( echo "TAG unset: missing opentelemetry semantic-conventions tag"; exit 1 ) [ "$(OTEL_SEMCONV_REPO)" ] || ( echo "OTEL_SEMCONV_REPO unset: missing path to opentelemetry semantic-conventions repo"; exit 1 ) $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=attribute_group -p conventionType=trace -f attribute_group.go -t "$(SEMCONVPKG)/template.j2" -s "$(TAG)" $(SEMCONVGEN) -i "$(OTEL_SEMCONV_REPO)/model/." --only=metric -f metric.go -t "$(SEMCONVPKG)/metric_template.j2" -s "$(TAG)" $(SEMCONVKIT) -output "$(SEMCONVPKG)/$(TAG)" -tag "$(TAG)"

可以提炼出几个关键点:

  • 两个环境变量缺一不可:TAG(语义约定版本)和OTEL_SEMCONV_REPO(语义约定仓库本地路径)。Makefile 里用显式[ "$(TAG)" ] || exit 1做了强校验,缺失任一变量会直接终止;
  • SEMCONVGEN是构建工具:包名为go.opentelemetry.io/build-tools/semconvgen(见 Makefile),以 Docker 镜像otel/semconvgen:latest提供运行环境;
  • 生成分两类模板:attribute_group模板生成attribute_group.go(trace 类型),metric模板生成metric.go,输入统一指向OTEL_SEMCONV_REPO/model/.(语义约定仓库的 model 目录,YAML 模型定义所在);
  • SEMCONVKIT负责落盘:包名为go.opentelemetry.io/otel/internal/tools/semconvkit,把生成结果输出到semconv/<TAG>/新子目录。

在当前 vendored 副本中,可以实际看到这一机制的历史产物:semconv 下存在v1.20.0/、v1.21.0/、v1.26.0/三个按版本号命名的子包——这正是多次semconv-generate运行留下的累积结果,也印证了“每次新版本生成一个新子包”的流程描述。


三、Breaking Changes 校验:make gorelease

语义化版本承诺(semver)要求公共 API 不能被破坏性修改。OpenTelemetry Go 用gorelease工具做自动校验:

make gorelease
  • 该 target 在 Makefile 中定义为遍历OTEL_GO_MOD_DIRS(即除internal/tools外的所有含go.mod的目录),对每个 module 依次执行gorelease;
  • gorelease工具来源为golang.org/x/exp/cmd/gorelease(见 Makefile),它通过对比两个版本(当前工作区 vs 上一个 tag)的公共 API 差异,输出破坏性变更报告;
  • 如果发现非预期的公共 API 变化,就需要在发布前修正,而不是等到用户升级依赖时才发现兼容性问题。

实践建议:把make gorelease纳入发布前的强制检查项,与 CI 中的 lint、测试、verify-mods同等对待。


四、contrib 仓库兼容性验证

主仓库(opentelemetry-go)的 API 变更往往会波及下游的 contrib 仓库(opentelemetry-go-contrib,即各类 instrumentation 库的集合)。RELEASING.md 明确要求:如果本次主仓库的变更可能影响 contrib 仓库,必须先按 contrib 仓库 RELEASING.md 中 "Verify OTel changes" 一节描述的步骤,验证变更与 contrib 仓库的兼容性。

这一步是发布前的一层“影响面审计”,避免主仓库发布后立即破坏大量下游 instrumentation 包的编译。


五、Pre-Release:版本号变更与 Changelog 整理

5.1 决定发布哪些模块集并更新 versions.yaml

发布的第一步是决策:本次要发布哪些 module set。决定后,在versions.yaml中更新对应 module set 的version字段(例如把stable-v1从v1.31.0改到v1.32.0),并把这个改动提交到一个新分支上。

紧接着要更新各个子模块的go.mod,让它们依赖即将发布的新版本(即后续步骤才会真正打出的 tag)。

5.2 执行make prerelease

make prerelease MODSET=<module set>

其底层实现在 Makefile:

.PHONY: prerelease prerelease: verify-mods @[ "${MODSET}" ] || ( echo ">> env var MODSET is not set"; exit 1 ) $(MULTIMOD) prerelease -m ${MODSET}

要点:

  • MODSET是必填环境变量,不设置会直接报错退出;MODSET的值即versions.yaml中定义的模块集名字,如stable-v1、experimental-logs;
  • 前置步骤verify-mods调用$(MULTIMOD) verify,先校验各模块集配置的一致性;
  • 执行后multimod会创建一个形如prerelease_<module set>_<new tag>的分支,该分支包含本次发布的所有版本变更(各子模块 go.mod 的依赖版本、versions.yaml 的版本号等)。

5.3 人工核对变更

git diff ...prerelease_<module set>_<new tag>

核对点:所有模块的版本是否都已被改为<new tag>。确认无误后,将该分支合并进你的 pre-release 分支:

git merge prerelease_<module set>_<new tag>

5.4 更新 Changelog

RELEASING.md 对 Changelog 的维护有明确规范:

  1. 完整性:确保本次发布的所有相关变更都已收录,且语言要能让非贡献者看懂。可用以下命令直接核对自上个 tag 以来的提交:

    git --no-pager log --pretty=oneline "<last tag>..HEAD"
  2. 归档 Unreleased:把所有Unreleased下的变更移入新章节,标题遵循[<new tag>] - <date of release>格式。在 CHANGELOG.md 中可以看到实际格式,例如## [1.31.0/0.53.0/0.7.0/0.0.10] 2024-10-11——多版本线同时发布时用/分隔;

  3. 位置约束:新章节必须放在<!-- Released section -->注释之下,避免未来被自动化脚本覆盖(该注释在 CHANGELOG.md 中可见);

  4. 更新底部链接:同步更新文末的链接索引。

5.5 推送并创建 Pull Request

将改动推送到上游,创建 Pull Request。PR 描述中务必附带从 Changelog 中整理出的发布说明(curated changes),方便评审者与用户直接了解本次发布内容。


六、Tag:打标与推送(最容易出错的一步)

6.1 为什么 Tag 必须与 Pre-Release 一致

PR 合并后,需要对合并 commit 打 tag。RELEASING.md 用两个***IMPORTANT***强调了打标环节的风险:

  1. Tag 必须与 Pre-Release 步骤中使用的 tag 完全一致。如果 Pre-Release 与打标之间修改了versions.yaml,会导致发布状态错乱;
  2. Go module 的 tag 一旦打错就无法移除(Go 模块代理缓存了错误的版本),错误版本一旦推送上游,会引发连锁的线上事故,且难以补救。因此推送前务必反复确认版本号正确。

6.2 打标命令

对每个要发布的 module set,在主干分支合并 PR 的那个 commit 上执行:

make add-tags MODSET=<module set> COMMIT=<commit hash>
  • 只有当工作区当前HEAD不是目标 commit 时,才需要显式提供COMMIT值(Makefile 中COMMIT ?= "HEAD",见 Makefile);
  • 底层同样是multimod:$(MULTIMOD) tag -m ${MODSET} -c ${COMMIT},它会为模块集内每个 module打上对应路径前缀的 tag。

6.3 推送 tag(含所有子模块)

git push upstream <new tag> git push upstream <submodules-path/new tag> ...

注意:

  • 推送目标是上游 remote(github.com/open-telemetry/opentelemetry-go.git),不是自己的 fork;
  • 必须逐个推送所有子模块的 tag(例如sdk/metric/v1.32.0这类带路径前缀的 tag),漏推任何一个都会导致对应 module 无法被go get解析。

七、Release:创建 GitHub Release

打标完成后,为新的<new tag>在 GitHub 上创建 Release:

  • Release body 必须包含本次发布的全部 Changelog 发布说明(所有 release notes);
  • 这一步通常与打标在同一天完成,保证 tag 与 Release 一一对应。

八、Post-Release:发布后的三处联动更新

8.1 contrib 仓库

主仓库验证通过后,需要立即为使用该版本的 contrib 仓库发布新版本,让下游 instrumentation 能同步升级到新依赖。

8.2 官网 Go 语言文档

更新 OpenTelemetry 官网中 Go 语言的 instrumentation 文档(content/en/docs/languages/go目录):

  • 将文档中引用的各包版本号升级为刚发布的最新版本;
  • 确保文档中所有代码示例仍能编译、内容准确。

8.3 Demo 仓库

升级 OpenTelemetry Demo 仓库中以下 Go 服务的依赖:

  • accountingservice
  • checkoutservice
  • productcatalogservice

这三处升级属于“发布收尾”动作,目的是让示例与真实 SDK 始终保持同步,避免示例代码用过时 API。


九、发布流程全景回顾与最佳实践

把整个流程串起来,一次完整发布的操作序列如下:

阶段命令 / 操作关键产物验证手段
Semconv 生成docker pull otel/semconvgen:latest+make semconv-generatesemconv/<TAG>/新子包人工核对生成代码
API 校验make goreleasegorelease 兼容性报告无破坏性 API 变更
影响面审计按 contrib 仓库流程验证兼容性结论contrib 仓库编译/测试
Pre-Release改versions.yaml+make prerelease MODSET=...prerelease_<modset>_<tag>分支git diff核对版本号
Changelog归档 Unreleased、更新链接新版本章节git log <last tag>..HEAD对照
Tagmake add-tags MODSET=... COMMIT=...+git push upstream各 module tag核对 tag 与 prerelease 一致
ReleaseGitHub 创建 ReleaseRelease notesbody 含完整 Changelog
Post-Releasecontrib 发布、官网文档、Demo 依赖升级同步更新文档可编译、Demo 可运行

结合仓库源码可以提炼出几条通用最佳实践,适用于任何 Go 多模块仓库:

  1. 用versions.yaml集中管理模块集版本,发布决策只改一处;
  2. 让make prerelease这类自动化工具负责机械性的版本替换,人工只做git diff审查;
  3. Tag 是发布流程中唯一“不可逆”的操作,Go module 代理会永久缓存错误版本,所以打标前必须三查(版本号、commit、与 prerelease 一致性);
  4. Changelog 用<!-- Released section -->注释做“写保护”,避免后续自动化流程覆盖已发布的历史记录;
  5. 发布不是终点,contrib 仓库、官网文档、官方 Demo 的联动升级才能保证整个生态步调一致。

十、本仓库中的落点:vendored 副本的意义

这份 RELEASING.md 在当前仓库中位于 pkg/init/vendor/go.opentelemetry.io/otel/RELEASING.md,是 linuxkit 的 init 组件依赖 OpenTelemetry Go SDK 时随 vendor 目录一并带入的官方文档。它所在的 otel 目录 完整保留了官方仓库的核心文件——Makefile、versions.yaml、CHANGELOG.md、VERSIONING.md 以及 semconv 下的多个版本子包——这本身就构成了验证本文所述流程的“活标本”:你可以在 vendored 副本中直接查看versions.yaml的多版本线结构、比对 CHANGELOG 的[1.31.0/0.53.0/0.7.0/0.0.10]多版本格式、浏览semconv/v1.20.0、semconv/v1.21.0、semconv/v1.26.0等历次生成产物,从而把发布流程文档与真实仓库状态一一对应起来。对于负责维护该依赖的开发者而言,理解这套发布机制也有助于判断何时需要升级 vendor 中的 OTel 版本,以及升级时应该关注哪些兼容性风险。

  • 操作系统
  • 云原生
  • 容器运行时

【免费下载链接】linuxkit

A toolkit for building secure, portable and lean operating systems for containers

项目地址:https://gitcode.com/gh_mirrors/li/linuxkit
点击查看免费下载
上一篇:3阶段掌握AI模型微调:kohya_ss深度应用指南
下一篇:Unity游戏微信小游戏终极适配指南:5大架构解析与完整性能优化实战

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询