CRD自定义控制器

一、创建自定义CRD

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
  - name: v1beta1  
    served: true 
    storage: true 
    schema:  
      openAPIV3Schema:
        description: Define CronTab YAML Spec
        type: object
        properties:
          spec:
            type: object
            properties:
              cronSpec:
                type: string
              image:
                type: string
              replicas:
                type: integer
  scope: Namespaced
  names:
    kind: CronTab
    plural: crontabs
    singular: crontab    
    shortNames:
    - ct

二、初始化项目并且导入包

1、初始化项目

$ mkdir -p github.com/cnych/controller-demo && cd github.com/cnych/controller-demo
# 初始化项目
$ go mod init github.com/cnych/controller-demo
go: creating new go.mod: module github.com/cnych/controller-demo
# 获取依赖
$ go get k8s.io/apimachinery@v0.17.9
$ go get -d k8s.io/code-generator@v0.17.9
$ go get k8s.io/client-go@v0.17.9

2、在当前项目目录建立好自己的 CRD 结构体,然后使用code-generator 生成客户端代码:

mkdir -p pkg/apis/stable/v1beta1

3、在该文件夹中新建 doc.go 文件,内容如下所示:

// +k8s:deepcopy-gen=package
// +groupName=stable.example.com

package v1beta1

4、新建 type.go 文件

package v1beta1

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

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

// 根据 CRD 定义 CronTab 结构体
type CronTab struct {
 metav1.TypeMeta `json:",inline"`
 // +optional
 metav1.ObjectMeta `json:"metadata,omitempty"`
 Spec              CronTabSpec `json:"spec"`
}

// +k8s:deepcopy-gen=false

type CronTabSpec struct {
 CronSpec string `json:"cronSpec"`
 Image    string `json:"image"`
 Replicas int    `json:"replicas"`
}

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

// CronTab 资源列表
type CronTabList struct {
 metav1.TypeMeta `json:",inline"`

 // 标准的 list metadata
 // +optional
 metav1.ListMeta `json:"metadata,omitempty"`

 Items []CronTab `json:"items"`
}

5、还需要提供 AddToScheme 与 Resource 两个变量供 client 注册,新建 register.go 文件,内容如下所示

package v1beta1

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 = "stable.example.com"
// 注册自己的自定义资源
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"}

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

var (
 // SchemeBuilder initializes a scheme builder
 SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
 // AddToScheme is a global function that registers this API group & version to a scheme
 AddToScheme = SchemeBuilder.AddToScheme
)

// Adds the list of known types to Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
  // 添加 CronTab 与 CronTabList 这两个资源到 scheme
 scheme.AddKnownTypes(SchemeGroupVersion,
  &CronTab{},
  &CronTabList{},
 )
 metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
 return nil
}

6、最终的项目结构如图

$ tree .
.
├── go.mod
├── go.sum
└── pkg
    └── apis
        └── stable
            └── v1beta1
                ├── doc.go
                ├── register.go
                └── types.go

4 directories, 5 files

三、生成代码

1、项目目录下创建目录

mkdir hack && cd hack

2、创建tools.go文件

// +build tools

// 建立 tools.go 来依赖 code-generator
// 因为在没有代码使用 code-generator 时,go module 默认不会为我们依赖此包.
package tools

import _ "k8s.io/code-generator"

3、创建update-codegen.sh 脚本

#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

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)}

bash "${CODEGEN_PKG}"/generate-groups.sh "deepcopy,client,informer,lister" 
  github.com/cnych/controller-demo/pkg/client github.com/cnych/controller-demo/pkg/apis 
  stable:v1beta1 
  --output-base "${SCRIPT_ROOT}"/../../.. 
  --go-header-file "${SCRIPT_ROOT}"/hack/boilerplate.go.txt

# To use your own boilerplate text append:
#   --go-header-file "${SCRIPT_ROOT}"/hack/custom-boilerplate.go.txt

4、创建verify-codegen.sh 脚本

#!/usr/bin/env bash

set -o errexit
set -o nounset
set -o pipefail

SCRIPT_ROOT=$(dirname "${BASH_SOURCE[0]}")/..

DIFFROOT="${SCRIPT_ROOT}/pkg"
TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg"
_tmp="${SCRIPT_ROOT}/_tmp"

cleanup() {
  rm -rf "${_tmp}"
}
trap "cleanup" EXIT SIGINT

cleanup

mkdir -p "${TMP_DIFFROOT}"
cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"

"${SCRIPT_ROOT}/hack/update-codegen.sh"
echo "diffing ${DIFFROOT} against freshly generated codegen"
ret=0
diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
if [[ $ret -eq 0 ]]
then
  echo "${DIFFROOT} up to date."
else
  echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
  exit 1
fi

5、为生成的代码文件添加头部内容的 boilerplate.go.txt 文件,内容如下所示

/*
Copyright The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

6、接下来就是生成代码了,首先将依赖包放置到 vendor 目录中去

go mod vendor

7、然后执行脚本生成代码

$ chmod +x ./hack/update-codegen.sh
$ ./hack/update-codegen.sh
Generating deepcopy funcs
Generating clientset for stable:v1beta1 at github.com/cnych/controller-demo/pkg/client/clientset
Generating listers for stable:v1beta1 at github.com/cnych/controller-demo/pkg/client/listers
Generating informers for stable:v1beta1 at github.com/cnych/controller-demo/pkg/client/informers

8、代码生成后,整个项目的 pkg 包变成了下面的样子:

$ tree pkg
pkg
├── apis
│   └── stable
│       └── v1beta1
│           ├── 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
    │               └── v1beta1
    │                   ├── crontab.go
    │                   ├── doc.go
    │                   ├── fake
    │                   │   ├── doc.go
    │                   │   ├── fake_crontab.go
    │                   │   └── fake_stable_client.go
    │                   ├── generated_expansion.go
    │                   └── stable_client.go
    ├── informers
    │   └── externalversions
    │       ├── factory.go
    │       ├── generic.go
    │       ├── internalinterfaces
    │       │   └── factory_interfaces.go
    │       └── stable
    │           ├── interface.go
    │           └── v1beta1
    │               ├── crontab.go
    │               └── interface.go
    └── listers
        └── stable
            └── v1beta1
                ├── crontab.go
                └── expansion_generated.go

20 directories, 26 files

 

原文地址:https://www.cnblogs.com/wuchangblog/p/14267844.html