JavaLYG

Kubernetes 1.37 存储版本迁移默认启用:CRD 升级后的检查与回滚清单

Kubernetes 1.37 带来了一个容易被忽略、却和升级安全性直接相关的变化:Storage Version Migration(SVM)已经进入 GA,内置的 StorageVersionMigration API 和 control plane controller 默认启用。它解决的是“资源已经切换到新存储版本,但 etcd 里还有旧对象”的问题。本文不讨论如何盲目升级集群,而是给出一套更稳的 CRD 版本迁移检查方法:确认存储版本、检查转换能力、创建迁移对象、观察状态,最后用 storedVersions 验收。

Kubernetes 1.37 存储版本迁移流程图

一、先分清三个“版本”

CRD 升级时,最容易混淆的是 API 版本、服务版本和存储版本。API 版本决定客户端请求使用什么字段;served: true 表示该版本仍能被 API Server 提供;storage: true 表示新写入对象优先按哪个版本保存。

例如同时提供 v1v2 时,可让两者 served,但只把 v2 设为 storage。旧对象不会因“能读”就自动重写,SVM 负责将其转换并写回。

二、Kubernetes 1.37 的变化

官方发布说明显示,Kubernetes v1.37 于 2026 年 8 月 26 日发布,共有 16 项增强能力晋级 Stable。8 月 31 日官方博客说明,Storage Version Migration 已进入 GA,storagemigration.k8s.io/v1 API 和控制器在 v1.37 集群中默认启用。

这不等于所有对象会自动迁移。迁移仍要围绕具体 Resource 创建 SVM,并检查状态。Kubernetes 提供了稳定基础设施,但迁移目标、转换 webhook、备份和验收仍需运维负责。

三、升级前先保存证据

不要一上来就改 CRD。先记录集群版本、CRD 当前 storage 版本、可提供的 API 版本,以及目标资源能否正常读取。

# 集群版本
kubectl version

# 查看 CRD 的服务与存储版本
kubectl get crd selfierequests.example.com -o yaml

# 只打印当前 storage 版本
kubectl get crd selfierequests.example.com \
  -o jsonpath='{.spec.versions[?(@.storage==true)].name}'
echo

# 确认资源是否能被 API Server 发现
kubectl api-resources | grep -i selfie

# 读取一条真实对象,确认转换 webhook 没有先天故障
kubectl get selfierequests.example.com -A -o yaml

示例名称是占位符,实际操作时替换为自己的资源。生产环境应保存 CRD YAML 和迁移前的资源数量。

四、CRD 版本切换顺序

先部署并验证 conversion webhook,再让新版本 served;确认 v1、v2 可以双向转换后,把 v2 设置为 storage;最后创建 SVM。

重点看两个字段:spec.versions[*].storage 表示首选存储版本,应该只有一个 true;status.storedVersions 表示仍可能存在对象的历史存储版本,迁移完成前可能同时包含 v1 和 v2。

不要只验证新版本创建成功,还要用旧版本对象做读取、更新和列表测试,避免 SVM 重写旧对象时才暴露转换问题。

五、创建 StorageVersionMigration

迁移对象通过资源的 group 和 resource 指定目标。以 example.com 组的 selfierequests 为例:

cat > migrate-crd.yaml <<'EOF'
apiVersion: storagemigration.k8s.io/v1
kind: StorageVersionMigration
metadata:
  name: selfierequests-migration
spec:
  resource:
    group: example.com
    resource: selfierequests
EOF

kubectl apply -f migrate-crd.yaml
kubectl get storageversionmigration.storagemigration.k8s.io \
  selfierequests-migration -o yaml

如果集群只提供 v1beta1,以 Discovery 和对应官方文档为准,不要照抄示例版本。

六、状态怎么看才算完成

迁移对象的 status.conditions 是第一层证据。成功时,Succeeded 条件应为 TrueRunning 通常应为 False。可以这样等待:

kubectl wait \
  --for=condition=Succeeded \
  storageversionmigration.storagemigration.k8s.io/selfierequests-migration \
  --timeout=10m

kubectl get storageversionmigration.storagemigration.k8s.io \
  selfierequests-migration -o yaml

这里的 succeeded 只说明迁移控制器报告成功,不应该直接等同于“所有验收结束”。第二层证据是 CRD 的 status.storedVersions,确认旧版本已经从列表中消失:

kubectl get crd selfierequests.example.com \
  -o jsonpath='{.status.storedVersions}'
echo

第三层证据是抽样读取、更新和列表。使用旧版本客户端读取时,API Server 仍可能按转换后的对象返回;这时要确认字段没有丢失,尤其是 webhook 自定义转换的字段。

Kubernetes 升级后排查清单

七、卡住或失败时按证据排查

现象优先证据常见原因处理方向
找不到 APIkubectl api-resources集群版本、API 注册或资源版本不匹配以 Discovery 结果和控制面配置为准
一直 RunningSVM 的 conditions、事件对象数量多、控制器异常或资源读取失败查看控制器日志,先定位首个失败资源
成功但仍有 v1CRD 的 storedVersions转换 webhook、资源名或迁移范围不正确核对 group/resource 和 webhook 双向转换
读取对象报错API Server 与 webhook 日志schema 不兼容、证书或网络问题修复转换链路后再重试,不要反复创建同名对象
担心直接查 etcd备份、API 读回、审计记录etcd 二进制内容不便人工判断优先使用 API 与 storedVersions 双重验收

排查先看“第一个失败的资源”。转换 webhook 重点检查 Service、Endpoint、证书和 API Server 到 webhook 的连通性。

八、回滚边界

迁移失败时先暂停变更、修复 webhook 或 schema,再根据状态决定是否重试。不要无备份地切回旧 storage 版本,更不要手工编辑 etcd。回滚前必须确认新字段能否转换回旧版本;“把 storage 改回 v1”不是完整回滚。

九、上线验收清单

  • 集群版本和 StorageVersionMigration API 已通过 Discovery 确认。
  • CRD 只有一个 storage 版本,目标版本为预期值。
  • 旧版本和新版本的 conversion webhook 均能读取、创建、更新和列表。
  • SVM 的 Succeeded=True,并保存了完整 status。
  • CRD 的 status.storedVersions 已不再包含待淘汰的旧版本。
  • 抽样对象字段完整,业务读写和控制器日志无新增错误。
  • 备份、回滚边界和变更记录已归档。

🔕 评论已关闭