CRD YAML 中关键字段不可错:apiVersion 必须为 apiextensions.k8s.io/v1;spec.group、spec.names.kind、spec.names.plural、spec.scope 必须严格匹配且大小写敏感;OpenAPI v3 schema 中 spec/status 需显式声明 type: object,字段类型须准确(如 integer/string/boolean),数组须含 items;结构体需 +kubebuilder:validation 注解才能生成 schema;storage 版本有且仅有一个,须 served: true 且 storage: true。

CRD YAML 文件里哪些字段不能错
CRD 的 apiVersion 必须是 apiextensions.k8s.io/v1(K8s v1.16+ 强制要求),v1beta1 已废弃且在 v1.22+ 完全不可用。常见错误是复制旧文档里的 v1beta1,导致 kubectl apply 报错 no matches for kind "CustomResourceDefinition"。
关键字段必须成对匹配:
-
spec.group(如cache.example.com)要和 Go 类型注册时的GroupVersion.Group一致 -
spec.names.kind(如RedisCluster)需首字母大写,且必须与 Go struct 名、register.go中的Kind字段完全一致 -
spec.names.plural(如redisclusters)决定kubectl get命令路径,拼写错误会导致资源无法列出 -
spec.scope只能是Namespaced或Cluster,大小写敏感;写成namespaced会静默降级为 Cluster 级但不报错,极易引发权限和隔离问题
OpenAPI v3 schema 怎么写才不被 API Server 拒绝
CRD 的 schema 不是可选装饰,而是强制校验入口。漏掉 type: object 或嵌套 properties 缺失顶层 spec 定义,会导致 kubectl apply 成功但后续 kubectl create -f cr.yaml 直接返回 Invalid value: 。
实际写法要点:
-
spec和status必须显式声明为type: object,即使为空也要写properties: {} - 所有字段类型必须明确:整数用
type: integer(不是int或number),字符串用type: string,布尔用type: boolean - 可选字段加
"x-kubernetes-preserve-unknown-fields": true是危险操作——它绕过校验,但会让 controller-runtime 的 Go 结构体反序列化失败,出现json: unknown field "xxx" - 数组字段必须带
items,例如type: array; items: { type: string },光写type: array会触发校验失败
为什么 kubebuilder generate 后 CRD YAML 里没生成 schema
这是最常被忽略的标记问题:api/v1/xxx_types.go 中的结构体字段**必须有 +kubebuilder:validation 注解才能进 schema**。没有注解的字段,controller-gen 默认跳过,生成的 CRD YAML 中对应字段直接消失。
正确示例:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
type MyAppSpec struct {
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=100
Replicas int `json:"replicas"`
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
Image string `json:"image"`
}
漏掉注解的后果:
-
Replicas字段在 CRD YAML 的openAPIV3Schema中彻底缺失 → 创建 CR 时该字段不被校验,但 Go struct 反序列化会设为零值(如 int=0) -
Image缺少Pattern→ 用户填nginx:latest能过,填NGINX:LATEST也能过,失去约束意义 - 整个
MyAppSpec结构体若没加// +kubebuilder:object:root=true,controller-gen甚至不会把它当 CR 类型处理
storage 版本和 served 版本怎么配才不出问题
一个 CRD 可以定义多个版本(如 v1alpha1, v1),但有且仅有一个版本能同时满足 served: true 和 storage: true。违反这点,kubectl get crd 会显示 ESTABLISHED=False,且所有 CR 操作失败。
典型配置组合:
- 新项目起步:只留一个
v1,设served: true和storage: true,其他版本删掉 - 升级场景:新增
v1(served: true,storage: false),原v1alpha1改为served: true,storage: false,再部署 conversion webhook - 绝对禁止:
v1alpha1和v1都设storage: true—— API Server 会拒绝创建 CRD,报错only one version can be marked as the storage version - 注意:
served: false的版本仍可读(如果已有对象存于该版本),但无法通过kubectl apply创建新对象
多版本演进是高阶需求,初期硬扛一个稳定版更省事。真正容易翻车的,是以为“多开几个版本更灵活”,结果卡在 storage 冲突上动不了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










