Grafana Loki 版本发布流程:如何安全补丁升级 Go 版本(Patch Go version)
2026/9/11 3:45:34 网站建设 项目流程

Grafana Loki 版本发布流程:如何安全补丁升级 Go 版本(Patch Go version)

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

导读

当上游 Go 官方发布安全修复版本后,使用受影响 Go 工具链构建的 Grafana Loki 二进制文件同样存在风险,维护者需要及时将易受攻击的 Go 版本升级为非易受攻击版本。本文基于 Loki 仓库中 patch-go-version.md 官方流程,完整讲解从定位目标版本、修改 Makefile、重新生成发布工作流,到提交 Pull Request 的全过程,并深入到 Makefile 目标、go-version-bump.sh脚本与 Jsonnet 生成管线的实现细节,帮助你在mainrelease-MAJOR.MINOR.x分支上独立完成一次 Go 版本补丁升级。

背景:为什么需要手动补丁 Go 版本

Loki 使用 Go 工具链构建所有二进制与容器镜像。Go 官方在发现安全漏洞(如标准库中的高危 CVE)后,会发布新的 patch 版本,例如从1.20.5升级到1.20.6。由于 Go 版本在 Loki 仓库中被多处以硬编码方式维护,只修改一处远远不够,因此官方流程要求按固定步骤统一更新。

从当前仓库(Makefile)可见:

# Ensure you run `make update-go-version` after changing this GO_VERSION := 1.26.6

Makefile 中明确注释了「修改后必须运行make update-go-version」,说明 Go 版本是一个需要联动更新的全局变量,而不是一处孤立的配置。

升级前置准备:确认目标 Go 版本

执行任何修改之前,先确定要升级到的具体 Go 版本号。判定依据包括:

  • Go 官方安全公告中标注的修复版本;
  • 通过漏洞扫描工具(如govulncheck)在当前构建工具链中检测到的受影响版本;
  • 目标发布分支(mainrelease-MAJOR.MINOR.x)当前使用的版本与期望版本之间的差异。

Loki 仓库本身也内置了govulncheck的 CI 检查(govulncheck.yml),它在 PR 涉及 Go 源码、go.modgo.sum变更时自动运行:

env: GO_VERSION: "1.26.6" GOVULNCHECK_VERSION: "v1.3.0"

并使用符号可达性分析(govulncheck -mode=source -show=verbose ./...)只报告从 main 包实际可达的漏洞,可以据此判断当前 Go 版本是否存在需要立即修补的问题。

第一步:修改 Makefile 中的 GO_VERSION

打开仓库根目录的 Makefile,将GO_VERSION更新为目标版本,例如:

GO_VERSION := 1.26.6 # 修改前:1.26.5

GO_VERSION在构建系统中承担着「单一事实来源」的角色,其下游使用点包括:

  • BUILD_IMAGE := golang:$(GO_VERSION)(Makefile):所有在容器内执行的构建(yacc/protobuf 生成、release 构建等)使用的基础镜像;
  • OCI_BUILD_ARGS := --build-arg GO_VERSION=$(GO_VERSION) --build-arg BUILD_IMAGE=$(BUILD_IMAGE)(Makefile):Docker / Buildx 构建 OCI 镜像时传入的构建参数;
  • goversion目标:@echo $(GO_VERSION)(Makefile),用于输出当前版本号。

第二步:运行 make release-workflows 重新生成发布工作流

Loki 的发布相关 GitHub Actions 工作流不是手写的 YAML,而是由 Jsonnet 模板生成的。修改 Go 版本后,必须重新生成这些工作流,否则发布流水线仍会使用旧的 Go 版本构建。

make release-workflows目标的定义如下(Makefile):

.PHONY: release-workflows release-workflows: ifeq ($(BUILD_IN_CONTAINER),true) $(run_in_container) else pushd $(CURDIR)/.github && jb update && popd jsonnet -SJ .github/vendor -m .github/workflows -V GO_VERSION=$(GO_VERSION) .github/release-workflows.jsonnet endif

该目标的行为取决于BUILD_IN_CONTAINER(默认true):

  • 默认情况下,整个生成过程在golang:$(GO_VERSION)容器内执行,保证工具链一致;
  • 若在本机执行(BUILD_IN_CONTAINER=false),则会先运行jb update拉取 jsonnet-bundler 依赖,再调用jsonnet将 release-workflows.jsonnet 渲染为.github/workflows/下的 YAML 文件,并通过-V GO_VERSION=$(GO_VERSION)把 Makefile 中的版本注入模板。

在 release-workflows.jsonnet 中可以看到版本的注入点:

local goVersion = std.extVar('GO_VERSION'); local buildImage = 'golang:%s' % goVersion;

buildImage随后被用于生成patch-release-pr.ymlminor-release-pr.ymlrelease.ymlcheck.ymlimages.yml等全部发布工作流中的基础镜像与 Go 版本环境变量。

仓库还提供了release-workflows-check目标(Makefile),它会重新生成工作流并用git diff --exit-code对比差异,用于 CI 中校验生成结果与提交内容一致:

