使用 code-generator 爲 CustomResources 生成代碼

kubernetes 項目中有至關一部分代碼是自動生成的,主要是 API 的定義和調用方法,kubernetes 項目下 k8s.io/kubernetes/hack/ 目錄中以 update 開頭的大部分腳本都是用來生成代碼的。code-generator 是官方提供的代碼生成工具,在實現自定義 controller 的時候須要用到 CRD,也須要使用該工具生成對 CRD 操做的代碼。
html

要生成哪些代碼

在自定義 controller 時須要用到 typed clientsets,informers,listers 和 deep-copy 等函數,這些函數均可以使用 code-generator 來生成,具體的做用能夠參考:kubernetes 中 informer 的使用。node

code-generator 裏面包含多個生成代碼的工具,下面是須要用到的幾個:git

  • deepcopy-gen:爲每種類型T生成方法: func (t* T) DeepCopy() *T,CustomResources 必須實現runtime.Object 接口且要有 DeepCopy 方法github

  • client-gen:爲 CustomResource APIGroups 生成 typed clientsetsshell

  • informer-gen:爲 CustomResources 建立 informers,用來 watch 對應 CRD 所觸發的事件,以便對 CustomResources 的變化進行對應的處理json

  • lister-gen:爲 CustomResources 建立 listers,用來對 GET/List 請求提供只讀的緩存層api

除了上面幾個工具外,code-generator 中還提供了 conversion-gen、defaulter-gen、register-gen、set-gen,這些生成器能夠應用在其餘場景,好比構建聚合 API 服務時會用到一些內部的類型,conversion-gen 會爲這些內部和外部類型之間建立轉換函數,defaulter-gen 會處理某些字段的默認值。緩存

代碼生成步驟

使用 code-generator 生成代碼還須要如下幾步:bash

  • 建立指定的目錄格式微信

  • 在代碼中使用 tag 標註要生成哪些代碼

首先要建立指定的目錄格式,目錄的格式能夠參考官方提供的示例項目:sample-controller,下文也會講到,目錄中須要包含對應 CustomResources 的定義以及 group 和 version 信息。

其次要在在代碼中使用 tag 標註要生成哪些代碼,tag 有兩鍾類型,全局的和局部的,全部類型的 deepcopy tag 會默認啓用,更多關於 tag 的使用方法能夠參考:Kubernetes Deep Dive: Code Generation for CustomResources,也能夠參考官方的示例 code-generator/_example 。

開始生成代碼

本文以該 CRD 爲例子進行演示,group 爲ecs.yun.com ,version 爲 v1

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: kubernetesclusters.ecs.yun.com
spec:
  group: ecs.yun.com
  names:
    kind: KubernetesCluster
    listKind: KubernetesClusterList
    plural: kubernetesclusters
    singular: kubernetescluster
    shortNames:
    - ecs
  scope: Namespaced
  subresources:
    status: {}
  version: v1
  versions:
  - name: v1
    served: true
    storage: true

建立指定目錄結構 pkg/apis/{group}/{version},group 能夠定義一個 shortNames,也就是 CRD 中的 shortNames

mkdir -pv pkg/apis/ecs/v1

建立 doc.go:

$ cat << EOF > pkg/apis/ecs/v1/doc.go
// Package v1 contains API Schema definitions for the ecs v1 API group
// +k8s:deepcopy-gen=package,register
// +groupName=ecs.yun.com
package v1
EOF

建立 register.go:

$ cat << EOF > pkg/apis/ecs/v1/register.go
package v1

import (
    "github.com/gosoon/kubernetes-operator/pkg/apis/ecs"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/schema"
)

// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: ecs.GroupName, Version: "v1"}

// Kind takes an unqualified kind and returns back a Group qualified GroupKind
func Kind(kind string) schema.GroupKind {
    return SchemeGroupVersion.WithKind(kind).GroupKind()
}

// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
    return SchemeGroupVersion.WithResource(resource).GroupResource()
}

var (
    SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
    AddToScheme   = SchemeBuilder.AddToScheme
)

// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
    scheme.AddKnownTypes(SchemeGroupVersion,
        &KubernetesCluster{},
        &KubernetesClusterList{},
    )
    metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
    return nil
}
EOF

建立 types.go,該文件中會定義多個 tag:

$ cat << EOF > pkg/apis/ecs/v1/types.go
package v1

import (
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// KubernetesCluster is the Schema for the kubernetesclusters API
type KubernetesCluster struct {
    metav1.TypeMeta   `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty"`

    Spec   KubernetesClusterSpec   `json:"spec,omitempty"`
    Status KubernetesClusterStatus `json:"status,omitempty"`
}

// KubernetesClusterSpec defines the desired state of KubernetesCluster
type KubernetesClusterSpec struct {
    // Add custom validation using kubebuilder tags:
    // https://book.kubebuilder.io/beyond_basics/generating_crd.html
    TimeoutMins   string     `json:"timeout_mins,omitempty"`
    ClusterType   string     `json:"clusterType,omitempty"`
    ContainerCIDR string     `json:"containerCIDR,omitempty"`
    ServiceCIDR   string     `json:"serviceCIDR,omitempty"`
    MasterList    []Node     `json:"masterList" tag:"required"`
    MasterVIP     string     `json:"masterVIP,omitempty"`
    NodeList      []Node     `json:"nodeList" tag:"required"`
    EtcdList      []Node     `json:"etcdList,omitempty"`
    Region        string     `json:"region,omitempty"`
    AuthConfig    AuthConfig `json:"authConfig,omitempty"`
}

// AuthConfig defines the nodes peer authentication
type AuthConfig struct {
    Username      string `json:"username,omitempty"`
    Password      string `json:"password,omitempty"`
    PrivateSSHKey string `json:"privateSSHKey,omitempty"`
}

// KubernetesClusterStatus defines the observed state of KubernetesCluster
type KubernetesClusterStatus struct {
    // Add custom validation using kubebuilder tags: https://book.kubebuilder.io/beyond_basics/generating_crd.html
    Phase KubernetesOperatorPhase `json:"phase,omitempty"`

    // when job failed callback or job timeout used
    Reason string `json:"reason,omitempty"`

    // JobName is store each job name
    JobName string `json:"jobName,omitempty"`

    // Last time the condition transitioned from one status to another.
    LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
}

// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// KubernetesClusterList contains a list of KubernetesCluster
type KubernetesClusterList struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ListMeta `json:"metadata,omitempty"`
    Items           []KubernetesCluster `json:"items"`
}

// users
// "None,Creating,Running,Failed,Scaling"
type KubernetesOperatorPhase string

type Node struct {
    IP string `json:"ip,omitempty"`
}
EOF

執行命令生成代碼:

$ $GOPATH/src/k8s.io/code-generator/generate-groups.sh all github.com/gosoon/test/pkg/client github.com/gosoon/test/pkg/apis ecs:v1

generate-groups.sh 須要四個參數,第一個參數all,也就是要生成全部的模塊,clientset,informers,listers;第二個參數github.com/gosoon/test/pkg/client,這個是你要生成代碼的目錄,目錄的名稱通常定義爲 client;第三個參數github.com/gosoon/test/pkg/apis這個目錄是已經建立好的源目錄;第四個參數ecs:v1 是 group 和 version 信息,ecs 是 apis 下的目錄,v1 是 ecs 下面的目錄。

生成的代碼以下所示:

CRD 以及生成的代碼見:kubernetes-operator

總結

本問講述瞭如何使用 code-generator 生成代碼,要使用自定義 controller,代碼生成是最開始的一步,下文會繼續講述自定義 controller 的詳細步驟,感興趣的能夠關注筆者 github 的項目 kubernetes-operator。

參考:

https://github.com/kubernetes/sample-controller

https://blog.openshift.com/kubernetes-deep-dive-code-generation-customresources/

https://hexo.do1618.com/2018/04/04/Kubernetes-Deep-Dive-Code-Generation-for-CustomResources/

本文分享自微信公衆號 - 田飛雨(kubeConChina)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索