Kubernetes 1.37 有个很容易被升级日志盖住的变化:Storage Version Migration(SVM)已经进入 GA,storagemigration.k8s.io/v1 API 和控制器默认启用。它解决的不是“API 能不能访问”,而是 CRD 切换存储版本后,etcd 里遗留的旧对象是否已经被转换并重写。本文用一套可复核的流程,把 CRD 升级从“看起来成功”变成有证据的验收。

一、先分清三个版本
API 版本决定客户端请求路径;served: true 表示 API Server 仍提供该版本;storage: true 表示新写入对象优先以哪个版本保存。比如 CRD 同时提供 v1alpha1、v1 和 v1,只有一个版本应该是 storage。把 storage 改成新版本,只影响新写入,历史对象不会凭空改写。
二、1.37 到底改变了什么
Kubernetes 官方 1.37 发布说明和 8 月 31 日的专题文章确认:SVM 已 GA,内置 API 与控制器在 v1.37 集群默认启用。它提供稳定的迁移机制,但不会替运维决定迁移哪个 Resource,也不会替你验证 conversion webhook、备份和业务字段。
三、升级前留证
kubectl version
kubectl get crd crontabs.example.com -o yaml
kubectl get crd crontabs.example.com -o jsonpath='{.spec.versions[?(@.storage==true)].name}'
echo
kubectl api-resources | grep -i crontab
kubectl get crontabs.example.com -A -o yaml示例中的域名和资源名是占位符。生产环境还应保存 CRD YAML、资源数量和一份可恢复备份。升级前先读一条真实对象,用来区分“迁移失败”和“原本就读不通”。
四、正确的切换顺序
先部署并验证 conversion webhook,再保证旧、新版本都能读取、创建、更新和列表;然后把目标版本设为 storage: true,最后创建 SVM。重点检查 spec.versions 中只有一个 storage=true,以及 status.storedVersions 当前包含哪些历史版本。
五、创建迁移对象
cat > migrate-crd.yaml <<'EOF'
apiVersion: storagemigration.k8s.io/v1
kind: StorageVersionMigration
metadata:
name: crontabs-migration
spec:
resource:
group: example.com
resource: crontabs
EOF
kubectl apply -f migrate-crd.yaml
kubectl get storageversionmigration.storagemigration.k8s.io crontabs-migration -o yamlgroup 和 resource 必须以 API Discovery 的结果为准,不要把 CRD 的复数名称、Kind 和 group 写混。若目标集群不是 1.37,先查该集群实际提供的 API 版本。
六、三层验收,不只看 Succeeded
第一层看迁移对象的 status.conditions,确认 Succeeded=True:
kubectl wait --for=condition=Succeeded storageversionmigration.storagemigration.k8s.io/crontabs-migration --timeout=10m
kubectl get storageversionmigration.storagemigration.k8s.io crontabs-migration -o yaml第二层看 CRD 的存储版本:
kubectl get crd crontabs.example.com -o jsonpath='{.status.storedVersions}'
echo待淘汰的旧版本应从列表中消失。第三层做抽样读写:分别用旧、新 API 读取对象,更新一个无业务影响的字段,再列表并比较关键字段。转换 webhook 自定义字段时,尤其要检查默认值、枚举和嵌套数组是否丢失。
七、卡住时按证据排查

| 现象 | 先查 | 常见方向 |
|---|---|---|
| API 不存在 | kubectl api-resources | 集群版本或 Discovery 不匹配 |
| 一直 Running | conditions、事件、控制器日志 | 资源读取失败或控制器异常 |
| 成功但仍有旧版本 | CRD storedVersions | group/resource 或 webhook 不正确 |
| 对象读取报错 | API Server 与 webhook 日志 | 证书、网络或双向转换问题 |
八、回滚边界
失败时先暂停后续 CRD 清理,修复 webhook 或 schema,再按状态重试。不要无备份地把 storage 改回旧版本,更不要手工编辑 etcd。真正的回滚必须确认新字段可以安全转换回旧版本,并保留变更、备份和抽样读写证据。
九、上线清单
- Discovery、集群版本和 SVM API 已确认。
- CRD 只有一个 storage 版本,目标版本正确。
- Webhook 的读、写、列表和双向转换已验证。
- SVM 为 Succeeded=True,完整 status 已归档。
- storedVersions 不再包含待淘汰版本。
- 抽样对象字段完整,业务控制器无新增错误。
- 备份、回滚边界和变更记录齐全。
🔕 评论已关闭