必须确认CRD已Established,否则90%会报no matches for kind;用kubectl get crd -o wide检查STATUS列是否为Established,未达成时需排查storage设置、apiVersion一致性及Conditions状态。

测试CRD资源前,必须确认CRD已Established
没看到 Established 状态就跑测试,90% 的 case 会卡在 no matches for kind "MyApp"。这不是测试代码的问题,而是 API Server 还没完成 CRD 的注册流程。
用这条命令盯住状态:
kubectl get crd myapps.example.com -o wide
直到 STATUS 列显示 Established(不是 Accepted 或空),再继续。中间可能有几秒到几十秒延迟,尤其在启用了 webhook 的集群里。
- 如果一直卡在
Accepted,检查 CRD YAML 中spec.versions[*].storage是否为true(且仅一个版本设为true) - 如果报
Invalid value: "v1": must match the first version in spec.versions,说明apiVersion字段写错了,比如用了example.com/v1alpha1却在 CR 实例里写example.com/v1 - 用
kubectl describe crd myapps.example.com查Conditions,重点关注Established条件的status和reason
本地单元测试别碰真实集群,用envtest启动fake API Server
直接在测试里调 rest.InClusterConfig() 或硬塞 kubeconfig 路径,会导致测试环境不可控、CI 失败、权限泄露。正确做法是用 controller-runtime/pkg/envtest 启一个轻量 fake API Server。
立即学习“go语言免费学习笔记(深入)”;
它不依赖真实集群,所有 CRUD 操作走内存模拟,还能自动加载你定义的 CRD —— 关键是得显式告诉它哪些 CRD 要装进去:
testEnv := &envtest.Environment{
CRDs: []string{
filepath.Join("..", "config", "crd", "bases", "example.com_myapps.yaml"),
},
}
- 路径必须指向你生成的、已验证能
kubectl apply成功的 CRD YAML;手写或过期的 YAML 会导致no kind "MyApp" is registered - 如果你用 kubebuilder,这个路径通常是
config/crd/bases/;手动管理的话,确保文件里spec.group和你 Go 结构体注册的 group 一致 - envtest 默认只加载内置资源(
core/v1,apps/v1等),CRD 必须显式传入CRDs:字段,否则scheme认不出你的类型
Reconcile 测试要隔离 client 行为,别让 test 依赖真实 Kubernetes
测试控制器逻辑时,真正要验证的是:给定某个 CR 状态,Reconcile 是否按预期创建 Deployment、更新 Status、返回正确 error。不该也不需要它真去连 API Server。
用 fake.NewClientBuilder().WithScheme(scheme).WithObjects(...) 构造 client,把初始资源(如待处理的 MyApp 实例、已存在的 Deployment)提前塞进去:
cl := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(&myapp, &dep).
Build()
-
WithObjects()传的是 *runtime.Object,不是 unstructured;确保你的MyApp类型已通过AddToScheme(scheme)注册,否则构建 client 会 panic - 不要在 test 里调
mgr.GetClient()—— 那是运行时才有的;测试中 client 就是输入参数,由你完全控制 - 若 Reconcile 内部调了
r.Client.Status().Update(),记得在WithObjects()里也塞一个带Status字段的实例,否则 Update 会因 ResourceVersion 为空失败
集成测试跑在真实集群?先检查 RBAC 和命名空间隔离
真集群上跑 e2e 测试不是不行,但容易因权限或 namespace 污染失败。最常踩的坑是:测试用的 ServiceAccount 没被授予对 CRD 的权限,或者误删了其他团队的资源。
- RBAC 的
rules[].resources必须写成["myapps"](复数、小写),不是"MyApp"或"myapp";status 子资源要单独列:resources: ["myapps", "myapps/status"] - 测试 namespace 必须显式创建并 cleanup,别用
default—— 它太容易被共享污染;用test-ns-+ 随机后缀,测试结束立即kubectl delete ns - 避免用
clientset.CoreV1().Namespaces().Create()在 test 里建 namespace:某些托管集群(如 EKS、AKS)限制 namespace 创建权限;改用kubectl create nsshell 命令(仅限 CI 环境且明确可控时)或跳过,直接指定预置 namespace
真实集群测试的价值在于验证 webhook、finalizer、OwnerReference 这类无法被 envtest 完全模拟的机制,但代价高、速度慢、稳定性差 —— 不要把它当成日常开发测试的主力。


















