crd需与operator的reconcile逻辑协同工作;单独apply仅注册类型,无控制器监听则无效;其yaml须匹配go类型定义,由controller-gen生成;status更新必须用status().update(),不可用普通update()。

CRD 不是“写完就生效”的静态定义,它必须和 Operator 的 Reconcile 逻辑协同工作;单独 apply 一个 CRD YAML,Kubernetes 只会认识这个资源类型,但不会做任何事——没控制器监听它,它就是个空壳。
CRD YAML 必须匹配 Go 类型的字段定义
controller-gen 会从 api/v1/myapp_types.go 中的 struct 和注释(如 //+kubebuilder:validation)自动生成 CRD YAML。如果你手动改了 YAML 文件(比如在 config/crd/bases/ 下),下次运行 make manifests 就会被覆盖。常见错误包括:
- Go 结构体字段漏加
json:tag,导致 client-go 解析失败,Reconcile 时spec字段为空 - CRD 中
openAPIV3Schema定义了required: ["replicas"],但 Go struct 里Replicas int32没设默认值且未标记omitempty,会导致创建 CR 时校验失败并报spec.replicas in body must be of type integer -
status子资源未开启(subresources: { status: {} }缺失),r.Status().Update(ctx, &myapp)会返回the server does not allow this method on the requested resource
CR 实例创建后,Operator 才真正开始工作
CRD 注册成功只是第一步。Operator 启动后,会通过 client.Client 监听该 CR 的增删改事件,触发 Reconcile()。关键点:
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 确保 RBAC 规则中包含对 CR 的
get/list/watch权限,否则控制器收不到事件,日志里只有静默无响应 - CR 的
namespace必须和控制器 watch 范围一致:如果 CRDscope: Namespaced,而控制器只 watchdefault命名空间,那在my-ns下创建的 CR 就不会被处理 - Reconcile 函数内不能直接调用
kubectl或 shell 命令;所有操作必须走注入的client.Client,它已自动集成缓存、序列化和权限上下文
status 更新必须显式调用 Status().Update()
很多人误以为更新 myapp.Status.Phase = "Running" 后,调用 r.Update(ctx, &myapp) 就行了——这是错的。CR 的 status 是独立子资源,必须用专用方法:
myapp.Status.Phase = "Running"
myapp.Status.AvailableReplicas = 3
if err := r.Status().Update(ctx, &myapp); err != nil {
return ctrl.Result{}, err
}
否则会出现 Invalid: spec: Forbidden: updates to spec are forbidden 错误,因为普通 Update() 尝试修改不可变字段 spec。
最容易被忽略的是:CRD 的 additionalPrinterColumns 和 subresources.status 必须同时存在,才能让 kubectl get myapps 显示 PHASE 列且支持 kubectl patch myapp xxx -p '{"status":{"phase":"Failed"}}' 这类直接操作——这两处不配对,调试时你会反复怀疑是不是 status 没写进去。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










