1.创建CRD
2.自动生成代码
3.编写controller代码
1.创建CRD
目标如下:
创建自定义API对象(Custom Resource Definition),名为Student;
用代码生成工具生成informer和client相关代码;
创建并运行自定义控制器,k8s环境中所有Student相关的"增、删、改"操作都会被此控制器监听到,可以根据实际需求在控制器中编写业务代码;
创建CRD的第一步是通过官方文档做初步了解,地址:https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#create-a-customresourcedefinition
登录可以执行kubectl命令的机器,创建student.yaml文件,内容如下:
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:# name must match the spec fields below, and be in the form: .name: students.stable.example.com
spec:# group name to use for REST API: /apis//group: stable.example.com# list of versions supported by this CustomResourceDefinitionversions:- name: v1# Each version can be enabled/disabled by Served flag.served: true# One and only one version must be marked as the storage version.storage: trueschema:openAPIV3Schema:type: objectproperties:spec:type: objectproperties:name:type: stringschool:type: stringreplicas:type: integer# either Namespaced or Clusterscope: Namespacednames:# plural name to be used in the URL: /apis///plural: students# singular name to be used as an alias on the CLI and for displaysingular: students# kind is normally the CamelCased singular type. Your resource manifests use this.kind: Students# shortNames allow shorter string to match your resource on the CLIshortNames:- stu
在student.yaml所在目录执行命令kubectl apply -f student.yaml,即可在k8s环境创建Student的定义,今后如果发起对类型为Student的对象的处理,k8s的api server就能识别到该对象类型了
访问k8s的etcd上存储的数据,那么执行以下命令,就可以看到新的CRD已经保存在etcd中
ETCDCTL_API=3 etcdctl --endpoints="192.168.204.129:2379,192.168.204.130:2379,192.168.204.131:2379" --cacert=/etc/kubernetes/pki/etcd/etcd-ca.pem --cert=/etc/kubernetes/pki/etcd/etcd.pem --key=/etc/kubernetes/pki/etcd/etcd-key.pem get /registry/apiextensions.k8s.io/customresourcedefinitions/ --prefix
创建Student对象
前面的步骤使得k8s能识别Student类型了,接下来创建个Student对象
apiVersion: "stable.example.com/v1"
kind: Student
metadata:name: object-student
spec:name: "李四"school: "北京中学"
在object-student.yaml文件所在目录执行命令kubectl apply -f object-student.yaml
执行命令kubectl get stu可见已创建成功的Student对象
创建成功的Stutend对象存储在etcd中是什么样的呢,如果您的etcdctl已经配置好,执行以下命令
ETCDCTL_API=3 etcdctl --endpoints="192.168.204.129:2379,192.168.204.130:2379,192.168.204.131:2379" --cacert=/etc/kubernetes/pki/etcd/etcd-ca.pem --cert=/etc/kubernetes/pki/etcd/etcd.pem --key=/etc/kubernetes/pki/etcd/etcd-key.pem get /registry/stable.example.com/students/default/object-student --print-value-only
至此,自定义API对象(也就是CRD)就创建成功了,此刻我们只是让k8s能识别到Student这个对象的身份,但是当我们创建Student对象的时候,还没有触发任何业务(相对于创建Pod对象的时候,会触发kubelet在node节点创建docker容器)
2.自动生成代码
为什么要做controller
但如果仅仅是在etcd保存Student对象是没有什么意义的,试想通过deployment创建pod时,如果只在etcd创建pod对象,而不去node节点创建容器,那这个pod对象只是一条数据而已,没有什么实质性作用,其他对象如service、pv也是如此;
controller的作用就是监听指定对象的新增、删除、修改等变化,针对这些变化做出相应的响应(例如新增pod的响应为创建docker容器),关于controller的详细设计,最好的参考就是Harry (Lei) Zhang老师在twitter上的分享,地址是:https://twitter.com/resouer/status/1009996649832185856
API对象的变化会通过Informer存入队列(WorkQueue),在Controller中消费队列的数据做出响应,响应相关的具体代码就是我们要做的真正业务逻辑;
自动生成代码是什么
接下来要做的事情就是编写API对象Student相关的声明的定义代码,然后用代码生成工具结合这些代码,自动生成Client、Informet、WorkQueue相关的代码;
在$GOPATH/src/目录下创建一个文件夹k8s_customize_controller:
进入文件夹k8s_customize_controller,执行如下命令创建三层目录:
mkdir -p pkg/apis/stable
在新建的stable目录下创建文件register.go,内容如下:
package stableconst (GroupName = "stable.example.com"Version = "v1"
)
在新建的stable目录下创建名为v1的文件夹;
在新建的v1文件夹下创建文件doc.go,内容如下:
// +k8s:deepcopy-gen=package// +groupName=stable.example.com
package v1
上述代码中的两行注释,都是代码生成工具会用到的,一个是声明为整个v1包下的类型定义生成DeepCopy方法,另一个声明了这个包对应的API的组名,和CRD中的组名一致;
在v1文件夹下创建文件types.go,里面定义了Student对象的具体内容:
package v1import (metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Objecttype Student struct {metav1.TypeMeta `json:",inline"`metav1.ObjectMeta `json:"metadata,omitempty"`Spec StudentSpec `json:"spec"`
}type StudentSpec struct {name string `json:"name"`school string `json:"school"`
}// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object// StudentList is a list of Student resources
type StudentList struct {metav1.TypeMeta `json:",inline"`metav1.ListMeta `json:"metadata"`Items []Student `json:"items"`
}
从上述源码可见,Student对象的内容已经被设定好,主要有name和school这两个字段,表示学生的名字和所在学校,因此创建Student对象的时候内容就要和这里匹配了;
在v1目录下创建register.go文件,此文件的作用是通过addKnownTypes方法使得client可以知道Student类型的API对象:
package v1import (metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/apimachinery/pkg/runtime""k8s.io/apimachinery/pkg/runtime/schema""k8s_customize_controller/pkg/apis/stable"
)var SchemeGroupVersion = schema.GroupVersion{Group: stable.GroupName,Version: stable.Version,
}var (SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)AddToScheme = SchemeBuilder.AddToScheme
)func Resource(resource string) schema.GroupResource {return SchemeGroupVersion.WithResource(resource).GroupResource()
}func Kind(kind string) schema.GroupKind {return SchemeGroupVersion.WithKind(kind).GroupKind()
}func addKnownTypes(scheme *runtime.Scheme) error {scheme.AddKnownTypes(SchemeGroupVersion,&Student{},&StudentList{},)// register the type in the schememetav1.AddToGroupVersion(scheme, SchemeGroupVersion)return nil
}
至此,为自动生成代码做的准备工作已经完成了,目前为止,$GOPATH/src/k8s_customize_controller目录下的文件和目录结构是这样的:
.└── pkg└── apis└── bolingcavalry├── register.go└── v1├── doc.go├── register.go└── types.go
4 directories, 4 files
执行下面的命令,要在$GOPATH/src下执行:
go get -u k8s.io/apimachinery@v0.24.2
go get -u k8s.io/code-generator@v0.24.2
./k8s.io/code-generator/generate-groups.sh all k8s_customize_controller/pkg/client k8s_customize_controller/pkg/apis stable:v1
会看到以下输出:
Generating deepcopy funcs
Generating clientset for stable:v1 at k8s_customize_controller/pkg/client/clientset
Generating listers for stable:v1 at k8s_customize_controller/pkg/client/listers
Generating informers for stable:v1 at k8s_customize_controller/pkg/client/informers
在$GOPATH/src/k8s_customize_controller目录下执行tree命令,可见已生成了很多内容:
.
├── go.mod
├── go.sum
└── pkg├── apis│ └── stable│ ├── register.go│ └── v1│ ├── doc.go│ ├── register.go│ ├── types.go│ └── zz_generated.deepcopy.go└── client├── clientset│ └── versioned│ ├── clientset.go│ ├── doc.go│ ├── fake│ │ ├── clientset_generated.go│ │ ├── doc.go│ │ └── register.go│ ├── scheme│ │ ├── doc.go│ │ └── register.go│ └── typed│ └── stable│ └── v1│ ├── doc.go│ ├── fake│ │ ├── doc.go│ │ ├── fake_stable_client.go│ │ └── fake_student.go│ ├── generated_expansion.go│ ├── stable_client.go│ └── student.go├── informers│ └── externalversions│ ├── factory.go│ ├── generic.go│ ├── internalinterfaces│ │ └── factory_interfaces.go│ └── stable│ ├── interface.go│ └── v1│ ├── interface.go│ └── student.go└── listers└── stable└── v1├── expansion_generated.go└── student.go21 directories, 29 files
如上所示,zz_generated.deepcopy.go就是DeepCopy代码文件,client目录下的内容都是客户端相关代码,在开发controller时会用到;
client目录下的clientset、informers、listers的身份和作用可以和前面的自动生成代码-controller的详细设计结合来理解;
3.编写controller代码
我们创建了CRD,再通过自动生成代码的工具将controller所需的informer、client等依赖全部准备好,到了本章,就该编写controller的代码了,也就是说,现在已经能监听到Student对象的增删改等事件,接下来就是根据这些事件来做不同的事情,满足个性化的业务需求;
上一篇:抢跑数字中国建设,青岛市统计系统考察团赴实在智能调研统计数字员工
下一篇:【RuoYi-Vue-Plus】学习笔记 49 - Easy Excel(三)自定义转换器 ExcelDictConvert 源码分析