K8s中不更新CRD版本直接修改CRD Schema会引发什么问题?
关于同版本CRD Schema修改的问题解答
为什么Kubernetes允许不升级CRD版本就修改Schema?
Kubernetes本身没有强制要求同版本CRD的Schema必须保持不可变,核心原因有两点:
- CRD的版本字段主要用于标识API的演进分支(比如v1alpha1到v1),而非强制约束同版本内的Schema变更。默认情况下,K8s不会阻断同版本CRD的Schema更新请求。
- 早期Kubebuilder生成的CRD默认会设置
preserveUnknownFields: true(Kubernetes 1.16+后默认值为false,但部分脚手架可能仍保留旧配置),这个参数会让K8s忽略对象中不存在于当前Schema的字段,进一步降低了Schema变更的阻碍。
另外,Kubernetes在更新CRD时,不会对已存在的自定义资源(CR)对象进行回溯校验,只会对后续新创建/更新的CR对象应用新的Schema规则,这也是更新能被无警告接受的原因之一。
同版本不同Schema的CR对象共存的影响
假设先创建了基于旧Schema(含A、B字段)的Foo1,再更新CRD的v1版本Schema(移除A字段)并创建Foo2(仅含B字段),会出现以下几种情况:
- 已存在的Foo1对象:
- 如果CRD的
preserveUnknownFields为true:Foo1中的A字段会被K8s保留,查询时会正常返回该字段。如果你的控制器逻辑依赖A字段,处理Foo1时能正常读取,但处理Foo2时会缺失该字段,可能导致逻辑不一致。 - 如果
preserveUnknownFields为false:Foo1中的A字段会被保留(K8s不会主动修改已存在的对象),但当你尝试更新Foo1时,K8s会用新的Schema校验,此时因A字段不在Schema中,会直接报错并阻止更新操作。
- 如果CRD的
- 新创建的Foo2对象:会完全符合新Schema的要求,正常创建和使用,没有异常。
- 控制器与业务逻辑:如果控制器未适配Schema的变更,会出现对Foo1和Foo2的处理逻辑不一致的情况,比如依赖A字段的计算逻辑在Foo2上会出现空值错误,进而引发业务问题。
为什么没出现预期的报错?
Kubernetes默认不开启同版本Schema的不可变校验,如果你希望阻止此类操作,可以在CRD的spec.versions[*].schema.openAPIV3Schema中添加x-kubernetes-immutable: true扩展字段,这样当尝试修改同版本Schema时,K8s会直接拒绝更新请求并报错。
内容的提问来源于stack exchange,提问作者Owe u.
相关产品推荐
相关产品推荐

