k8s自定义controller
创始人
2024-05-30 22:03:07
0

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对象的增删改等事件,接下来就是根据这些事件来做不同的事情,满足个性化的业务需求;

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
【PdgCntEditor】解... 一、问题背景 大部分的图书对应的PDF,目录中的页码并非PDF中直接索引的页码...
修复 爱普生 EPSON L4... L4151 L4153 L4156 L4158 L4163 L4165 L4166 L4168 L4...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...