CRD创建
通过对Kubebuilder的介绍,我们已经了解了Kubebuilder 的功能与原理。从本节开始,我们深入分析 Kubebuilder 各模块的运行原理。首先,我们通过添加几条命令来添加几个自定义 CRD,Group表示 CRD所属的组,它可以支持多种不同版本、不同类型的资源构建;Version表示 CRD的版本号;Kind表示 CRD的类型,具体见代码清单 3-2。
#kubebuildercreateapi--groupdemo--versionv1--kindDemo
#kubebuildercreateapi--groupship--versionv1beta1--kindTest1#kubebuildercreateapi--groupship--versionv1beta1--kindTest2
执行上述命令后,我们先来看一下API层多出来的 CRD 文件结构,按照版本号进行了资源的一级划分,在上述案例中,创建了 1个 v1 版本的 Demo 类型的资源,因此,它自动生成了 {kind}types.go的文件,即 demotypes.go;同时创建了 2个 v1beta1版本的不同类型的资源,可以看到生成了 2个资源文件,分别是 test1_types.go、test2_types.go。我们看到 Kind定义的资源类型在Kubernetes 中一定以大写字母开头,而它的资源文件都自动转化成小写字母,这是Kubernetes的一种约定。并且在每个版本的资源生成的过程中, 都会包含 groupversion_info.go、zz_generated.deepcopy.go 文件,它们的作用是什么呢? 这与 Scheme模块的原理有关,即 Scheme通过这 2个文件实现了 CRD的注册及资源的拷贝,具体见代码清单 3-3。
[root@crd/demo]#treeapi/api/
├──v1
│ ├──demo_types.go
│ ├──groupversion_info.go
│ └──zz_generated.deepcopy.go
└──v1beta1
├──groupversion_info.go
├──test1_types.go
├──test2_types.go
└──zz_generated.deepcopy.go
到这里,细心的读者会思考上述 3个资源的定义文件,除了类型、版本号、所属组不同,即 demo_types.go、test1_types.go、test2_types.go,这几个文件的内容有什么实质性的差异吗?下面我们继续看一下资源文件的具体内容,经过实践我们发现,资源本身的结构 除了名称上的差异,并无任何区别。换句话说,Kubebuilder创建出来的 CRD,结构体是相似的,用户只需要定义自己资源的结构体、做 Controller的协调部分的逻辑。这个简化 过程,对于初次接触 KubernetesCRD 的用户来说非常有益,可以帮助用户快速构建应用。
下面我们挑选其中的test1_types.go内容进行说明(截取部分内容)。Test1表明资源的结构体,包括 metadata、spec、status,以及继承的 Kubernetes资源属性,如 kind、apiVersion等;Test1List 表明资源的列表结构体,即当用户查询这一类资源时,各test1的内容放在了Items键的下面。另外,init() 初始化方法的作用是将资源的类型注册到Scheme对应的 ship组的 v1beta1版本下,在介绍 Kubebuilder框架的时候,我们提及了Scheme的作用,在这里就体现了,具体见代码清单 3-4。
typeTest1struct{
metav1.TypeMeta `json:",inline"`metav1.ObjectMeta`json:"metadata,omitempty"`Spec Test1Spec `json:"spec,omitempty"`StatusTest1Status`json:"status,omitempty"`
}
typeTest1Liststruct{
metav1.TypeMeta`json:",inline"`
metav1.ListMeta`json:"metadata,omitempty"`Items []Test1`json:"items"`
}
funcinit(){
SchemeBuilder.Register(&Test1{},&Test1List{})
}
除了CRD的定义外,我们还需要思考它的 Controller部分,这也可以通过代码清单 3-2的几条命令初始化出来的 Controller 文件来理解。下面,我们先来看一下文件的结构,其中每一个 CRD,默认会创建对应的 {kind}controller.go文件,如 test1_controller.go,这就是 CRDController逻辑构造的位置,具体见代码清单 3-5。
[root@crd/demo]#treecontrollers/controllers/
├──demo_controller.go
├──suite_test.go
├──test1_controller.go
└──test2_controller.go
那么 {kind}controller.go 文件的内容是什么呢?为了阐明它的原理,我们截取部分代码。通过观察我们发现,自动生成的 Reconciler的对象名称是 {kind}Reconciler,它的主方法是 Reconcile(),即通过在这个函数的空白处填入逻辑完成对应的 CRD 构造工作,剩下的是安装、运行工作。另外,我们还发现了 SetupWithManager 方法,这个方法的作用是什么?下一节将会系统介绍。这里,我们只需要清楚,它用于 CRDController的安装。安装完成后,CRDController才能运行,具体内容见代码清单 3-6。
typeDemoReconcilerstruct{client.Client
Loglogr.LoggerScheme*runtime.Scheme
}
func(r*DemoReconciler)Reconcile(reqctrl.Request)(ctrl.Result,error){
_=context.Background()
_=r.Log.WithValues("demo",req.NamespacedName)
//yourlogicherereturnctrl.Result{},nil
}
//SetupWithManagersetsupthecontrollerwiththeManager.
func (r*DemoReconciler)SetupWithManager(mgrctrl.Manager)error{returnctrl.NewControllerManagedBy(mgr).
For(&yangweiweiv1.Demo{}).
Complete(r)
}