如何利用kubebuilder高效构建并实施K8s operator?

2026-05-22 22:011阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1679个文字,预计阅读时间需要7分钟。

一、准备在本文中,我们将设置一个Kubernetes环境,并使用Kubebuilder进行CRD(Custom Resource Definition)的开发。以下是所需的软件版本:

- Kubernetes: v1.16.3- Go: 1.15.6- Kubebuilder: 3.1.0- Docker: 20.10.7

二、安装Kubebuilder安装Kubebuilder的步骤如下:

1. 下载Kubebuilder的安装包: bash curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubebuilder

2. 使安装包可执行: bash chmod +x kubebuilder

3. 将安装包移动到PATH中: bash sudo mv kubebuilder /usr/local/bin/

一、准备

本文中的示例运行环境及相关软件版本如下:

  • Kubernetes v1.16.3
  • Go 1.15.6
  • Kubebuilder 3.1.0
  • Docker 20.10.7

安装kubebuilder:

#下载kubebuilder 3.1.0,建议二进制版本:github.com/kubernetes-sigs/kubebuilder/releases #将二进制文件copy到/usr/local/bin下 % chmod +x kubebuilder && mv kubebuilder /usr/local/bin/ #验证 % kubebuilder version 二、创建项目

% mkdir guestbook % cd guestbook % % go mod init guestbook //go mod管理包 % kubebuilder init --domain xiaohongshu.org --owner "luxiu" 三、创建API

% kubebuilder create api --group redis --version v1 --kind RedisCluster 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/rediscluster_types.go controllers/rediscluster_controller.go Update dependencies: $ go mod tidy Running make: $ make generate go: creating new go.mod: module tmp Downloading sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.1 go: found sigs.k8s.io/controller-tools/cmd/controller-gen in sigs.k8s.io/controller-tools v0.4.1 /Users/luxiu/Desktop/luxiu/project/kubernetes/crd-test/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."

API 创建完成后,在项目根目录下查看目录结构:

四、安装 CRD

这里安装CRD到指定的k8s集群里,需要修改Makefile里连接k8s配置:

install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | kubectl --context cls-j07gq3ud-context-default apply -f - uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | kubectl --context cls-j07gq3ud-context-default delete -f - deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} $(KUSTOMIZE) build config/default | kubectl --context cls-j07gq3ud-context-default apply -f - undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/default | kubectl --context cls-j07gq3ud-context-default delete -f -

执行下面命令来安装CRD:

% make install /Users/luxiu/Desktop/luxiu/project/kubernetes/crd-test/bin/controller-gen "crd:trivialVersions=true,preserveUnknownFields=false" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases /Users/luxiu/Desktop/luxiu/project/kubernetes/crd-test/bin/kustomize build config/crd | kubectl --context cls-j07gq3ud-context-default apply -f - customresourcedefinition.apiextensions.k8s.io/redisclusters.redis.xiaohongshu.org created 五、部署 Controller

在开始部署 controller 之前,我们需要先检查 kubebuilder 自动生成的 YAML 文件。

修改使用 gcr.io 镜像仓库的镜像地址

对于中国大陆用户,可能无法访问 Google 镜像仓库 gcr.io,因此需要修改 config/default/manager_auth_proxy_patch.yaml文件中的镜像地址,将其中 gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0修改为quay.io/brancz/kube-rbac-proxy:v0.8.0

有两种方式运行 controller:

  • 本地运行,用于调试
  • 部署到 Kubernetes 上运行,作为生产使用
本地运行 controller

要想在本地运行 controller,只需要执行下面的命令,你将看到 controller 启动和运行时输出:

$ make run 将 Controller 部署到指定 Kubernetes集群

这里有个问题,需要修改Dockerfile中 ,给go 设置proxy代理,这样go mod download时不至于超时连不上:

在 RUN go mod download 这行的上面加如下一行: ENV GOPROXY="goproxy.cn"

构建 controller 的镜像,并推送到公司docker harbor 上,然后在 Kubernetes 上部署 Deployment 资源,如下命令:

