侧边栏壁纸
博主头像
问道

问道的小花园,总能给你带来惊喜

  • 累计撰写 68 篇文章
  • 累计创建 35 个标签
  • 累计收到 6 条评论

kubernetes二次开发系列(5):从零开发 Kubernetes Operator

问道
2023-02-05 / 0 评论 / 5 点赞 / 2,602 阅读 / 28,051 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-02-05,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

主流operator开发框架的包括operator framework sdk和kubebuilder,前者是redhat开源并维护的一套工具,支持使用go、ansible、helm进行operator开发(其中只有go可以开发到能力级别5的operator,其他两种则不行);而kubebuilder则是kubernetes官方的一个sig(特别兴趣小组)维护的operator开发工具。目前基于operator framework sdk和go进行operator开发时,operator sdk底层使用的也是kubebuilder,所以这里我们就直接使用kubebuilder来开发operator。

Windows下编译安装kubebuilder

kuberbuilder没有直接的Windows版本,所以需要下载源码,编译后使用

可能会clone不下来,直接下下来打开。

原始的go.mod用的是1.19,改成1.8试试

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/kubebuilder-master
$ make build
fatal: not a git repository (or any of the parent directories): .git
fatal: not a git repository (or any of the parent directories): .git
go build -ldflags " -X main.kubeBuilderVersion= -X main.goos=windows -X main.goarch=amd64 -X main.gitCommit= -X main.buildDate=2022-12-04T02:24:32Z " -o bin/kubebuilder ./cmd


build成功了,文件放在bin下了

要把编译后的二进制文件放到Git目录下:C:\Program Files\Git\usr\bin

拷贝过去后进行验证,出现下面这样表示成功

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/kubebuilder-master
$ kubebuilder -v
time="2022-12-04T10:30:29+08:00" level=error msg="could not get plugins root: Host not supported: windows"
time="2022-12-04T10:30:29+08:00" level=error msg="Host not supported: windows"
CLI tool for building Kubernetes extensions and tools.                        

Usage:
  kubebuilder [flags]
  kubebuilder [command]

Examples:
The first step is to initialize your project:
    kubebuilder init [--plugins=<PLUGIN KEYS> [--project-version=<PROJECT VERSION>]]

<PLUGIN KEYS> is a comma-separated list of plugin keys from the following table
and <PROJECT VERSION> a supported project version for these plugins.

                              Plugin keys | Supported project versions
------------------------------------------+----------------------------
                base.go.kubebuilder.io/v3 |                          3
          base.go.kubebuilder.io/v4-alpha |                          3
         declarative.go.kubebuilder.io/v1 |                       2, 3
  deploy-image.go.kubebuilder.io/v1-alpha |                          3
                     go.kubebuilder.io/v2 |                       2, 3
                     go.kubebuilder.io/v3 |                          3
               go.kubebuilder.io/v4-alpha |                          3
          grafana.kubebuilder.io/v1-alpha |                          3
       kustomize.common.kubebuilder.io/v1 |                          3
 kustomize.common.kubebuilder.io/v2-alpha |                          3

For more specific help for the init command of a certain plugins and project version
configuration please run:
    kubebuilder init --help --plugins=<PLUGIN KEYS> [--project-version=<PROJECT VERSION>]

Default plugin keys: "go.kubebuilder.io/v3"
Default project version: "3"


Available Commands:
  completion  Load completions for the specified shell
  create      Scaffold a Kubernetes API or webhook
  edit        Update the project configuration
  help        Help about any command
  init        Initialize a new project
  version     Print the kubebuilder version

Flags:
  -h, --help                     help for kubebuilder
      --plugins strings          plugin keys to be used for this subcommand execution
      --project-version string   project version (default "3")

Additional help topics:
  kubebuilder alpha      Alpha-stage subcommands

Use "kubebuilder [command] --help" for more information about a command.

通过kubebuilder创建一个operator项目

使用kuberbuilder初始化新项目,该命令将下载 controller-runtime 二进制文件,并为我们准备好项目。

