0x01 背景
编程者总有想偷懒的倾向。至少我的初衷时,尽量复用现有的代码。但有时也会变得弄巧成拙。
这不,最近需要在一个Go服务里添加一个CRD的缓存等待。熟悉k8s的同学都知道,向 kube-apiserver 提交一个更新,到同一个进程中的informer 获取到这个更新,有一定的时延。这个时延比较小,一般使用上没什么问题,但提交测试自动化时,就会出现各种妖蛾子,自动化跑的快,很容易就能撞到不一致。
我的思路时,在更新对象时,Update接口会返回一个更新后的对象,咱们又不能直接把对象塞到informer里。那只能轮询informer,看什么时候informer返回的版本号大于或等于新对象的版本号,这时就说明informer已经同步到了更新。
那么既然看到了之前已经有同学初始化好了一个标准的client,很自然写出了这样的代码。
import xxxclientset "xxx/clienset/versioned" // 这是自动生成的CRD的client。func() wrong{client := xxxclientset.New(client.RESTClient) // client 是标记的 client-go中的clientset实例。client.Update(xxx)
}
非常简洁,省去再加载、解析kubeconfig配置。但当我去测试时,傻眼了。
failed to update UICluster object, err: v1.UpdateOptions is not suitable for converting to "meta.k8s.io/v1" in scheme "pkg/runtime/scheme.go:100
看结果是更新成功了,但自己服务的API请求报错了。
0x02 折腾
查阅了社区的几个issue后,认定是我忘记注册了什么东西。多次尝试之后,还是报错,非常痛苦。思来想去不应该,感觉应该注册的东西都已经注册了。
最终反应过来,那个New可能不是能随便用的,至于原因还没深入研究。总之,老老实实地加载kubeconfig配置文件和使用常规的clientset.NewForConfig
之后,不再报错了。
0x03 总结——个人直觉
作为开发人员,直觉很重要,有时可以省掉很多麻烦。想起来多年前使用某一个打车软件时,在午夜时,好像是看到估算的行程时间有点错乱,直觉告诉我,这是个corner case就是边界场景,很容易出问题。同样的,这次遇到的小问题,属于很少有人直接这样的用场景,既然很少有人用,它的顺畅性没经过验证,出问题的可能性就大了。