$ make docker-build IMG=docker-reg.devops.xiaohongshu.com/data-infra/rediscluster:v1 $ make docker-push IMG=docker-reg.devops.xiaohongshu.com/data-infra/rediscluster:v1 $ make deploy IMG=docker-reg.devops.xiaohongshu.com/data-infra/rediscluster:v1

在初始化项目时,kubebuilder 会自动根据项目名称创建一个 Namespace,如本文中的guestbook-system,查看 Deployment 对象和 Pod 资源。

% k8sdev get deployment -n guestbook-system NAME READY UP-TO-DATE AVAILABLE AGE guestbook-controller-manager 1/1 1 1 25h % k8sdev get pod -n guestbook-system NAME READY STATUS RESTARTS AGE guestbook-controller-manager-79fd58d674-fvm2m 2/2 Running 0 145m 六、创建 CR

该创建自定义资源对象CR了,如原生中的rc/deployment等对象

% k8sdev apply -f config/samples/redis_v1_rediscluster.yaml rediscluster.redis.xiaohongshu.org/rediscluster-sample created % k8sdev get RedisCluster NAME AGE rediscluster-sample 38s

至此一个基本的 Operator 框架已经创建完成,但这个 Operator 只是修改了 etcd 中的数据而已,实际上什么事情也没做,因为我们没有在 Operator 中的增加业务逻辑。

七、开发业务逻辑

下面我们将修改 CRD 的数据结构并在 controller 中增加一些日志输出。

修改 CRD

我们将修改api/v1/guestbook_types.go文件的内容,在 CRD 中增加FirstNameLastNameStatus字段。

// GuestbookSpec defines the desired state of Guestbook type GuestbookSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file // Foo is an example field of Guestbook. Edit guestbook_types.go to remove/update FirstName string `json:"firstname"` LastName string `json:"lastname"` } // GuestbookStatus defines the observed state of Guestbook type GuestbookStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file Status string `json:"Status"` } 修改 Reconcile 函数

Reconcile 函数是 Operator 的核心逻辑,Operator 的业务逻辑都位于controllers/guestbook_controller.go文件的 Reconcile函数中

func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) // your logic here // 获取当前的 CR,并打印 logger := log.FromContext(ctx) obj := &webappv1.Guestbook{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { logger.Error(err, "Unable to fetch object") return ctrl.Result{}, nil } else { logger.Info("Greeting from Kubebuilder to", obj.Spec.FirstName, obj.Spec.LastName) } // 初始化 CR 的 Status 为 Running obj.Status.Status = "Running" if err := r.Status().Update(ctx, obj); err != nil { logger.Error(err, "unable to update status") } return ctrl.Result{}, nil } 运行测试

  • 安装CRD(同上)
  • 部署controller(同上)
  • 创建CR

修改 config/samples/redis_v1_rediscluster.yaml 文件中的配置

apiVersion: redis.xiaohongshu.org/v1 kind: RedisCluster metadata: name: rediscluster-sample spec: # Add fields here firstname: Jimmy lastname: Song

执行下面命令,创建CR:

$ k8sdev apply -f config/samples/redis_v1_rediscluster.yaml

查看controller里的运行日志:

% k8sdev get pod -n guestbook-system NAME READY STATUS RESTARTS AGE guestbook-controller-manager-79fd58d674-fvm2m 2/2 Running 0 3h53m % k8sdev logs -f guestbook-controller-manager-79fd58d674-fvm2m -n guestbook-system -c manager 2022-03-08T08:24:04.641Z INFO controller-runtime.manager.controller.guestbook Greeting from Kubebuilder to {"reconciler group": "webapp.my.domain", "reconciler kind": "Guestbook", "name": "guestbook-sample", "namespace": "default", "Jimmy": "Song"} 2022-03-08T08:24:04.651Z INFO controller-runtime.manager.controller.guestbook Greeting from Kubebuilder to {"reconciler group": "webapp.my.domain", "reconciler kind": "Guestbook", "name": "guestbook-sample", "namespace": "default", "Jimmy": "Song"}

参考:部署k8s operator

本文共计1679个文字,预计阅读时间需要7分钟。

