結合Kubebuilder與code-generator開發Operator

結合Kubebuilder與code-generator開發Operator

1、概念簡介

1.1 code-generator

k8s.io/client-go for talking to a kubernetes cluster.

k8s.io/client-go 提供了對k8s原生資源的informer和clientset等等,但對於自定義資源的操做則相對低效,須要使用 rest api 和 dynamic client 來操做,並本身實現反序列化等功能。javascript

​ code-generator 提供瞭如下工具用於爲k8s中的資源生成相關代碼,能夠更加方便的操做自定義資源:html

  • deepcopy-gen: 生成深度拷貝對象方法
  • client-gen: 爲資源生成標準的操做方法(get;list;watch;create;update;patch;delete)
  • informer-gen: 生成informer,提供事件機制(AddFunc,UpdateFunc,DeleteFunc)來響應kubernetes的event
  • lister-gen: 爲get和list方法提供只讀緩存層

​ code-generator整合了這些gen,使用腳本generate-groups.shgenerate-internal-groups.sh能夠爲自定義資源生產相關代碼。java

1.2 Kubebuilder

Kubebuilder是用於使用 自定義資源定義(CRD)構建Kubernetes API的框架。

相似於Ruby on RailsSpringBoot之類的Web開發框架,Kubebuilder能夠提升速度並下降開發人員管理的複雜性,以便在Go中快速構建和發佈Kubernetes API。它創建在用於構建核心Kubernetes API的規範技術的基礎之上,以提供減小樣板和麻煩的簡單抽象。git

Resource + Controller = Operator,能夠利用Kubebuilder編寫自定義資源的Operator。github

2、結合背景

Kubebuildercode-generator 均可覺得CRD生成Kubernetes API相關代碼,從代碼生成層面來說, 二者的區別在於:golang

  • Kubebuilder不會生成informers、listers、clientsets,而code-generator會。
  • Kubebuilder會生成Controller、Admission Webhooks,而code-generator不會。
  • Kubebuilder會生成manifests yaml,而code-generator不會。
  • Kubebuilder還帶有一些其餘便利性設施。

​ 使用Kubebuilder能夠快捷生成CRD以及相關的控制器框架,然而因爲Kubebuilder不會生成clientset等包,當別的服務想要操做CRD時將會很麻煩。web

​ 二者結合後可使用Kubebuilder生成CRD和一整套控制器架構,再使用code-generator生成informers、listers、clientsets等。api

3、操做步驟

3.1 依賴組件

3.2 初始化項目

安裝Kubebuilder:參考官方文檔 https://cloudnative.to/kubebu...緩存

一、建立一個項目bash

mkdir -p $GOPATH/src/my.domain/example
cd $GOPATH/src/my.domain/example
kubebuilder init --domain my.domain
tree -CL 2
.
├── bin
│   └── manager
├── config
│   ├── certmanager
│   ├── default
│   ├── manager
│   ├── prometheus
│   ├── rbac
│   └── webhook
├── Dockerfile
├── go.mod
├── go.sum
├── hack
│   └── boilerplate.go.txt
├── main.go
├── Makefile
└── PROJECT

9 directories, 8 files

二、建立一個 API

kubebuilder create api --group example --version v1 --kind Guestbook
Create Resource [y/n]
y
Create Controller [y/n]
n
tree -CL 3
.
├── api
│   └── v1
│       ├── groupversion_info.go
│       ├── guestbook_types.go
│       └── zz_generated.deepcopy.go
......

注意:

若是修改了 api/v1/guestbook_types.go ,須要執行如下命令來更新代碼和manifests:

make && make manifests

3.3 使用code-generator

3.3.1 更新依賴版本

初始化項目後的go.mod:

cat go.mod
module my.domain/example

go 1.13

require (
        k8s.io/apimachinery v0.17.2
        k8s.io/client-go v0.17.2
        sigs.k8s.io/controller-runtime v0.5.0
)

須要將初始化的k8s庫更新到要使用的版本,如:

K8S_VERSION=v0.17.3
go get k8s.io/client-go@$K8S_VERSION
go get k8s.io/apimachinery@$K8S_VERSION

3.3.2 安裝code-generator

k8s的版本號與 go.mod 中的 k8s.io/client-go 的版本保持一致便可。

注意:須要將依賴複製到vendor中

K8S_VERSION=v0.17.3
go get k8s.io/code-generator@$K8S_VERSION
go mod vendor

3.3.3 建立&修改所需文件

