首页
/ etcd × Kubernetes 版本升级实战:在 kubernetes/kubernetes 中 Bump etcd 的完整流程

etcd × Kubernetes 版本升级实战:在 kubernetes/kubernetes 中 Bump etcd 的完整流程

2026-09-05 10:55:24作者:申梦珏Efrain

本文基于 etcd 官方贡献者指南 bump_etcd_version_k8s.md,完整讲清在 Kubernetes 仓库中升级 etcd 依赖的全部步骤:先升级 Go 客户端 SDK(vendor 层面),再升级 etcd 镜像(发布与引用两个仓库联动)。读完后,你将掌握 K8s 版本与 etcd 版本线的对应规则、pin-dependency.sh / update-vendor.sh 等关键脚本的用法,以及 7 个需要修改的 K8s 仓库文件的精确位置和示例值,可以直接照单执行一次真实的 etcd 版本升级。

1. 背景:Kubernetes 为什么要定期 Bump etcd

etcd 是 Kubernetes 的默认存储后端,负责保存集群中所有 API 对象的持久化状态。随着 etcd 社区持续修复 bug 和安全漏洞,Kubernetes 需要周期性地把依赖的 etcd 版本"bump"(提升)到新的补丁版本,以获取这些修复。

官方指南明确给出了当前的版本对应策略(引自 bump_etcd_version_k8s.md):

目前,K8s release-1.33 及更低的版本使用 etcd v3.5.x 线,K8s release-1.34 及更高的版本使用 etcd v3.6.x 线。

这个策略与 etcd 仓库自身的发布节奏一致:在本仓库中,CHANGELOG-3.5.mdCHANGELOG-3.6.md 都在持续滚动发布补丁版本(两条维护线几乎同步修复同一批问题,例如 peer lease HTTP handler 的无界 io.ReadAll 修复、watch 权限越界读取等安全修复同时出现在 3.5 与 3.6 两个 CHANGELOG 中)。因此 K8s 社区可以为不同 release 分支锁定各自对应的 etcd 版本线。

整个升级动作可以概括为两个相互独立、先后执行的阶段:

  1. Bump etcd client SDK —— 升级 kubernetes/kubernetes 通过 Go module 依赖的 etcd 客户端库;
  2. Bump etcd image —— 升级 K8s 各测试/部署场景实际运行的 etcd 容器镜像。

指南原文约定:文档示例中"被注释掉的行"表示升级前的旧值,"未注释的行"表示要改成/新增的新值。下文的示例均按此约定保留。

2. 阶段一:Bump etcd client SDK

etcd 客户端以 Go module 形式被 Kubernetes 依赖,升级它本质上是一次标准的 Go 依赖升级 + vendor 重构建。指南中引用的操作脚本全部位于 kubernetes/kubernetes 仓库内(下文所有 hack/...cmd/...cluster/... 等路径均指该仓库,不是 etcd 仓库的路径)。

2.1 找出 Kubernetes 用到的全部 etcd 模块

在 kubernetes/kubernetes 根目录执行:

$ grep 'go.etcd.io/etcd/' go.mod | awk '{print $1}'
go.etcd.io/etcd/api/v3
go.etcd.io/etcd/client/pkg/v3
go.etcd.io/etcd/client/v3
go.etcd.io/etcd/client/v2
go.etcd.io/etcd/pkg/v3
go.etcd.io/etcd/raft/v3
go.etcd.io/etcd/server/v3

etcd 采用多模块(multi-module)仓库结构:每个子目录(api/client/v3/server/ 等)各自是一个独立的 Go module,版本号独立演进。这一点可以从 etcd 仓库本身的 go.work 中直接印证,它通过 use 指令列出了 ./api./client/pkg./client/v3./pkg./server./etcdctl./etcdutl./tests 等所有参与本地开发的模块;各模块的 go.mod 声明也与之对应,例如 client/v3/go.mod 中:

module go.etcd.io/etcd/client/v3

而从当前 etcd 源码结构看,模块组成会随版本演进:本仓库主线(api/version/version.goVersion = "3.8.0-alpha.0")的 server/go.mod 只直接依赖 api/v3client/pkg/v3client/v3pkg/v3 四个模块,并通过 replace 指令把它们指向相对路径(../api../client/pkg 等)以便本地开发;而 Kubernetes 在 3.5/3.6 时代 pin 的模块清单(含 client/v2raft/v3)与主线模块清单存在差异。因此执行 2.1 的 grep 拿到"当前 go.mod 实际引用的模块清单"这一步是必须的,不能照抄历史 PR 的清单。

2.2 逐个 pin 新版本

对 2.1 列出的每个模块,在 kubernetes/kubernetes 仓库根目录执行 pin 脚本(以 client/v3 为例,NEW_VERSION 替换为目标版本,如 v3.5.21):