一、准备在本文中,我们将设置一个Kubernetes环境,并使用Kubebuilder进行CRD(Custom Resource Definition)的开发。以下是所需的软件版本:

- Kubernetes: v1.16.3- Go: 1.15.6- Kubebuilder: 3.1.0- Docker: 20.10.7

二、安装Kubebuilder安装Kubebuilder的步骤如下:

1. 下载Kubebuilder的安装包: bash curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubebuilder

2. 使安装包可执行: bash chmod +x kubebuilder

3. 将安装包移动到PATH中: bash sudo mv kubebuilder /usr/local/bin/

一、准备

本文中的示例运行环境及相关软件版本如下:

  • Kubernetes v1.16.3
  • Go 1.15.6
  • Kubebuilder 3.1.0
  • Docker 20.10.7

安装kubebuilder:

#下载kubebuilder 3.1.0,建议二进制版本:github.com/kubernetes-sigs/kubebuilder/releases #将二进制文件copy到/usr/local/bin下 % chmod +x kubebuilder && mv kubebuilder /usr/local/bin/ #验证 % kubebuilder version 二、创建项目

% mkdir guestbook % cd guestbook % % go mod init guestbook //go mod管理包 % kubebuilder init --domain xiaohongshu.org --owner "luxiu" 三、创建API

% kubebuilder create api --group redis --version v1 --kind RedisCluster 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/rediscluster_types.go controllers/rediscluster_controller.go Update dependencies: $ go mod tidy Running make: $ make generate go: creating new go.mod: module tmp Downloading sigs.k8s.io/controller-tools/cmd/controller-gen@v0.4.1 go: found sigs.k8s.io/controller-tools/cmd/controller-gen in sigs.k8s.io/controller-tools v0.4.1 /Users/luxiu/Desktop/luxiu/project/kubernetes/crd-test/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."

API 创建完成后,在项目根目录下查看目录结构:

四、安装 CRD

这里安装CRD到指定的k8s集群里,需要修改Makefile里连接k8s配置:

install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | kubectl --context cls-j07gq3ud-context-default apply -f - uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/crd | kubectl --context cls-j07gq3ud-context-default delete -f - deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} $(KUSTOMIZE) build config/default | kubectl --context cls-j07gq3ud-context-default apply -f - undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. $(KUSTOMIZE) build config/default | kubectl --context cls-j07gq3ud-context-default delete -f -

执行下面命令来安装CRD:

% make install /Users/luxiu/Desktop/luxiu/project/kubernetes/crd-test/bin/controller-gen "crd:trivialVersions=true,preserveUnknownFields=false" rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases /Users/luxiu/Desktop/luxiu/project/kubernetes/crd-test/bin/kustomize build config/crd | kubectl --context cls-j07gq3ud-context-default apply -f - customresourcedefinition.apiextensions.k8s.io/redisclusters.redis.xiaohongshu.org created 五、部署 Controller

在开始部署 controller 之前,我们需要先检查 kubebuilder 自动生成的 YAML 文件。

修改使用 gcr.io 镜像仓库的镜像地址

对于中国大陆用户,可能无法访问 Google 镜像仓库 gcr.io,因此需要修改 config/default/manager_auth_proxy_patch.yaml文件中的镜像地址,将其中 gcr.io/kubebuilder/kube-rbac-proxy:v0.8.0修改为quay.io/brancz/kube-rbac-proxy:v0.8.0

有两种方式运行 controller:

  • 本地运行,用于调试
  • 部署到 Kubernetes 上运行,作为生产使用
本地运行 controller

要想在本地运行 controller,只需要执行下面的命令,你将看到 controller 启动和运行时输出:

$ make run 将 Controller 部署到指定 Kubernetes集群

这里有个问题,需要修改Dockerfile中 ,给go 设置proxy代理,这样go mod download时不至于超时连不上:

在 RUN go mod download 这行的上面加如下一行: ENV GOPROXY="goproxy.cn"

构建 controller 的镜像,并推送到公司docker harbor 上,然后在 Kubernetes 上部署 Deployment 资源,如下命令:

$ make docker-build IMG=docker-reg.devops.xiaohongshu.com/data-infra/rediscluster:v1 $ make docker-push IMG=docker-reg.devops.xiaohongshu.com/data-infra/rediscluster:v1 $ make deploy IMG=docker-reg.devops.xiaohongshu.com/data-infra/rediscluster:v1

在初始化项目时,kubebuilder 会自动根据项目名称创建一个 Namespace,如本文中的guestbook-system,查看 Deployment 对象和 Pod 资源。

% k8sdev get deployment -n guestbook-system NAME READY UP-TO-DATE AVAILABLE AGE guestbook-controller-manager 1/1 1 1 25h % k8sdev get pod -n guestbook-system NAME READY STATUS RESTARTS AGE guestbook-controller-manager-79fd58d674-fvm2m 2/2 Running 0 145m 六、创建 CR

该创建自定义资源对象CR了,如原生中的rc/deployment等对象

% k8sdev apply -f config/samples/redis_v1_rediscluster.yaml rediscluster.redis.xiaohongshu.org/rediscluster-sample created % k8sdev get RedisCluster NAME AGE rediscluster-sample 38s

至此一个基本的 Operator 框架已经创建完成,但这个 Operator 只是修改了 etcd 中的数据而已,实际上什么事情也没做,因为我们没有在 Operator 中的增加业务逻辑。

七、开发业务逻辑

下面我们将修改 CRD 的数据结构并在 controller 中增加一些日志输出。

修改 CRD

我们将修改api/v1/guestbook_types.go文件的内容,在 CRD 中增加FirstNameLastNameStatus字段。

// GuestbookSpec defines the desired state of Guestbook type GuestbookSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file // Foo is an example field of Guestbook. Edit guestbook_types.go to remove/update FirstName string `json:"firstname"` LastName string `json:"lastname"` } // GuestbookStatus defines the observed state of Guestbook type GuestbookStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file Status string `json:"Status"` } 修改 Reconcile 函数

Reconcile 函数是 Operator 的核心逻辑,Operator 的业务逻辑都位于controllers/guestbook_controller.go文件的 Reconcile函数中

func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = log.FromContext(ctx) // your logic here // 获取当前的 CR,并打印 logger := log.FromContext(ctx) obj := &webappv1.Guestbook{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { logger.Error(err, "Unable to fetch object") return ctrl.Result{}, nil } else { logger.Info("Greeting from Kubebuilder to", obj.Spec.FirstName, obj.Spec.LastName) } // 初始化 CR 的 Status 为 Running obj.Status.Status = "Running" if err := r.Status().Update(ctx, obj); err != nil { logger.Error(err, "unable to update status") } return ctrl.Result{}, nil } 运行测试

  • 安装CRD(同上)
  • 部署controller(同上)
  • 创建CR

修改 config/samples/redis_v1_rediscluster.yaml 文件中的配置

apiVersion: redis.xiaohongshu.org/v1 kind: RedisCluster metadata: name: rediscluster-sample spec: # Add fields here firstname: Jimmy lastname: Song

执行下面命令,创建CR:

$ k8sdev apply -f config/samples/redis_v1_rediscluster.yaml

查看controller里的运行日志:

% k8sdev get pod -n guestbook-system NAME READY STATUS RESTARTS AGE guestbook-controller-manager-79fd58d674-fvm2m 2/2 Running 0 3h53m % k8sdev logs -f guestbook-controller-manager-79fd58d674-fvm2m -n guestbook-system -c manager 2022-03-08T08:24:04.641Z INFO controller-runtime.manager.controller.guestbook Greeting from Kubebuilder to {"reconciler group": "webapp.my.domain", "reconciler kind": "Guestbook", "name": "guestbook-sample", "namespace": "default", "Jimmy": "Song"} 2022-03-08T08:24:04.651Z INFO controller-runtime.manager.controller.guestbook Greeting from Kubebuilder to {"reconciler group": "webapp.my.domain", "reconciler kind": "Guestbook", "name": "guestbook-sample", "namespace": "default", "Jimmy": "Song"}

参考:部署k8s operator