OpenTelemetry Go 多模块版本发布流程深度指南:从 semconv 升级、模块集打 tag 到 GPG 签名
【免费下载链接】kubernetesProduction-Grade Container Scheduling and Management项目地址: https://gitcode.com/GitHub_Trending/kuber/kubernetes
本文以当前仓库 vendored 的go.opentelemetry.io/otel模块(位于 vendor/go.opentelemetry.io/otel)自带的发布流程文档 vendor/go.opentelemetry.io/otel/RELEASING.md 为主体,完整讲解其官方版本发布全流程:如何升级并重新生成 Semantic Conventions 代码、如何用multimod工具对多个 module set 统一改版本、如何校验 API 兼容性、如何给数十个 Go 子模块打 tag、如何按 CNCF 规范签名发布产物并维护里程碑。读懂本指南后,你将掌握一套可用于任何 Go 多模块仓库的、可复现的版本发布 SOP。
背景说明:
opentelemetry-go是 Kubernetes 通过 Go module 机制 vendored 的第三方遥测依赖,其整棵仓库源码连同Makefile、versions.yaml、CHANGELOG.md都原样保留在vendor/go.opentelemetry.io/otel/下。因此本文中所有命令、Makefile 目标与配置均可在该目录中直接核对。
一、发布总览与整体节奏
一次完整的 OpenTelemetry Go 发布按以下阶段推进,每个阶段都有对应的 Makefile 目标或人工操作:
- 创建
Version Release跟踪 issue; - 若有新的语义约定(Semantic Conventions)上游 tag,则执行Semantic Convention Upgrade(生成新
semconv子包、替换全库 import); - 执行Breaking changes validation(
make gorelease)与contrib 仓库兼容性验证; - 进入Pre-Release:在
versions.yaml中决定发布哪些 module set 与版本号,用make prerelease生成改动分支; - 更新 Changelog 并提 PR 合入;
- 执行Tag:用
make add-tags给主模块与所有子模块打 tag 并推送; - 下载归档并做GPG 签名(CNCF 合规要求);
- 在 GitHub 创建Release(归档不可后补);
- 执行Post-Release:发布 contrib、更新官网文档、收尾里程碑并关闭 issue。
从该目录的 Makefile 可以看到,发布相关的工具统一由internal/tools子模块构建到.tools/下:MULTIMOD = $(TOOLS)/multimod(来自go.opentelemetry.io/build-tools/multimod)、GORELEASE(来自golang.org/x/exp/cmd/gorelease)、SEMCONVKIT(来自本仓库internal/tools/semconvkit)——这正是下述各make目标背后真正的执行者。
二、发布前置:创建Version Releaseissue
第一步是创建一个Version Release类型的 issue,用其 todo 列表跟踪整个发布过程,从 semconv 升级到打 tag、签名、收尾里程碑,每完成一项勾选一项,最终发布完成后关闭该 issue(见文档原句与下文"关闭 issue"环节)。
三、Semantic Convention 升级(升级前最易出错的环节)
OpenTelemetry 的语义约定(HTTP、DB、Messaging 等跨语言共享的 attribute 定义)由独立的上游仓库发布新版本。上游每发一版,就意味着本仓库需要生成新版本的semconv代码包。
3.1 用semconv-generate生成新版本子包
文档给出的标准流程是:先设置TAG环境变量为要生成的语义约定版本号,再执行make semconv-generate:
export TAG="v1.30.0" # 换成你要生成的版本号 make semconv-generate # 使用导出的 TAG命令执行后会在semconv目录下产生一个新的版本子包。对照 Makefile 可看到该目标实际做了什么:
- 从 dependencies.Dockerfile 中解析出
weaver镜像(WEAVER_IMAGE); - 强制要求
TAG非空,否则报错退出; - 创建
semconv/<TAG>目录,然后以 Docker bind mount 方式把本仓库的semconv/templates与新建的<TAG>目录挂进容器,从https://github.com/open-telemetry/semantic-conventions/archive/refs/tags/$(TAG).zip拉取上游约定模型,用registry generate产出 Go 代码; - 最后用
semconvkit工具对产物做校验与整理。
当前 vendored 快照中 semconv 目录下已存在v1.37.0、v1.40.0、v1.41.0三个版本子包,每个子包都包含attribute_group.go、error_type.go、exception.go、schema.go以及独立的httpconv、otelconv转换包——这就是多次执行上述流程留下的历史产物。
3.2 更新 CHANGELOG 并提交新增包
生成完新子包后需要向仓库提交 PR 合入,并同步更新CHANGELOG.md,追加一条符合下述格式的记录(把<NEW VERSION>、<PREVIOUS VERSION>、#PR_NUMBER替换为实际值,见 CHANGELOG.md 的Added章节惯例):
- The `go.opentelemetry.io/otel/semconv/<NEW VERSION>` package. The package contains semantic conventions from the `<NEW VERSION>` version of the OpenTelemetry Semantic Conventions. See the [migration documentation](https://link.gitcode.com/i/0ecd447125517fd85f3b4b6c4b74a1df) for information on how to upgrade from `go.opentelemetry.io/otel/semconv/<PREVIOUS VERSION>`. (#PR_NUMBER)提示:把条目中的"本次版本"与"上一版本"都改对,保持与仓库内实际 semconv 版本链一致。例如当前目录中每个
semconv/v1.x.y子包都带一份 MIGRATION.md,供使用方做跨版本迁移参考。
3.3 更新全库 semconv imports
新模块生成后,代码库中所有对旧 semconv 的引用都要切换为新版本,文档给出的迁移前后对照如下:
// Before semconv "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/otel/semconv/v1.37.0/otelconv" // After semconv "go.opentelemetry.io/otel/semconv/v1.39.0" "go.opentelemetry.io/otel/semconv/v1.39.0/otelconv"替换完毕后运行make(顶层 Makefile 的默认目标为precommit,内含 generate、gofmt、lint、verify-mods、test 等全套自检)确认没有编译或测试失败。
3.3.1 属性变更的处理(attribute changes)
部分 semconv 版本可能新增属性,也可能影响正在使用的属性——可能是简单的改名,也可能是合并属性、修改属性取值等更复杂的变化。处理原则是:代码应迁移到语义约定中的新属性上;但对于被取代的旧属性,是否继续按旧名发射,受OTEL_SEMCONV_STABILITY_OPT_IN环境变量控制(即遵循约定中"稳定属性可选 opt-in 旧行为"的机制)。文档给出一个完整的迁移追踪案例可参考:opentelemetry-go 仓库 issue #7806。
3.4 同步 go-contrib 仓库的 linter 约束
由于本仓库升级了 semconv 主版本,配套的opentelemetry-go-contrib仓库也需要同步修改其.golangci.yml,强制使用新的 semconv 版本,避免 contrib 继续编译旧的约定包。
四、Breaking changes 校验与 contrib 兼容性验证
在正式改版本号之前,需先确认本次改动没有破坏公共 API。
4.1make gorelease公共 API 校验
运行:
make gorelease该命令逐个 module 调用 gorelease 工具,用于检测公共 API 是否存在计划外的破坏性变更。从 Makefile 可以看出其实现:gorelease目标展开为对所有go.mod目录(OTEL_GO_MOD_DIRS,即排除internal/tools外的全部子模块)逐一执行gorelease/%,进入每个目录后运行 gorelease 检查。
如果发现 gorelease 本身存在问题,可在 https://golang.org/issues/26420 跟踪反馈。
4.2 验证对 contrib 仓库的影响
如果本仓库改动会影响 contrib 仓库,应按照 contrib 仓库RELEASING.md中的 "Verify OTel changes" 一节先行验证二者兼容性,确保下游不出问题。
五、Pre-Release:确定 module set 版本并生成改动
OpenTelemetry Go 是一个多模块仓库,不同模块走不同版本号。版本编排全部集中在 versions.yaml,其中用module-sets定义了四个模块集,每个模块集有独立版本:
| module set | 当前版本(vendored 快照) | 包含的典型模块 |
|---|---|---|
stable-v1 | v1.44.0 | go.opentelemetry.io/otel、metric、sdk、sdk/metric、trace、exporters/otlp/*、exporters/zipkin、bridge/opencensus、bridge/opentracing等 |
experimental-metrics | v0.66.0 | exporters/prometheus、metric/x |
experimental-logs | v0.20.0 | log、sdk/log、exporters/otlp/otlplog/*、exporters/stdout/stdoutlog |
experimental-schema | v0.0.17 | schema |
同时文件还用excluded-modules排除internal/tools与trace/internal/telemetry/test这类不参与独立发版的内部模块,用modules+version-refs声明个别模块(如exporters/stdout/stdouttrace、exporters/prometheus等)的版本引用要同步写到其internal/version.go中,保证"编译期版本号常量"与发布版本一致。
发布时的第一步,就是决定本次要发布哪些 module set,把versions.yaml中对应version改为新版本号,并提交到一个新分支。
5.1 运行 prerelease
随后在仓库中运行 prerelease 目标:
make prerelease MODSET=<module set>它会生成一个名为prerelease_<module set>_<new tag>的分支,包含所有版本改动(例如把所有 go.mod 的依赖指向即将发布的新版本)。对照 Makefile,该目标先执行verify-mods(即multimod verify,校验 versions.yaml 与各 go.mod 一致性),再执行$(MULTIMOD) prerelease -m ${MODSET},且强制要求设置MODSET环境变量。
5.2 核对改动并合入发布分支
git diff ...prerelease_<module set>_<new tag>该 diff 应把所有相关模块的版本统一改为<new tag>。确认无误后合入你的 pre-release 分支:
git merge prerelease_<module set>_<new tag>5.3 更新 Changelog
版本改动就绪后,同步维护 CHANGELOG.md:
- 确保本次发布所有相关改动都收录,且语言要能让非本项目贡献者读懂。可用下面的命令直接核对自上一个 tag 以来的提交:
git --no-pager log --pretty=oneline "<last tag>..HEAD" - 把
Unreleased下的改动整体移入一个新章节,标题格式为[<new tag>] - <date of release>(对照真实文件的写法,如 CHANGELOG.md 中的## [1.44.0/0.66.0/0.20.0/0.0.17] 2026-05-27,一次多模块发布可在一个标题里并列列出各 module set 版本); - 新章节必须放在
<!-- Released section -->注释之下,避免将来被工具覆盖(该仓库正是用这条注释来划分"已发布区"与"Unreleased 区",详见 CHANGELOG.md); - 更新文件底部所有版本间 compare 链接。
5.4 推送并提 PR
把改动推送到 upstream,并在 GitHub 创建 Pull Request,PR 描述中要包含上述精选过的 Changelog 内容。
六、Tag:给每个子模块打标签并推送
当包含全部版本改动的 PR 被合入主干后,即可对合入 commit 打 tag。
两个关键警告(文档原意):
- 必须使用与 Pre-Release 阶段完全相同的 tag;只要在 prerelease 与 tag 之间不修改
versions.yaml,就不会出错,否则仓库会处于损坏状态。- Go 模块一旦错误打 tag,目前没有删除已错误标记的 Go 模块版本的办法(对应 golang/go#34189),错误推送会引发难以绕过的紧急问题,因此推送前务必确认版本号正确。
6.1 运行 add-tags
对每个要发布的 module set 执行:
make add-tags MODSET=<module set> COMMIT=<commit hash>COMMIT取合入 PR 后主干上的 commit hash。只有当前工作区HEAD不是正确 commit 时才必须显式传COMMIT。对照 Makefile,它同样先跑verify-mods,再执行$(MULTIMOD) tag -m ${MODSET} -c ${COMMIT}——也就是由 multimod 依据versions.yaml里该 module set 的模块清单,为每一个子模块打上<path>/<version>格式的 tag。
6.2 推送所有 tag
把 tag 推到 upstream(注意不是你的 fork):
git push upstream <new tag> git push upstream <submodules-path/new tag> ...需要把主模块 tag 与全部子模块 tag 一并推送。
七、签名发布产物(CNCF 合规)
为符合 CNCF 最佳实践,需要对发布产物做 GPG 签名。
- 从新 tag 的 tags 页面下载对应的
.tar.gz与.zip归档; - 签名前可用官方辅助脚本先核对归档内容;
- 查询本机 GPG 密钥 ID:
gpg --list-secret-keys --keyid-format=long密钥 ID 即
sec rsa4096/之后(或类似位置)的 16 位字符串; - 设置环境变量并对两份归档做分离式 ASCII 签名:
export VERSION="<version>" # 例如 v1.32.0 export KEY_ID="<your-gpg-key-id>" gpg --local-user $KEY_ID --armor --detach-sign opentelemetry-go-$VERSION.tar.gz gpg --local-user $KEY_ID --armor --detach-sign opentelemetry-go-$VERSION.zip - 校验签名:
gpg --verify opentelemetry-go-$VERSION.tar.gz.asc opentelemetry-go-$VERSION.tar.gz gpg --verify opentelemetry-go-$VERSION.zip.asc opentelemetry-go-$VERSION.zip
最终会得到.tar.gz、.tar.gz.asc、.zip、.zip.asc四份产物。
八、创建 GitHub Release
最后为<new tag>在 GitHub 上创建 Release,正文应包含本次发布对应的全部 Changelog release notes。
重要:GitHub Releases 一经创建即不可变。签名产物(
.tar.gz、.tar.gz.asc、.zip、.zip.asc)必须在创建 Release 时就上传,之后无法再追加或修改。
九、Post-Release 收尾
9.1 发布 contrib 仓库
确认无误后,应基于本次发布为opentelemetry-go-contrib仓库制作对应 release(该仓库有自己的 RELEASING.md 流程)。
9.2 更新官网 Go 文档
同步更新 OpenTelemetry 官网中content/en/docs/languages/go目录下的 Go instrumentation 文档:把引用的包版本号 bump 到刚发布的版本,并确保所有代码示例仍可编译、内容准确。
9.3 关闭里程碑
发布后,把本版本修复的所有 issue 与合入的所有 PR 归入对应里程碑,便于追踪每次发布包含的改动:
- 用仓库内的搜索条件找出尚未归入里程碑的已关闭 issue(
is:issue no:milestone is:closed reason:completed等条件组合); - 找出尚未归入里程碑的已合入 PR(
is:pr no:milestone is:merged)。
全部归入后关闭该里程碑。
9.4 关闭Version Releaseissue
Version Releaseissue 中的 todo 全部完成后,关闭该 issue,一次发布正式结束。
十、结语:把发布流程沉淀为可核对的 SOP
回顾整个流程可以看出,opentelemetry-go 的发布高度工具化:versions.yaml是唯一的版本事实来源,multimod负责按 module set 统一改版本与打 tag,semconv-generate通过 weaver 容器把语义约定模型转成 Go 代码,gorelease守护公共 API 兼容性,GPG 签名满足 CNCF 产物合规,CHANGELOG 的<!-- Released section -->注释机制则保证发布历史不被后续改写覆盖。
这些机制全部可以在当前仓库的 versions.yaml、Makefile 与 CHANGELOG.md 中逐一印证;对于需要维护"一主仓多子模块"版本的 Go 项目而言,这套由 issue 驱动、工具兜底、人工复核的发布 SOP 本身就是一份极佳的工程参考。
【免费下载链接】kubernetesProduction-Grade Container Scheduling and Management项目地址: https://gitcode.com/GitHub_Trending/kuber/kubernetes
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考