須要在api目錄下建立code-generator所需的文件,並添加相關注釋。

  • 新增 api/v1/doc.go

    注意:修改groupName,package與api的version保持一致。

    // +k8s:deepcopy-gen=package
    
    // Package v1 is the v1alpha1 version of the API.
    // +groupName=example.my.domain
    package v1
  • 新增 api/v1/register.go

    注意:package與api的version保持一致。

    package v1
    
    import (
        "k8s.io/apimachinery/pkg/runtime/schema"
    )
    
    // SchemeGroupVersion is group version used to register these objects.
    var SchemeGroupVersion = GroupVersion
    
    // Resource takes an unqualified resource and returns a Group qualified GroupResource
    func Resource(resource string) schema.GroupResource {
        return SchemeGroupVersion.WithResource(resource).GroupResource()
    }
  • 修改 api/v1/{crd}_types.go 文件,添加註釋 // +genclient

    // +genclient
    // +kubebuilder:object:root=true
    
    // Guestbook is the Schema for the guestbooks API
    type Guestbook struct {

3.3.4 準備腳本

在項目 hack 目錄下準備如下文件:

  • 新建 hack/tools.go 文件

    // +build tools
    
    package tools
    
    import _ "k8s.io/code-generator"
  • 新建 hack/update-codegen.sh,注意根據項目修改相應變量:

    • MODULEgo.mod 保持一致
    • API_PKG=api,和 api 目錄保持一致
    • OUTPUT_PKG=generated/example,與生成Resource時指定的group保持一致
    • GROUP=example, 和生成Resource時指定的group 保持一致
    • VERSION=v1, 和生成Resource時指定的version保持一致
    #!/usr/bin/env bash
    
    set -o errexit
    set -o nounset
    set -o pipefail
    
    # corresponding to go mod init <module>
    MODULE=my.domain/example
    # api package
    APIS_PKG=api
    # generated output package
    OUTPUT_PKG=generated/example
    # group-version such as foo:v1alpha1
    GROUP=example
    VERSION=v1
    GROUP_VERSION=${GROUP}:${VERSION}
    
    SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
    CODEGEN_PKG=${CODEGEN_PKG:-$(cd "${SCRIPT_ROOT}"; ls -d -1 ./vendor/k8s.io/code-generator 2>/dev/null || echo ../code-generator)}
    
    # kubebuilder2.3.2版本生成的api目錄結構code-generator沒法直接使用
    rm -rf "${APIS_PKG}/${GROUP}" && mkdir -p "${APIS_PKG}/${GROUP}" && cp -r "${APIS_PKG}/${VERSION}/" "${APIS_PKG}/${GROUP}"
    
    # generate the code with:
    # --output-base    because this script should also be able to run inside the vendor dir of
    #                  k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir
    #                  instead of the $GOPATH directly. For normal projects this can be dropped.
    #client,informer,lister(注意: code-generator 生成的deepcopy不適配 kubebuilder 所生成的api)
    bash "${CODEGEN_PKG}"/generate-groups.sh "client,informer,lister" \
      ${MODULE}/${OUTPUT_PKG} ${MODULE}/${APIS_PKG} \
      ${GROUP_VERSION} \
      --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt
    #  --output-base "${SCRIPT_ROOT}"
    #  --output-base "${SCRIPT_ROOT}/../../.."

    注意:

    1. kubebuilder2.3.2版本生成的api目錄結構code-generator沒法直接使用,須要在sh腳本中進行處理。
    2. 修改腳本執行參數能夠選擇生成的代碼,如:"client,informer,lister"。注意無需再次生成deepcopy:code-generator 生成的deepcopy不適配 kubebuilder 所生成的api。
  • 修改 Makefile ,添加生成命令

    update-codegen:
        chmod +x ./hack/update-codegen.sh
        ./hack/update-codegen.sh

3.3.5 生成代碼

項目根目錄下執行make update-codegen 便可,將生成以下代碼結構:

.
├── api
│   ├── example
│   │   └── v1
│   │       ├── doc.go
│   │       ├── groupversion_info.go
│   │       ├── guestbook_types.go
│   │       ├── register.go
│   │       └── zz_generated.deepcopy.go
│   └── v1
│       ├── doc.go
│       ├── groupversion_info.go
│       ├── guestbook_types.go
│       ├── register.go
│       └── zz_generated.deepcopy.go
├── generated
│   └── example
│       ├── clientset
│       ├── informers
│       └── listers

以後即可以經過clientset等包對自定義資源對象進行操做。

注意事項:

kubebuilder2.3.2版本生成的api目錄結構爲 api/v1,而code-generator須要的api目錄結構爲 api/example/v1,相比較增長了group這一層。

  • hack/update-codegen.sh 腳本會自動根據kubebuilder的api生成code-generator所需目錄結構。
  • code-generator 生成的deepcopy不適配 kubebuilder 所生成的api。
  • code-generator 生成代碼後再次使用make操做時可能因爲生成的代碼影響命令正常執行,例如: make manifests 在生成CRD模版時,需先刪除api以及generated目錄中爲code-generator生成的代碼,纔可正常生成CRD模版。
  • 使用時kubebuilder正常使用 api/v1 中的types,而code-generator生成的clientset等則須要使用 api/example/v1 中的types。

參考

https://github.com/kubernetes...

https://github.com/kubernetes...

https://cloud.tencent.com/dev...

https://blog.csdn.net/sixinch...

相關文章
相關標籤/搜索