为 Grafana Loki 发布准备升级指南:Main/Unreleased 工作流完整实战
本文面向 Grafana Loki 的核心维护者与发布协调者,讲解如何在每次 stable、patch 或 security 版本发布前,维护并发布官方升级指南(Upgrade Guide)的完整流程:从 setup/upgrade/_index.md 这一升级信息唯一载体的定位,到 release-VERSION_PREFIX 分支上 Main/Unreleased 区块的更新、提升(promote)与清理三个关键步骤,并辅以版本号语义、配置/指标变更的自动化检查手段,让读者能够独立完成一次发布周期的升级指南准备与维护工作。
升级指南在 Loki 发布流程中的定位
在 Grafana Loki 的稳定版本发布流程(见 docs/sources/community/maintaining/release/_index.md)中,一次 stable release 依次经过「创建发布分支 → 回移植提交(backport)→ 记录指标与配置变更 → 准备升级指南 → 更新版本号」,而 patch 版本发布同样包含「准备升级指南」这一环节,位于「合并 Release PR」之前。
升级指南记录的是从上一版本升级到特定 Loki 版本时,需要用户注意或采取行动的所有变更——包括破坏性变更、配置项删除/重命名、默认值调整以及指标改名等。它的受众是真实世界的 Loki 使用者:他们在升级前会通读这份文档来决定是否需要修改自己的配置或迁移数据。因此,准备升级指南不是简单的写作任务,而是发布工程的一部分,必须保证其内容与将要发布的二进制完全一致。
Loki 用一份单一文件承载所有版本的升级信息:setup/upgrade/_index.md(即 docs/sources/setup/upgrade/_index.md)。该文件同时承担两层职责:
- 面向普通用户:提供升级风险提示、配置变更检查方法,并按版本(
Main / Unreleased、3.6.0、3.5.0……)组织各版本的破坏性变更条目; - 面向维护者:作为升级指南工作流的工作对象,其中的
Main / Unreleased区块是当前未发布变更的暂存区。
开始前的准备:理解版本号与 VERSION_PREFIX
升级指南的工作全部围绕版本号展开。Loki 采用 Semantic Versioning(语义化版本),见 docs/sources/community/maintaining/release/concepts/version.md。发布流程需要设置两个环境变量:
VERSION:完整的语义化版本A.B.C。例如2.9.0是 v2.9.0 stable release 的VERSION,2.9.1是 v2.9.0 之后的第一个 patch release 的VERSION;VERSION_PREFIX:仅取主版本号和次版本号组成的A.B.x。例如2.9.x。
VERSION_PREFIX 决定了发布分支的命名:每个 major/minor 版本只创建一个名为 release-VERSION_PREFIX(如 release-2.9.x)的分支,该分支后续承载该 minor 版本的所有 stable 与 patch 发布(详见 create-release-branch.md)。升级指南的三个步骤全部在该分支上执行,因此在开始前应确认当前发布的 VERSION 与 VERSION_PREFIX 取值正确。
核心三步工作流
prepare-upgrade-guide 流程(即 prepare-upgrade-guide.md)包含三个步骤,分别在 release-VERSION_PREFIX 分支和 main 分支上操作。
第 1 步:确保 release 分支上 Main/Unreleased 区块是最新的
首先,在 release-VERSION_PREFIX 分支上,检查 docs/sources/setup/upgrade/_index.md 文件中的 Main / Unreleased 部分,确认它已经包含了本版本发布的所有需要用户关注的变更。
Main / Unreleased 是升级指南中的滚动暂存区:从上一个版本发布以来,所有合入 main 分支的、需要用户注意的变更(破坏性变更、配置删除、默认值变化、指标改名)都先记录在这里。以当前仓库中的 Main / Unreleased 区块 为例,它记录了诸如:
frontend.encoding默认值从json改为protobuf(仅影响内部组件间编码,客户端 API 不变,滚动升级安全,可通过显式设置frontend.encoding: json保持旧行为);- LogQL 拒绝针对
__error__、__error_details__的数字/时长/字节/ip()比较(这两类标签恒为字符串或未设置,改用| __error__ != ""之类的字符串比较); variants()查询与enable_multi_variant_queries设置的移除;row_shardsschema 设置的移除(TSDB 索引动态解析分片因子,遗留row_shards:键会导致配置加载失败);- 各类已废弃配置项的集中移除清单等。
如果发现有遗漏的变更尚未记录,应在该区块中补齐条目,同时保持与 document-metrics-configurations-changes 步骤(见下文)产出的清单一致。
第 2 步:在 release 分支上把 Main/Unreleased 提升为 VERSION
确认 Main/Unreleased 内容完整后,仍然在 release-VERSION_PREFIX 分支上,执行「promote」操作:把 Main / Unreleased 区块重命名/提升为正式的版本区块 VERSION (YYYY-MM-DD),使其成为该版本的固定升级记录。
这一步通常通过一个针对升级指南文件的 PR 完成,其效果是:之前属于"待发布"的变更,现在正式归属于本次发布的版本标题之下,与将要发布的 tag 一一对应。这也意味着从此刻起,任何新的变更如果被回移植(backport)到该 release 分支,都应重新记录到新的 Main / Unreleased 区块(如果后续还有 patch 发布)或直接归入已发布的版本区块。
第 3 步:在 main 分支上清理已发布的条目
最后,切换到 main 分支,把 Main / Unreleased 中已经包含在本次 VERSION (YYYY-MM-DD) 区块里的条目删除。因为这些变更已经随本次发布固化到 release 分支的版本区块中,main 上的 Main / Unreleased 应当清空,为下一版本的变更记录腾出空间。
这一"release 分支提升 → main 分支清理"的双分支协作模式,保证了同一份变更不会被重复记录:release 分支持有已发布版本的完整历史,main 分支只保留尚未发布的增量。值得注意的是,patch 发布在旧 release 分支上进行时(例如最新分支是 release-2.9.x 却在 release-2.8.x 上发布补丁),相应的升级指南条目应记录在对应的旧 release 分支上,而不是 main 分支的 Main / Unreleased 中。
数据从哪来:配置与指标变更的自动化检查
升级指南的素材不是凭空撰写的。在准备升级指南之前,维护者需要先执行「记录指标与配置变更」环节(见 document-metrics-configurations-changes.md),该环节同样在 release-VERSION_PREFIX 分支上完成,其产出直接喂给第 1 步的 Main/Unreleased 区块:
- 检查哪些配置项发生了变更(包括默认值变化):
$ OLD_VERSION=X.Y.Z ./tools/diff-config.sh - 将被重命名或默认值发生变化的配置记录到升级指南(即 prepare-upgrade-guide.md 中描述的工作流);
- 检查指标是否变化:
$ OLD_VERSION=X.Y.Z ./tools/diff-metrics.sh - 将名称被修改的指标记录到升级指南。
这两个脚本位于仓库 tools/diff-config.sh 与 tools/diff-metrics.sh。它们以 OLD_VERSION=X.Y.Z 环境变量指定对比基线,脚本会基于新旧版本之间的差异生成变更清单,维护者据此决定哪些条目需要写进 Main/Unreleased。这也解释了为什么升级指南中的条目大多以「配置名 + 新默认值/去向 + 影响面 + 应对动作」的结构出现——它们直接来源于这些 diff 工具的检出结果,例如「-store.index-cache-write 被移除(仅用于已删除的 legacy 存储后端)」「loki_log_flushes 更名为 loki_internal_log_flushes」。
面向用户的升级指南形态:发布后用户如何消费这份文档
升级指南被发布后,就变成了用户升级时的第一手依据。理解它的用户侧形态,有助于维护者判断应该记录什么、记录到什么粒度。以 docs/sources/setup/upgrade/_index.md 为例,其用户侧内容包含三个层次:
升级前的通用检查:配置差异对比命令
文件开篇建议用户尽量保持版本跟进、顺序升级,若需跨版本升级应先在小环境验证。同时给出一个非常实用的 Docker 命令,用于对比两个 Loki 版本的完整内部配置结构:
export OLD_LOKI=2.9.4
export NEW_LOKI=3.0.0
export CONFIG_FILE=local-config.yaml
diff --color=always --side-by-side \
<(docker run --rm -t -v "${PWD}":/config grafana/loki:${OLD_LOKI} \
-config.file=/etc/loki/${CONFIG_FILE} -print-config-stderr 2>&1 | sed '/Starting Loki/q' | tr -d '\r') \
<(docker run --rm -t -v "${PWD}":/config grafana/loki:${NEW_LOKI} \
-config.file=/etc/loki/${CONFIG_FILE} -print-config-stderr 2>&1 | sed '/Starting Loki/q' | tr -d '\r') | less -R
其原理是:Loki 二进制支持 -print-config-stderr 标志,会在启动时把完整的内部配置结构体 dump 到 stderr(该标志的定义见 pkg/loki/config_wrapper.go,同文件还定义了 -verify-config 用于只校验配置不启动服务)。用 sed '/Starting Loki/q' 截取启动行之前的所有输出,再交给 diff 对比新旧版本即可快速定位默认值变化。文档同时提示:输出会非常冗长(展示整个内部配置结构),且 tr -d '\r' 通常非必需(原作者遇到 WSL2 混入 Windows 换行符的情况)。
按版本组织的变更记录
Main / Unreleased 以及各历史版本(3.6.0、3.5.0、3.4.0……)区块,是维护者发布流程的产物,也是用户按版本查阅的目录。每个条目都遵循"变更是什么 → 影响谁 → 如何应对"的模板,例如 Helm chart 6.46.0 的默认 service account 改名(loki → <release-name>-loki,建议显式设置 serviceAccount.name 以保持幂等)、3.5.8 移除 BusyBox shell(改用 kubectl debug 临时容器或 docker cp 调试)、3.0.0 的 TSDB/schema v13 强制要求等。
升级前的配置预检
升级指南还给出了一个低成本的预检手段,在升级前用目标版本镜像直接校验现有配置:
docker run --rm -t -v "${PWD}":/config grafana/loki:3.0.0 \
-config.file=/config/loki-config.yaml -verify-config=true
-verify-config(同样定义于 pkg/loki/config_wrapper.go)让 Loki 只解析并校验配置文件后退出,是"我的配置能否在目标版本启动"的快速答案;配合 deprecated-config-checker 工具(tools/deprecated-config-checker)可以进一步标记出已被移除的废弃配置键。
与其他发布环节的衔接
prepare-upgrade-guide 不是孤立步骤,它与周边流程存在明确依赖:
- 输入:依赖
document-metrics-configurations-changes的 diff 产出(配置/指标变更清单),依赖backport-commits将需要记录的变更合入 release 分支; - 输出:产出的版本区块最终随 Release PR(标题形如
chore(<BRANCH>): release <VERSION>)合并而发布,用户将在升级指南中看到该版本的所有变更(见 merge-release-pr.md); - 版本号联动:步骤 2 中提升出的
VERSION (YYYY-MM-DD)必须与update-version-numbers环节通过LOKI_NEW_VERSION=$VERSION ./tools/release_update_tags.sh(tools/release_update_tags.sh)更新的文档、示例、jsonnet 中的版本引用保持一致。
小结
准备升级指南是 Loki 发布工程中"对用户最诚实"的一环:它把散落在代码变更、配置删除、指标改名中的破坏性信息,收敛成一份按版本组织的、可检索的官方记录。对维护者而言,掌握 Main/Unreleased 的「release 分支更新 → 提升为 VERSION → main 分支清理」三步节奏,配合 diff-config.sh/diff-metrics.sh 的自动化检出,就能让每次发布的升级指南既完整又及时,从而把升级风险明确地传递给用户。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.2 K634
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown300
jforgamejforgame是一个一站式游戏服务器开发框架。包含游戏服务器开发所需要的各种组件,比如网关,socket服务端与客户端,自定义高效消息编解码,游戏热更新,游戏通用工具等等。包含游戏服,跨服,匹配服,后台管理系统等实现,同时提供大量业务案例以供学习。亦可用于其他socket应用,例如及时聊天等。Java101
fizz-gateway-nodeAn Aggregation API Gateway in Java . FizzGate 是一个基于 Java开发的微服务聚合网关,是拥有自主知识产权的应用网关国产化替代方案,能够实现热服务编排聚合、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理、回调管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。Java60
certd开源SSL证书管理工具;全自动证书申请、更新、续期;通配符证书,泛域名证书申请;证书自动化部署到阿里云、腾讯云、主机、群晖、宝塔;https证书,pfx证书,der证书,TLS证书,nginx证书自动续签自动部署JavaScript60
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python280