必须调用.Complete(r)才能启动Informer并触发Reconcile,仅.For()仅声明监听意图;默认监听所有命名空间,特定命名空间需手动过滤或用Owns()+OwnerReference;Watches()注册额外资源监听,避免cache未热加载时查不到。

直接用 controller-runtime,别碰 raw client-go 手动搭 Informer/Workqueue——90% 的人卡在缓存未同步、Scheme 注册遗漏、OwnerReference 写错这三处。
为什么不能只调 For(&corev1.Pod{}) 就完事
调了 For() 只是声明“我想监听 Pod”,但没真正启动 Informer。必须接 .Complete(r),否则 manager 启动后日志里看不到 Starting workers,Reconcile 根本不会被触发。
- 漏掉
.Complete()是本地调试时最常遇到的“没反应”问题 -
For(&corev1.Pod{})默认监听所有 namespace;若只想看特定命名空间,得在Reconcile里手动检查req.Namespace,或改用Owns()+OwnerReference关联 - 如果还要响应 ConfigMap 变更,不能在 Reconcile 里反复
r.Client.Get()查——得提前用Watches()注册额外 Watch,否则 cache 没热加载时返回空
mgr.GetClient().Get() panic 报 no kind "MyResource" 是因为什么
因为你没把自定义类型注册进 Scheme。controller-runtime 启动时会用 Scheme 解析 API 响应体,没注册就无法反序列化。
- 必须在
main()初始化阶段调用scheme.AddKnownTypes()或schemeBuilder.Register() - 还得加载基础 Scheme:
clientgoscheme.AddToScheme(scheme)和apiextensionsv1.AddToScheme(scheme),否则连 CRD 自身都解析不了 - 结构体要嵌入
metav1.TypeMeta和metav1.ObjectMeta,并实现runtime.Object - CRD YAML 推荐用
controller-gen自动生成(靠// +kubebuilder:object:root=true注释驱动),手写极易拼错group/version/kind
Reconcile 函数里怎么安全更新资源
别直接 client.Get → 修改字段 → client.Update,并发下大概率触发 resourceVersion conflict 错误并退出。
立即学习“go语言免费学习笔记(深入)”;
- 优先用
client.Patch(ctx, obj, client.MergeFrom(oldObj)),只提交变更字段,天然绕过 resourceVersion 校验 - 如果必须全量更新,得包一层
retry.RetryOnConflict,否则第一次冲突就返回 error - 更新 Status 字段必须走
r.Client.Status().Update(ctx, instance),直接Update()会被 APIServer 拒绝 - 永远检查
err != nil后立刻return ctrl.Result{}, err;对client.IgnoreNotFound(err)要明确处理,避免无限重试或误删
最易忽略的是本地调试时 cache 同步等待——mgr.GetCache().WaitForCacheSync(ctx) 必须显式调用或依赖 manager 自动等待,否则 Reconcile 一上来查不到对象就 panic。这不是 bug,是设计使然:controller-runtime 默认延迟加载 cache,不等同步完成就操作等于读空数据。


















