Overview
Kubernetes中提供了多種自定義控制器的方式:
Controller 作為CRD的核心,這裡將解釋如何使用 code-generator
來建立自定義的控制器,作為文章的案例,將完成一個 Firewalld Port 規則的控制器作為描述,通過 Kubernetes 規則來生成對應節點上的 iptables規則。
Prerequisites
CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: ports.firewalld.fedoraproject.org
spec:
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
需要預先下載 code-generator
。因為這個工具不是必需要求的。
注意,下載完成後需要將程式碼庫的的分支更改為你目前使用的版本,版本的選擇與client-go類似,如果使用master分支,會與當前的 Kubernetes 叢集不相容。
git clone https://github.com/kubernetes/code-generator
cd 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 Tag說明
在使用 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 - 對於其他型別的使用方法,例如 deepcopy-gen ,可以在包 main.go中看註釋說明
- +k8s:openapi-gen=true:啟用一個生成器
注:最終準備完成的檔案(
doc.go
,register.go
,types.go
)應該為:apis/example.com/v1
這種型別的需要遵循的是,將這些檔案放在
<version>
目錄中,例如v1
。這裡v1
,v1alpha1
, 根據自己需求定義。
開始填寫檔案內容
type.go
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type 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=false
type 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.Object
type PortList struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
Items []Port `json:"items"`
}
doc.go
// +k8s:deepcopy-gen=package
// +k8s:protobuf-gen=package
// +k8s:openapi-gen=true
// +groupName=firewalld.fedoraproject.org
package v1 // import "k8s.io/api/firewalld/v1"
register.go
這裡是從 k8s.io/api 裡任意一個複製的,例如 k8s.io/api/core/v1/register.go
package v1
import (
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 package
const GroupName = "firewalld.fedoraproject.org"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func 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 ,該指令碼又四個引數
- 第一個引數:使用那些生成器,就是 *.gen,用逗號分割,all表示使用全部
- 第二個引數:client(client-go中informer, lister等)生成的檔案存放到哪裡
- 第三個引數:api(api結構,
k8s.io/api/
) 生成的檔案存放到哪裡,可以和定義的檔案為一個目錄 - 第四個引數:定義group:version
- -output-base:輸出包存放的根目錄
- -go-header-file:生成檔案的頭註釋資訊,這個是必要引數,除非生成失敗
注:對於引數二,三,與-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.txt
Reference