@$(MAKE) release-workflows @echo "Checking diff" @git diff --exit-code --ignore-space-at-eol -- ".github/workflows/*release*" || (echo "Please build release workflows by running 'make release-workflows'" && false)

第三步:运行 make update-go-version 统一更新所有相关文件

这是整个流程的核心一步。make update-go-version目标定义如下(Makefile):

update-go-version: goversion release-workflows @tools/go-version-bump.sh $(GO_VERSION)

它依赖goversion(先打印当前版本)与release-workflows(先重新生成发布工作流),随后执行 tools/go-version-bump.sh 脚本,由脚本自动批量替换仓库中所有引用 Go 版本的位置。

脚本的核心逻辑(tools/go-version-bump.sh)会排除operatorvendor目录,然后依次更新四类文件:

  1. go.mod 中的 Go 指令:查找所有含^gogo.mod,将go x.y.z替换为目标版本(当前根模块为go 1.26.6,见 go.mod):
print_green "Updating version in go.mod '${VERSION}'" find "${EXCLUDE_DIRS[@]}" -type f -name "go.mod" -exec grep -lE "^go " {} \; | while read -r x; do ${SED} -i -re "s,go [0-9\.]+,go ${VERSION},g" "${x}" done
  1. Dockerfile 中的 golang 基础镜像:查找所有FROM golang:Dockerfile*文件,更新镜像标签:
${SED} -i -re "s,golang:[0-9\.]+,golang:${VERSION},g" "${x}"
  1. 工作流中的GO_VERSION:环境变量:更新.github/workflows/*.yml中形如GO_VERSION: "x.y.z"的声明(例如 build-loki-binary.yml 与 govulncheck.yml 中的GO_VERSION: "1.26.6")。

  2. 工作流中的go-version:配置:更新actions/setup-go使用的go-version: "x.y.z"参数(如 lint-jsonnet.yml、logql-bench.yml、logql-correctness.yml、querytee-images.yml、verify-release-workflow.yaml 等)。

macOS 注意事项:脚本使用 GNU sed 语法,BSD 版sed无法兼容。若在 macOS 上执行,请先通过brew install gnu-sed安装,脚本会自动检测并使用gsed(tools/go-version-bump.sh)。

脚本做了什么与没做什么

值得注意:该脚本不修改.github/release-workflows.jsonnet模板本身(模板始终从std.extVar('GO_VERSION')读取版本),也不触碰operator/vendor/目录下的 go.mod 或 Dockerfile——这些目录由 Operator 项目独立维护其 Go 工具链。因此升级后应使用git statusgit diff核对变更范围,确认:

  • 根目录与各子模块的go.mod均已更新;
  • 所有Dockerfile*golang:基础镜像已更新;
  • .github/workflows/下所有GO_VERSIONgo-version已更新;
  • release-workflows重新生成的发布工作流 diff 符合预期。

第四步:提交 Pull Request 与目标分支选择

完成上述修改后,将所有变更提交并打开 Pull Request。目标分支的选择取决于补丁性质:

  • main分支:适用于常规的安全补丁升级,后续会随下一次发布(Weekly / Minor Release)合入;
  • release-MAJOR.MINOR.x分支:适用于需要为已发布的维护版本立即修复漏洞的场景。Loki 的补丁发布工作流 patch-release-pr.yml 恰好针对release-[0-9]+.[0-9]+.x分支运行(见 release-workflows.jsonnet),支持always-bump-patch版本策略,配合升级后的 Go 版本构建并发布补丁版本。

提交 PR 时,可在 PR 描述中注明升级前后版本与对应的 Go 安全公告;PR 通过后,CI 中的govulncheck、重新生成的发布工作流检查(release-workflows-check)会自动验证新工具链的安全性。

常见问题与排查

现象可能原因处理方式
make release-workflows在本地报错缺少 jsonnet / jsonnet-bundler使用默认的容器内执行(保持BUILD_IN_CONTAINER=true
脚本在 macOS 上 sed 报错BSD sed 语法不兼容安装 gnu-sed,脚本会自动使用gsed
发布工作流 diff 与预期不一致未重新生成或 jsonnetfile 依赖过期重新运行make release-workflows,必要时运行make update-loki-release-sha更新 loki-release 依赖 SHA
提交后 CI 报「Please build release workflows」生成结果与提交内容不一致重新运行make release-workflows并提交生成结果

小结

补丁 Go 版本是 Loki 发布维护流程中的高频安全操作,核心在于「一个变量、两级生成、一次脚本」:

  1. 在 Makefile 修改GO_VERSION
  2. make release-workflows基于 Jsonnet 模板重新生成全部发布工作流;
  3. make update-go-version通过 go-version-bump.sh 批量更新 go.mod、Dockerfile 基础镜像与 CI 工作流中的版本声明;
  4. mainrelease-MAJOR.MINOR.x分支提交 PR,交由 CI 校验。

掌握这套流程后,你可以在 Go 安全公告发布后第一时间为 Loki 完成工具链升级,确保发布产物不再受已知漏洞影响。

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

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

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

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

立即咨询