hack/pin-dependency.sh go.etcd.io/etcd/client/v3 NEW_VERSION

pin-dependency.sh 负责把目标模块在 go.mod 中锁定到指定版本。这一步遵循 Kubernetes 社区 vendor 指南中"Adding or updating a dependency"章节的规范流程。

2.3 重建 vendor 目录

hack/update-vendor.sh

该脚本会重新同步整个 vendor/ 目录,并自动更新 staging 仓库中所有 go.mod 文件以及许可证声明,不需要手工维护。

2.4 校验依赖一致性

新版本可能要求现有已 pin 依赖的更高版本,指南给出两个校验手段:

  • 分别在升级分支和 master 上运行 hack/lint-dependencies.sh,对比两者的输出差异;
  • 检查 staging/ 目录下各组件的 go.mod 是否新增了 replace 指令——新增 replace 往往是依赖约束冲突的信号,需要人工确认。

在 etcd 仓库侧可以对照模块间约束来理解这一步的必要性:server/go.modrequire 块里的 go.etcd.io/etcd/api/v3 v3.8.0-alpha.0 等条目声明了对兄弟模块的最低版本要求,K8s 升级任何一个 etcd 模块时,其余 etcd 模块的版本必须满足这类约束,这正是 2.1 要"整组"升级、而非单独升一个模块的原因。

3. 阶段二:Bump etcd image

3.1 构建镜像:使用官方发布镜像,无需自建

指南明确指出:Kubernetes 现在直接使用 etcd 官方发布的镜像,不再需要为 K8s 额外构建 etcd 镜像。etcd 官方镜像的构建逻辑可以直接在本仓库的 Dockerfile 中查看:基于 distroless static 基础镜像,仅拷贝 etcdetcdctletcdutl 三个二进制,暴露 2379/2380 端口,默认命令为 /usr/local/bin/etcd。官方发布流程(打 tag、发布镜像与 CHANGELOG)详见 release.md,其中还规定了补丁版本的发布门槛(例如修复了高危 CVE、关键 bug 或累计足够数量的 bug 修复)——K8s 社区 bump 的目标版本通常就是满足这些条件后发布的最新补丁版本。

3.2 发布镜像:在 k8s.io 仓库登记 SHA256 digest

镜像进入 K8s 官方 registry 的路径(参考 k8s.io 仓库的镜像 staging PR 流程):

  1. 上一步(SDK bump 或镜像构建 job)合并后,post-commit job 会自动构建镜像,新镜像出现在 staging registry(gcr.io/k8s-staging-etcd/etcd)中;
  2. 找到新构建的镜像,复制其 SHA256 digest
  3. kubernetes/k8s.io 仓库的 registry.k8s.io/images/k8s-staging-etcd/images.yaml 中,为期望的版本新增一条记录,写入该 digest:
"sha256:b4a9e4a7e1cf08844c7c4db6a19cab380fbf0aad702b8c01e578e9543671b9f9": ["3.5.17-0"]
# ADD:
"sha256:d58c035df557080a27387d687092e3fc2b64c6d0e3162dc51453a115f847d121": ["3.5.21-0"]

注意 image tag 的格式是 3.5.21-0-0 是 K8s staging registry 的镜像构建序号,与 etcd 本身的 semver(3.5.21)不同。

3.3 更新 kubernetes/kubernetes 仓库引用新镜像(7 处)

镜像发布后,需要在 kubernetes/kubernetes 仓库中更新所有硬编码的 etcd 版本引用。指南列出的完整清单如下,每处都给出"旧值(注释)→ 新值"的示例:

build/dependencies.yaml —— 修改 etcd 条目的 version,这是 K8s 依赖管理的单一事实来源,refPaths 声明了版本号需要同步的文件与匹配字段:

# etcd
- name: "etcd"
# version: 3.5.17
version: 3.5.21
refPaths:
- path: cluster/gce/manifests/etcd.manifest
match: etcd_docker_tag|etcd_version

cluster/gce/manifests/etcd.manifest —— GCE 测试集群的 etcd manifest,同时更新 image tag 和 TARGET_VERSION

// "image": "{{ pillar.get('etcd_docker_repository', 'registry.k8s.io/etcd') }}:{{ pillar.get('etcd_docker_tag', '3.5.17-0') }}",

"image": "{{ pillar.get('etcd_docker_repository', 'registry.k8s.io/etcd') }}:{{ pillar.get('etcd_docker_tag', '3.5.21-0') }}",

---

{ "name": "TARGET_VERSION",
// "value": "{{ pillar.get('etcd_version', '3.5.17') }}"
"value": "{{ pillar.get('etcd_version', '3.5.21') }}"
},

cluster/gce/upgrade-aliases.sh —— GCE 升级测试脚本中的镜像与版本变量:

# export ETCD_IMAGE=3.5.17-0
export ETCD_IMAGE=3.5.21-0
# export ETCD_VERSION=3.5.17
export ETCD_VERSION=3.5.21