zengz@DESKTOP-Q3MJC4 MINGW64 /f/go/project/0-shizhanxiangmu/myk8sOperator
$ kubebuilder init myk8soperator --domain="wendao" --project-name="myk8soperator" --repo="gitee.com/wendao365/myk8soperator" --skip-go-version-check
time="2022-12-04T10:59:52+08:00" level=error msg="could not get plugins root: Host not supported: windows"
time="2022-12-04T10:59:52+08:00" level=error msg="Host not supported: windows"
time="2022-12-04T10:59:52+08:00" level=warning msg="the platform of this environment (windows/amd64) is not suppported by kustomize v3 (v3.8.7) which is used in this scaffold. You will
 be unable to download a binary for the kustomize version supported and used by this plugin. The currently supported platforms are: [\"linux/amd64\" \"linux/arm64\" \"darwin/amd64\"]" 
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
Get controller runtime:
$ go get sigs.k8s.io/controller-runtime@v0.13.1
go: downloading sigs.k8s.io/controller-runtime v0.13.1
go: downloading k8s.io/apimachinery v0.25.0
go: downloading k8s.io/client-go v0.25.0
go: downloading k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed
go: downloading github.com/prometheus/client_golang v1.12.2
go: downloading k8s.io/klog/v2 v2.70.1
go: downloading k8s.io/component-base v0.25.0
go: downloading sigs.k8s.io/structured-merge-diff/v4 v4.2.3
go: downloading golang.org/x/time v0.0.0-20220609170525-579cf78fd858
go: downloading github.com/evanphx/json-patch/v5 v5.6.0
go: downloading k8s.io/api v0.25.0
go: downloading gomodules.xyz/jsonpatch/v2 v2.2.0
go: downloading k8s.io/apiextensions-apiserver v0.25.0
go: downloading sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2
go: downloading github.com/google/gnostic v0.5.7-v3refs
go: downloading k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1
go: downloading golang.org/x/net v0.0.0-20220722155237-a158d28d115b
go: downloading github.com/prometheus/procfs v0.7.3
go: downloading github.com/fsnotify/fsnotify v1.5.4
Update dependencies:
$ go mod tidy
go: go.mod file indicates go 1.19, but maximum version supported by tidy is 1.18
Error: failed to initialize project: unable to run post-scaffold tasks of "base.go.kubebuilder.io/v3": exit status 1
Usage:
  kubebuilder init [flags]

Examples:
  # Initialize a new project with your domain and name in copyright
  kubebuilder init --plugins go/v3 --domain example.org --owner "Your name"

  # Initialize a new project defining a specific project version
  kubebuilder init --plugins go/v3 --project-version 3


Flags:
      --component-config         create a versioned ComponentConfig file, may be 'true' or 'false'
      --domain string            domain for groups (default "my.domain")
      --fetch-deps               ensure dependencies are downloaded (default true)
  -h, --help                     help for init
      --license string           license to use to boilerplate, may be one of 'apache2', 'none' (default "apache2")
      --owner string             owner to add to the copyright
      --project-name string      name of this project
      --project-version string   project version (default "3")
      --repo string              name to use for go module (e.g., github.com/user/repo), defaults to the go package of the current working directory.
      --skip-go-version-check    if specified, skip checking the Go version

Global Flags:
      --plugins strings   plugin keys to be used for this subcommand execution

2022/12/04 11:00:17 failed to initialize project: unable to run post-scaffold tasks of "base.go.kubebuilder.io/v3": exit status 1

Operator 最重要的组成部分:

  • main.go 是项目入口,负责设置并运行管理器。
  • config/包含在 Kubernetes 中部署 Operator 的 manifest。
  • Dockerfile 是用于构建管理器镜像的容器文件。

make kustomize

kustomize 是一个通过 kustomization 文件定制 kubernetes 对象的工具,它可以通过一些资源生成一些新的资源,也可以定制不同的资源的集合。

一个比较典型的场景是我们有一个应用,在不同的环境例如生产环境和测试环境,它的 yaml 配置绝大部分都是相同的,只有个别的字段不同,这时候就可以利用 kustomize 来解决,kustomize 也比较适合用于 gitops 工作流。

简单理解,kustomize识别kustomization.yaml文件,并按照kustomization.yaml中的指示做事,并且kustomization.yaml中可以继续套用kustomization.yaml。

把kustomize工具拉下来,生成yaml文件

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/myk8sOperator (master)
$ make kustomize
mkdir -p /f/go/project/0-shizhanxiangmu/myk8sOperator/bin
test -s /f/go/project/0-shizhanxiangmu/myk8sOperator/bin/kustomize || { curl -Ss "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash -
s -- 3.8.7 /f/go/project/0-shizhanxiangmu/myk8sOperator/bin; }
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

kustomize失败,没有建立安全连接

要手动把这个文件弄下来,根据Makefile中的指令来执行

{ curl -Ss "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash - s -- 3.8.7 /f/go/project/0-shizhanxiangmu/myk8sOperator/bin; }

kubebuilder create api

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/myk8sOperator (master)
$ kubebuilder create api --group traefik --version v1 --kind Service
time="2022-12-04T11:21:49+08:00" level=error msg="could not get plugins root: Host not supported: windows"
time="2022-12-04T11:21:49+08:00" level=error msg="Host not supported: windows"
Create Resource [y/n]
y
Create Controller [y/n]
y
Writing kustomize manifests for you to edit...
Writing scaffold for you to edit...
api\v1\service_types.go
controllers\service_controller.go
Update dependencies:
$ go mod tidy
Running make:
$ make generate
Error: failed to create API: unable to run post-scaffold tasks of "base.go.kubebuilder.io/v3": exec: "make": executable file not found in %PATH%
Usage:
  kubebuilder create api [flags]

Examples:
  # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate
  kubebuilder create api --group ship --version v1beta1 --kind Frigate

  # Edit the API Scheme
  nano api/v1beta1/frigate_types.go

  # Edit the Controller
  nano controllers/frigate/frigate_controller.go

  # Edit the Controller Test
  nano controllers/frigate/frigate_controller_test.go

  # Generate the manifests
  make manifests

  # Install CRDs into the Kubernetes cluster using kubectl apply
  make install

  # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config
  make run

Flags:
      --controller           if set, generate the controller without prompting the user (default true)
      --force                attempt to create resource even if it already exists
      --group string         resource Group
  -h, --help                 help for api
      --kind string          resource Kind
      --make make generate   if true, run make generate after generating files (default true)
      --namespaced           resource is namespaced (default true)
      --plural string        resource irregular plural form
      --resource             if set, generate the resource without prompting the user (default true)
      --version string       resource Version

Global Flags:
      --plugins strings   plugin keys to be used for this subcommand execution

2022/12/04 11:22:00 failed to create API: unable to run post-scaffold tasks of "base.go.kubebuilder.io/v3": exec: "make": executable file not found in %PATH%

crd开发

make manifests

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/myk8sOperator (master)
$ make manifests
mkdir -p /f/go/project/0-shizhanxiangmu/myk8sOperator/bin
test -s /f/go/project/0-shizhanxiangmu/myk8sOperator/bin/controller-gen && /f/go/project/0-shizhanxiangmu/myk8sOperator/bin/controller-gen --version | grep -q v0.10.0 || \
GOBIN=/f/go/project/0-shizhanxiangmu/myk8sOperator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.10.0
go: downloading sigs.k8s.io/controller-tools v0.10.0
go: downloading github.com/fatih/color v1.12.0
go: downloading github.com/gobuffalo/flect v0.2.5
go: downloading github.com/mattn/go-colorable v0.1.8
/f/go/project/0-shizhanxiangmu/myk8sOperator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

make generate

直接下载kustuomize文件放在bin下,执行make generate生成了对应文件

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/myk8sOperator (master)
$ make generate
mkdir -p /f/go/project/0-shizhanxiangmu/myk8sOperator/bin
test -s /f/go/project/0-shizhanxiangmu/myk8sOperator/bin/controller-gen && /f/go/project/0-shizhanxiangmu/myk8sOperator/bin/controller-gen --version | grep -q v0.10.0 || \
GOBIN=/f/go/project/0-shizhanxiangmu/myk8sOperator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.10.0
/f/go/project/0-shizhanxiangmu/myk8sOperator/bin/controller-gen object:headerFile="hack\\boilerplate.go.txt" paths="./..."

连接kubernetes集群并安装crd

连接腾讯云的kubernetes集群,查看它本身的crd

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ kubectl.exe get crd
NAME                                                     CREATED AT          
loadbalancerresources.networking.tke.cloud.tencent.com   2022-12-13T02:51:32Z
tkeserviceconfigs.cloud.tencent.com                      2022-12-13T02:51:27Z
volumesnapshotclasses.snapshot.storage.k8s.io            2022-12-13T02:53:01Z
volumesnapshotcontents.snapshot.storage.k8s.io           2022-12-13T02:53:01Z
volumesnapshots.snapshot.storage.k8s.io                  2022-12-13T02:53:01Z

make install 安装crd

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ make install
mkdir -p /f/go/project/0-shizhanxiangmu/mykubeoper/bin
test -s /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen && /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen --version | grep -q v0.8.0 || \
GOBIN=/f/go/project/0-shizhanxiangmu/mykubeoper/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize version is not expected v3.8.7. Removing it before installing.
test -s /f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize || { curl -Ss "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash -s -
- 3.8.7 /f/go/project/0-shizhanxiangmu/mykubeoper/bin; }
{Version:kustomize/v3.8.7 GitCommit:ad092cc7a91c07fdf63a2e4b7f13fa588a39af4f BuildDate:2020-11-11T23:14:14Z GoOs:windows GoArch:amd64}
kustomize installed to /f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/services.traefik.wendao created

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ kubectl.exe get crd -o wide
NAME                                                     CREATED AT
loadbalancerresources.networking.tke.cloud.tencent.com   2022-12-13T02:51:32Z
services.traefik.wendao                                  2022-12-13T04:32:15Z
tkeserviceconfigs.cloud.tencent.com                      2022-12-13T02:51:27Z
volumesnapshotclasses.snapshot.storage.k8s.io            2022-12-13T02:53:01Z
volumesnapshotcontents.snapshot.storage.k8s.io           2022-12-13T02:53:01Z
volumesnapshots.snapshot.storage.k8s.io                  2022-12-13T02:53:01Z

验证crd

用一个样例文件来测试,在生成的样例文件处修改

config/samples/traefik_v1_service.yaml

apiVersion: traefik.wendao/v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/name: service
    app.kubernetes.io/instance: service-sample
    app.kubernetes.io/part-of: myk8soper
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: myk8soper
  name: service-sample
spec:
  # TODO(user): Add fields here
  entrypoint: "http"
  url: "10.10.10.10:8080"

创建crd并查看

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ kubectl.exe apply -f ./config/samples/traefik_v1_service.yaml 
service.traefik.wendao/service-sample created

类型就是根据crd的名称来看
zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ kubectl.exe get services.traefik.wendao -o wide
NAME             AGE
service-sample   91s

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ kubectl.exe describe services.traefik.wendao service-sample
Name:         service-sample
Namespace:    default
Labels:       app.kubernetes.io/created-by=myk8soper
              app.kubernetes.io/instance=service-sample
              app.kubernetes.io/managed-by=kustomize
              app.kubernetes.io/name=service
              app.kubernetes.io/part-of=myk8soper
Annotations:  <none>
API Version:  traefik.wendao/v1
Kind:         Service
Metadata:
  Creation Timestamp:  2022-12-13T06:52:56Z
  Generation:          1
  Managed Fields:
    API Version:  traefik.wendao/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
        f:labels:
          .:
          f:app.kubernetes.io/created-by:
          f:app.kubernetes.io/instance:
          f:app.kubernetes.io/managed-by:
          f:app.kubernetes.io/name:
          f:app.kubernetes.io/part-of:
      f:spec:
        .:
        f:entrypoint:
        f:url:
    Manager:         kubectl-client-side-apply
    Operation:       Update
    Time:            2022-12-13T06:52:56Z
  Resource Version:  14887488948
  Self Link:         /apis/traefik.wendao/v1/namespaces/default/services/service-sample
  UID:               dc3a4194-b25c-4850-a8ac-75ab72f29773
Spec:
  Entrypoint:  http
  URL:         10.10.10.10:8080
Events:        <none>

编写operator的controller

api/v1/service_types.go—修改一下ServiceStatus,增加一个字段

type ServiceStatus struct {
  // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
  // Important: Run "make" to regenerate code after modifying this file

  // 是否已经成功同步
  IsSync bool `json:"is_sysnc"`
  // 如果同步给Traefik失败,则记录使用原因
  FailedMessage string `json:"failed_message"`
  // 触发同步的时间
  UpdateTime int64 `json:"update_time"`
}

再次执行make manifests,生成新的yaml文件

执行make generate,生成新的go文件

删除原来的crd,用make uninstall

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ make uninstall
mkdir -p /f/go/project/0-shizhanxiangmu/mykubeoper/bin
test -s /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen && /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen --version | grep -q v0.8.0 || \
GOBIN=/f/go/project/0-shizhanxiangmu/mykubeoper/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
test -s /f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize || { curl -Ss "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash -s -
- 3.8.7 /f/go/project/0-shizhanxiangmu/mykubeoper/bin; }
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize build config/crd | kubectl delete --ignore-not-found=false -f -

安装新的crd,make install

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ make install
mkdir -p /f/go/project/0-shizhanxiangmu/mykubeoper/bin
test -s /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen && /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen --version | grep -q v0.8.0 || \
GOBIN=/f/go/project/0-shizhanxiangmu/mykubeoper/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
test -s /f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize || { curl -Ss "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash -s -
- 3.8.7 /f/go/project/0-shizhanxiangmu/mykubeoper/bin; }
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/services.traefik.wendao created

Crontroller 业务逻辑编写

Reconcile 函数是 Operator 的核心逻辑, 位于 controllers/traefikservice_controller.go 文件中, 我们修改他,添加我们的业务逻辑

// ServiceReconciler reconciles a Service object
type ServiceReconciler struct {
  client.Client
  Scheme *runtime.Scheme
}

//+kubebuilder:rbac:groups=traefik.magedu.go8,resources=services,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=traefik.magedu.go8,resources=services/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=traefik.magedu.go8,resources=services/finalizers,verbs=update

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Service object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.13.1/pkg/reconcile
func (r *ServiceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
  l := log.FromContext(ctx)

  // TODO(user): your logic here
  l.Info("start ...")

  // 1. 获取对象(用户期望的状态)
  obj := &traefikv1.Service{}
  if err := r.Get(ctx, req.NamespacedName, obj); err != nil {
    // 记录下保存信息
    l.Error(err, fmt.Sprintf("get object %s failed", req.NamespacedName))
    return ctrl.Result{}, nil
  }

  // 打印下对象
  l.Info("get an object",
    "name", req.NamespacedName,
    "entrypoint", obj.Spec.EntryPoint,
    "url", obj.Spec.URL,
  )

  // 2. 判断对象的状态
  if obj.Status.IsSync {
    // 已经同步, 无需做状态处理
    l.Info("object has synced", "name", req.NamespacedName)
    return ctrl.Result{}, nil
  }

  // 3. 操作对象 让其变成期望的状态(这里不写操作Traefik的业务路径)
  l.Info("sync to traefik success")

  // 4. 操作成功后,修改对象的状态, 变成期望状态
  obj.Status.IsSync = true
  obj.Status.UpdateTime = time.Now().Unix()

  // 5. 对象状态同步到API Server, 需要Status() 才能修改到资源的状态
  if err := r.Client.Status().Update(ctx, obj); err != nil {
    l.Error(err, "update k8s object error")
  }
  
  return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *ServiceReconciler) SetupWithManager(mgr ctrl.Manager) error {
  // 编写对应的Resoruce Controller 扩展对象
  // For(&appsv1.Deployment{}) 编写Deployment的Controller
  return ctrl.NewControllerManagedBy(mgr).
    For(&traefikv1.Service{}).
    Complete(r)
}

crd+controller调试

本地启动controller

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ make run
mkdir -p /f/go/project/0-shizhanxiangmu/mykubeoper/bin
test -s /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen && /f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen --version | grep -q v0.8.0 || \
GOBIN=/f/go/project/0-shizhanxiangmu/mykubeoper/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0                                               
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/f/go/project/0-shizhanxiangmu/mykubeoper/bin/controller-gen object:headerFile="hack\\boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go run ./main.go
1.6709186203836606e+09  INFO    controller-runtime.metrics      Metrics server is starting to listen    {"addr": ":8080"}
1.6709186203852835e+09  INFO    setup   starting manager
1.6709186203858254e+09  INFO    Starting server {"path": "/metrics", "kind": "metrics", "addr": "[::]:8080"}
1.6709186203858254e+09  INFO    Starting server {"kind": "health probe", "addr": "[::]:8081"}
1.6709186203858254e+09  INFO    Starting EventSource    {"controller": "service", "controllerGroup": "traefik.wendao", "controllerKind": "Service", "source": "kind source: *v1.Service"
}
1.6709186203863542e+09  INFO    Starting Controller     {"controller": "service", "controllerGroup": "traefik.wendao", "controllerKind": "Service"}
1.670918620488402e+09   INFO    Starting workers        {"controller": "service", "controllerGroup": "traefik.wendao", "controllerKind": "Service", "worker

运行crd

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/0-shizhanxiangmu/mykubeoper (master)
$ kubectl.exe apply -f config/samples/traefik_v1_service.yaml 
service.traefik.wendao/service-sample created

运行operator

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator
$ make run
mkdir -p /f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator/bin
test -s /f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator/bin/controller-gen && /f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator/bin/controller-gen --version | gre
p -q v0.8.0 || \
GOBIN=/f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator/bin go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0
/f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator/bin/controller-gen object:headerFile="hack\\boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go run ./main.go
1.6709229158465655e+09  INFO    controller-runtime.metrics      Metrics server is starting to listen    {"addr": ":8080"}
1.6709229158485708e+09  INFO    setup   starting manager
1.6709229158495705e+09  INFO    Starting server {"path": "/metrics", "kind": "metrics", "addr": "[::]:8080"}
1.670922915850569e+09   INFO    Starting EventSource    {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "source": "kind source: *v1.Serv
ice"}
1.670922915851587e+09   INFO    Starting Controller     {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service"}
1.6709229158495705e+09  INFO    Starting server {"kind": "health probe", "addr": "[::]:8081"}
1.6709229159595575e+09  INFO    Starting workers        {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "worker count": 1}
1.6709229538365262e+09  INFO    start ...       {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "Service": {"name":"service-sample","nam
espace":"default"}, "namespace": "default", "name": "service-sample", "reconcileID": "651d5b0a-e81e-4d8f-b2c5-860df52443c3"}
1.6709229538365262e+09  INFO    get an object   {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "Service": {"name":"service-sample","nam
espace":"default"}, "namespace": "default", "name": "service-sample", "reconcileID": "651d5b0a-e81e-4d8f-b2c5-860df52443c3", "name": {"namespace": "default", "name": "service-sample"},
 "entrypoint": "http", "url": "10.10.10.10:8080"}
1.6709229538371012e+09  INFO    sync to traefik success {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "Service": {"name":"service-samp
le","namespace":"default"}, "namespace": "default", "name": "service-sample", "reconcileID": "651d5b0a-e81e-4d8f-b2c5-860df52443c3"}
1.6709229538627574e+09  INFO    start ...       {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "Service": {"name":"service-sample","nam
espace":"default"}, "namespace": "default", "name": "service-sample", "reconcileID": "390d5a30-762a-4e25-899a-d4497aa668db"}
1.6709229538642845e+09  INFO    get an object   {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "Service": {"name":"service-sample","nam
espace":"default"}, "namespace": "default", "name": "service-sample", "reconcileID": "390d5a30-762a-4e25-899a-d4497aa668db", "name": {"namespace": "default", "name": "service-sample"},
 "entrypoint": "http", "url": "10.10.10.10:8080"}
1.6709229538652847e+09  INFO    object has synced       {"controller": "service", "controllerGroup": "traefik.magedu.go8", "controllerKind": "Service", "Service": {"name":"service-samp
le","namespace":"default"}, "namespace": "default", "name": "service-sample", "reconcileID": "390d5a30-762a-4e25-899a-d4497aa668db", "name": {"namespace": "default", "name": "service-s
ample"}}

运行效果检查

zengz@DESKTOP-Q3MJC54 MINGW64 /f/go/project/1-ProjectBatch/go8-day18/projects/k8soperator
$ kubectl.exe describe services.traefik.magedu.go8 service-sample
Name:         service-sample
Namespace:    default
Labels:       app.kubernetes.io/created-by=k8soperator
              app.kubernetes.io/instance=service-sample
              app.kubernetes.io/managed-by=kustomize
              app.kubernetes.io/name=service
              app.kubernetes.io/part-of=k8soperator
Annotations:  <none>
API Version:  traefik.magedu.go8/v1
Kind:         Service
Metadata:
  Creation Timestamp:  2022-12-13T09:15:54Z
  Generation:          1
  Managed Fields:
    API Version:  traefik.magedu.go8/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:metadata:
        f:annotations:
          .:
          f:kubectl.kubernetes.io/last-applied-configuration:
        f:labels:
          .:
          f:app.kubernetes.io/created-by:
          f:app.kubernetes.io/instance:
          f:app.kubernetes.io/managed-by:
          f:app.kubernetes.io/name:
          f:app.kubernetes.io/part-of:
      f:spec:
        .:
        f:entrypoint:
        f:url:
    Manager:      kubectl-client-side-apply
    Operation:    Update
    Time:         2022-12-13T09:15:54Z
    API Version:  traefik.magedu.go8/v1
    Fields Type:  FieldsV1
    fieldsV1:
      f:status:
        .:
        f:failed_message:
        f:is_sysnc:
        f:update_time:
    Manager:         main.exe
    Operation:       Update
    Subresource:     status
    Time:            2022-12-13T09:15:54Z
  Resource Version:  14895379840
  Self Link:         /apis/traefik.magedu.go8/v1/namespaces/default/services/service-sample
  UID:               3095b5ef-20b7-4fc7-b04d-f7404d89de7c
Spec:
  Entrypoint:  http
  URL:         10.10.10.10:8080
Status:
  failed_message:
  is_sysnc:        true
  update_time:     1670922953
Events:            <none>
5

评论区