crd在go中需过三关:yaml定义合法(spec.versions数组、openapi v3类型名严格)、scheme正确注册(addtoscheme调用顺序及路径准确)、controller能watch(status更新用client.status().update)。

CRD 在 Go 里不是“写个结构体就能用”,而是必须过三关:YAML 定义合法、Go 类型能被 Scheme 正确识别、Controller 能真正 watch 到对象——漏一关,kubectl apply 就报错或 Reconcile 根本不触发。
CRD YAML 怎么写才不被 kubectl apply 拒绝
K8s 1.16+ 已彻底废弃 spec.version,只认 spec.versions 数组,且必须满足硬性约束,否则直接报 ValidationError。
-
spec.versions至少含一个元素,每个元素必须有name(如v1)、served: true、storage: true(仅一个版本可设为true) - OpenAPI v3 类型名必须严格:用
integer不是int,boolean不是bool,string不能写成str -
properties下不能直接写type: object;必须显式声明properties: {}或additionalProperties: false - 常见错误:
error: error validating "crd.yaml": unknown field "version" in ...—— 这说明你还在用老文档里的单版本写法
Go 结构体怎么写才不会让 controller-runtime 找不到类型
Controller 启动后查不到你的 CR,90% 是因为 Scheme 没注册对,而不是 CRD 没装上。controller-runtime 默认完全不认识你的 MyApp。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 必须在
mgr := ctrl.NewManager(...)之前调用appsv1.AddToScheme(scheme),顺序错会 panic:no kind "MyApp" is registered -
AddToScheme的调用目标必须是生成的 client-go 包路径(如example.com/api/v1),不是SchemeBuilder.AddToScheme - 如果 CRD 支持多版本(
v1alpha1+v1),每个版本的 Go 类型都得单独AddToScheme,否则watch旧版本对象时静默失败 - 字段必须带完整 tag:
json:"replicas,omitempty" yaml:"replicas,omitempty";指针类型 +omitempty是安全底线,否则 API Server 拒绝解析
Reconcile 函数里怎么读 Status 和更新它才不冲突
直接 client.Get 后改 .Status 再 client.Update,必触发 object has been modified 错误——这不是并发问题,是 K8s 乐观锁强制校验 ResourceVersion。
- Status 更新必须走专用路径:
client.Status().Update(ctx, obj),这是唯一免版本检查的 status 提交方式 - 如果 Status 计算依赖 Spec,先
client.Get全量对象,再用obj.DeepCopy()构造新实例,避免污染本地缓存引用 - 别在 Reconcile 开头就
Get;加个if obj.DeletionTimestamp != nil提前 return,省掉无谓请求和潜在冲突 - OwnerReference 安全校验要用
metav1.IsControlledBy(obj, owner),别手写owner.UID == obj.OwnerReferences[0].UID
Webhook 和 Validation 怎么配才不卡住资源创建
Validation webhook 配错,会导致所有 kubectl apply 卡死在等待响应,甚至让整个命名空间无法创建任何该 CR 实例。
-
ValidatingWebhookConfiguration的caBundle必须与 webhook server 实际 TLS 证书一致;用cat server.crt | base64 -w 0注入,别漏-w 0 - CRD 的
validation规则必须显式注释到 Go 字段上,比如// +kubebuilder:validation:Required,双斜杠+空格缺一不可 - 数组长度限制用
MinItems=1,不是MinLength=1(网上大量教程写反);字符串长度才用MinLength - 运行
make manifests后,立刻检查生成的 YAML 中openAPIV3Schema.properties.spec.properties.xxx.type是否存在,缺失 = schema 生成失败 = kubectl 拒绝 CRD
最常被忽略的其实是 Scheme 注册顺序和 caBundle 的 base64 编码细节——前者导致启动即崩,后者导致资源永远卡在 Pending。这两处没验证过,其他都白搭。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










