Kubernetes中提供了多种自定义控制器的方式:
Controller 作为CRD的核心,这里将解释如何使用 code-generator 来创建自定义的控制器,作为文章的案例,将完成一个 Firewalld Port 规则的控制器作为描述,通过 Kubernetes 规则来生成对应节点上的 iptables规则。
apiVersion: apiextensions.k8s.io/v1kind: CustomResourceDefinitionmetadata: name: ports.firewalld.fedoraproject.orgspec: group: firewalld.fedoraproject.org scope: Namespaced names: plural: ports singular: port kind: PortRule shortNames: - fp versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: name: type: string port: type: integer host: type: string isPermanent: type: boolean需要预先下载 code-generator 。因为这个工具不是必需要求的。
注意,下载完成后需要将代码库的的分支更改为你目前使用的版本,版本的选择与client-go类似,如果使用master分支,会与当前的 Kubernetes 集群不兼容。
git clone https://github.com/kubernetes/code-generatorcd code-generator; git checkout {version} # ex. v0.18.0要想使用 code-generator 生成控制器,必须准备三个文件 doc.go , register.go , types.go 。
doc.go 中声明了这个包全局内,要使用生成器的tagregister.go 类似于kubernetes API,是将声明的类型注册到schema中type.go 是需要具体声明对象类型在使用 code-generator 时,就需要对 code-generator 的tag进行了解。code-generator 的tag是根据几个固定格式进行定义的,tag是 +k8s: + conversion 的组合,在仓库中 cmd 中的 *-gen* 文件夹就代表了 conversion 的替换位置。
client-gen的tag 参数可以在 code-generator\cmd\client-gen\generators\util\tags.go注:最终准备完成的文件(
doc.go,register.go,types.go)应该为:apis/example.com/v1这种类型的需要遵循的是,将这些文件放在
<version>目录中,例如v1。这里v1,v1alpha1, 根据自己需求定义。
package v1import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1")// +genclient// +genclient:noStatus// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Objecttype Port struct { metav1.TypeMeta `json:",inline"` // Standard object metadata. // +optional metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` // Specification of the desired behavior of the Deployment. // +optional Spec PortSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`}// +k8s:deepcopy-gen=falsetype PortSpec struct { Name string `json:"name"` Host string `json:"host"` Port int `json:"port"` IsPermanent bool `json:"isPermanent"`}// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Objecttype PortList struct { metav1.TypeMeta `json:",inline"` // +optional metav1.ListMeta `json:"metadata,omitempty"` Items []Port `json:"items"`}// +k8s:deepcopy-gen=package// +k8s:protobuf-gen=package// +k8s:openapi-gen=true// +groupName=firewalld.fedoraproject.orgpackage v1 // import "k8s.io/api/firewalld/v1"这里是从 k8s.io/api 里任意一个复制的,例如 k8s.io/api/core/v1/register.go
package v1import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema")// GroupName is the group name use in this packageconst GroupName = "firewalld.fedoraproject.org"// SchemeGroupVersion is group version used to register these objectsvar SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}// Resource takes an unqualified resource and returns a Group qualified GroupResourcefunc Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource()}var ( // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) localSchemeBuilder = &SchemeBuilder AddToScheme = localSchemeBuilder.AddToScheme)// Adds the list of known types to the given scheme.func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &Port{}, &PortList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil}使用 code-generator 时,实际上就是使用这个库中的脚本 generate-groups.sh ,该脚本又四个参数
k8s.io/api/) 生成的文件存放到哪里,可以和定义的文件为一个目录注:对于参数二,三,与-output-base,指定的路径,这里可以使用相对路径也可以使用go.mod中的定义的包名,对于使用相对路径而言,生成的文件中的import也将会为 "../../" 的格式
一个完整的示例
../code-generator/generate-groups.sh all \ ../code-controller/client \ ../code-controller/apis \ firewalld:v1 \ --output-base ../code-controller/ \ --go-header-file ../code-generator/hack/boilerplate.go.txtReference
CRD Programming