hello 各位小伙伴们, 今天想和大家分享的是利用client-go 生成 CustomResourceDefinition
为什么要做这样一个手记呢 , 原因是 原生的client-go 的clientSet 根本不支持 创建CustomResourceDefinition, 并且我找遍了 百度和google 都没有找到合适的答案, 最后在查看多篇 github repo 后,篡出了答案,所以放在这里分享给大家, 我想用到的人应该不多, 但一旦需要 这肯定是个万能药, 如果您已经搞定了这个问题, 好吧 您可以关闭这篇手记,如果正巧 你还在为此而头疼, 那么 来看看怎么做吧
首先 我们先随便上一个 template 的demo
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: queues.scheduling.volcano.sh
spec:
group: scheduling.volcano.sh
names:
kind: Queue
plural: queues
接下来我说我遇到的坑:
1: 大家看到了 kind 是 CustomResourceDefinition, 而 apiVersion apiextensions.k8s.io/v1beta1
当我们拿到yaml的str后,正常情况下怎么解析呢?
obj, _, err := scheme.Codecs.UniversalDeserializer().Decode([]byte(yaml), nil, nil) // 来自
"k8s.io/client-go/kubernetes/scheme"
接下来 我们只需要吧 obj 转成我们需要的结构体,比如说 obj.(*appsV1.DaemonSet), 拿到这样的结构体,我们就可以去 get create update delete了. 但是! scheme无法解析kind为CustomResourceDefinition的资源!所以我们遇到的第一个问题是无法把我们想要的yaml转成我们需要的结构体!
2: 标准的client-go 根本没有对应的CustomResourceDefinition的结构体!
3: 标准的client-go 根本不支持创建 CustomResourceDefinition 的资源!
以上三点让我非常郁闷,但毕竟还是有办法去解决的. 通过找零散的资料, 首先我找到了 CustomResourceDefinition的结构体的sdk-----"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" 我们通过安装他 可以拿到v1beta1.CustomResourceDefinition 这个结构体, 好, 那么问题 2解决了, 不过 即便有了结构体, 我们依然无法通过scheme 将yaml转成标准的 object.runtime , 不过这个倒也简单, 我们只需要呀 yaml转成json, 再将json返序列放入v1beta1.CustomResourceDefinition. 有的同学会说, 我直接把yaml放到结构体里不好了吗? 但事实证明,不行, 所以 参考代码如下:
obj := v1beta1.CustomResourceDefinition{}
jsonByte, err := yaml1.YAMLToJSON([]byte(yaml)) // yaml1 "github.com/ghodss/yaml"
if err != nil {
return err
}
err = json.Unmarshal(jsonByte, &obj)
if err != nil {
return nil
}
好了 1的问题也解决了, 我们可以将yaml 字符串直接转成我们的资源结构体对象了. (当然了 代码是死的,人是活的,我们并不一定都要用scheme 来定义对象,因为业务中有时候是用户传参数,我们来自动生成对应的结构体, 所以第一步到不是非常重要,关键是 2 和 3) 那么最后一步 我们的client-go的clientset 不支持创建 CustomResourceDefinition 这种资源, 这就是说,我们必须创建另外一个支持CustomResourceDefinition的clientSet, 这个clientset 找了好久后终于找到了-----clientsetCustom "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" 通过这个sdk 我们可以拥有一个支持CustomResourceDefinition的clientset了. 但是! 问题又来了, 这个clientset(后边我们叫他 cc吧) 他需要的kubeconfig 不是 client-go 标准中的 api.config, 而是一个叫做 rest.Config 而且进去查看这个结构体,和 api.config完全不同, 但我们自己的kubeconfig 都是标准的结构, 于是我又陷入了沉思, 因为 怎么都找不到对应 可以创建rest.config的结构体. 百度 google都找遍了,我依然找不到, 再我要放弃的时候, 看到来自google的一个英文帖子, 说 可以吧api.config 转换城 rest.config, 但找了很多网页,都没有找到, 于是我继续找,哪里呢? github, 我通过关键字,一点一点的寻找, 终于找到了答案, 振奋人心啊! 我们直接贴代码:
kubeconfig, err := clientcmd.NewClientConfigFromBytes([]byte(kubeCfgStr)) //"k8s.io/client-go/tools/clientcmd"
if err != nil {
return nil, err
}
_config, err := kubeconfig.ClientConfig() // 这一步最关键, 他将 api.config 转成了 rest.config
if err != nil {
return nil, err
}
cc := clientsetCustom.NewForConfigOrDie(_config)
就这样,我们终于可以通过 cc 来 操作 CustomResourceDefinition 这个资源了! 看似一切就结束了!不 并不是的. 其实我在创建这个资源的原因是 安装volcano 这个插件, 但是 这个插件创建 batchjob的插件sdk 和 我们刚才说的几个 sdk冲突, 他会强制把 client-go 等几个sdk升级到高版本,造成冲突, 所以解决办法是强制在go.mod中降低下来版本, 或许未来可以解决这个问题吧.
好了,以上就是我遇到的坑,我大概花费了1天的时间研究这个,终于搞定了,所以记录在这里,为自己,也为别人吧.
··································
欢迎关注课程:
《Django入门到进阶-更适合Python小白的系统课程》