cmd/kubeadm/app/constants/constants.go —— 这是影响最终用户最直接的改动:DefaultEtcdVersion 决定 kubeadm 拉取哪个 etcd 镜像,SupportedEtcdVersion 则声明各 K8s minor 版本支持的 etcd 镜像 tag。注意 map 的 key 是 K8s minor 版本号(30~33 对应 K8s 1.30~1.33),value 是带 -0 的镜像 tag:

// DefaultEtcdVersion = "3.5.17-0"
DefaultEtcdVersion = "3.5.21-0"

---

SupportedEtcdVersion = map[uint8]string{
// 30: "3.5.17-0",
// 31: "3.5.17-0",
// 32: "3.5.17-0",
// 33: "3.5.17-0",
30: "3.5.21-0",
31: "3.5.21-0",
32: "3.5.21-0",
33: "3.5.21-0",
}

hack/lib/etcd.sh —— 本地测试默认使用的 etcd 版本:

# ETCD_VERSION=${ETCD_VERSION:-3.5.17}
ETCD_VERSION=${ETCD_VERSION:-3.5.21}

staging/src/k8s.io/sample-apiserver/artifacts/example/deployment.yaml —— sample-apiserver 示例部署中使用的 etcd 镜像:

- name: etcd
# image: gcr.io/etcd-development/etcd:v3.5.17
image: gcr.io/etcd-development/etcd:v3.5.21

test/utils/image/manifest.go —— 测试框架的镜像清单,更新 etcd 条目:

// configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.5.17-0"}
configs[Etcd] = Config{list.GcEtcdRegistry, "etcd", "3.5.21-0"}

3.4 两个容易踩的坑

  • 版本号与镜像 tag 混用3.5.21(etcd semver,用于 dependencies.yamlETCD_VERSIONTARGET_VERSION)与 3.5.21-0(registry 镜像 tag,用于 manifest、kubeadm 常量、image manifest)是两套值,上表 7 处改动中每处该写哪个值都有固定规则,照抄示例即可。
  • SDK 与镜像版本要分开跟踪:阶段一改的是编译期依赖(Go module 版本,形如 v3.5.21),阶段二改的是运行期容器镜像(tag 形如 3.5.21-0),两者的目标 etcd 版本号应一致,但提交是独立的(指南也分别引用了独立的 SDK bump PR、镜像 staging PR 和镜像更新 PR 作为参考)。

4. 版本兼容性的底层机制(源码视角)

为什么 K8s 可以放心地"只 bump 补丁版本"而不做大规模适配?etcd 源码中有明确的集群版本协商机制可以佐证:

  • api/version/version.go 集中定义版本常量:Version(当前二进制版本)、MinClusterVersion = "3.0.0"(本二进制可兼容的最低集群版本),并以 semver 库构造 V3_5V3_6 等版本对象供各处比较使用;
  • 成员间通信时,raft 传输层会在每个 POST 请求头中携带版本信息,见 server/etcdserver/api/rafthttp/util.goX-Server-VersionX-Min-Cluster-Version;对端响应 412 Precondition Failed 并返回 incompatible version 时即判定版本不兼容(同文件的 checkPostResponse)。同目录下 pipeline_test.go 中的测试断言了请求头必须携带 MinClusterVersion

从源码结构看,只要 K8s 在同一个 minor 版本线内 bump(3.5.x → 3.5.x,3.6.x → 3.6.x),二进制间兼容性由上述协商机制保证,K8s 侧无需修改 API 调用代码——这也是指南把升级限定为"补丁版本滚动"的原因。

5. 执行清单与参考文件速查

一次完整的 etcd bump 按以下顺序执行:

步骤 操作 所在仓库
1 grep 'go.etcd.io/etcd/' go.mod 列出全部 etcd 模块 kubernetes/kubernetes
2 逐模块 hack/pin-dependency.sh <module> NEW_VERSION kubernetes/kubernetes
3 hack/update-vendor.sh 重建 vendor kubernetes/kubernetes
4 对比 hack/lint-dependencies.sh 输出,检查 staging go.modreplace kubernetes/kubernetes
5 确认 post-commit job 构建的新镜像,复制 SHA256 digest k8s-staging registry
6 images.yaml 登记 digest → 新版本映射 kubernetes/k8s.io
7 更新 build/dependencies.yamletcd.manifestupgrade-aliases.sh、kubeadm 常量、hack/lib/etcd.sh、sample-apiserver 部署、test/utils/image/manifest.go 共 7 处引用 kubernetes/kubernetes

etcd 仓库侧可用于对照的参考文件:

遵循上述流程后,Kubernetes 侧的 etcd SDK 与镜像将同步滚动到目标补丁版本,且每一步都有明确的脚本或文件锚点,可复现、可审查。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384