OpenTelemetry Go 多模块版本发布流程深度指南:从 semconv 升级、模块集打 tag 到 GPG 签名
2026/9/9 19:44:50 网站建设 项目流程

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 的第三方遥测依赖,其整棵仓库源码连同Makefileversions.yamlCHANGELOG.md都原样保留在vendor/go.opentelemetry.io/otel/下。因此本文中所有命令、Makefile 目标与配置均可在该目录中直接核对。

一、发布总览与整体节奏

一次完整的 OpenTelemetry Go 发布按以下阶段推进,每个阶段都有对应的 Makefile 目标或人工操作:

  1. 创建Version Release跟踪 issue;
  2. 若有新的语义约定(Semantic Conventions)上游 tag,则执行Semantic Convention Upgrade(生成新semconv子包、替换全库 import);
  3. 执行Breaking changes validationmake gorelease)与contrib 仓库兼容性验证
  4. 进入Pre-Release:在versions.yaml中决定发布哪些 module set 与版本号,用make prerelease生成改动分支;
  5. 更新 Changelog 并提 PR 合入;
  6. 执行Tag:用make add-tags给主模块与所有子模块打 tag 并推送;
  7. 下载归档并做GPG 签名(CNCF 合规要求);
  8. 在 GitHub 创建Release(归档不可后补);
  9. 执行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.0v1.40.0v1.41.0三个版本子包,每个子包都包含attribute_group.goerror_type.goexception.goschema.go以及独立的httpconvotelconv转换包——这就是多次执行上述流程留下的历史产物。

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-v1v1.44.0go.opentelemetry.io/otelmetricsdksdk/metrictraceexporters/otlp/*exporters/zipkinbridge/opencensusbridge/opentracing
experimental-metricsv0.66.0exporters/prometheusmetric/x
experimental-logsv0.20.0logsdk/logexporters/otlp/otlplog/*exporters/stdout/stdoutlog
experimental-schemav0.0.17schema

同时文件还用excluded-modules排除internal/toolstrace/internal/telemetry/test这类不参与独立发版的内部模块,用modules+version-refs声明个别模块(如exporters/stdout/stdouttraceexporters/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:

  1. 确保本次发布所有相关改动都收录,且语言要能让非本项目贡献者读懂。可用下面的命令直接核对自上一个 tag 以来的提交:
    git --no-pager log --pretty=oneline "<last tag>..HEAD"
  2. 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 版本);
  3. 新章节必须放在<!-- Released section -->注释之下,避免将来被工具覆盖(该仓库正是用这条注释来划分"已发布区"与"Unreleased 区",详见 CHANGELOG.md);
  4. 更新文件底部所有版本间 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 签名。

  1. 从新 tag 的 tags 页面下载对应的.tar.gz.zip归档;
  2. 签名前可用官方辅助脚本先核对归档内容;
  3. 查询本机 GPG 密钥 ID:
    gpg --list-secret-keys --keyid-format=long

    密钥 ID 即sec rsa4096/之后(或类似位置)的 16 位字符串;

  4. 设置环境变量并对两份归档做分离式 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
  5. 校验签名:
    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),仅供参考

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

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

立即咨询