一、准备

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

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

安装kubebuilder:

#下载kubebuilder 3.1.0,建议二进制版本:https://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="https://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 中增加 FirstNameLastName 和 Status 字段。

// 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

使用 kubebuilder 创建并部署 k8s-operator的更多相关文章

  1. ansible一键部署k8s单机环境

    一.虚拟机准备 干净的Centsot7.4.4G内存.2个CPU 最小化安装,最好带虚拟化 二.执行初始化脚本 注意:脚本中配置静态网卡根据实际网卡名称配置,我用的是ens33 可以用 sed -i ...

  2. 二进制部署k8s

    一.二进制部署 k8s集群 1)参考文章 博客: https://blog.qikqiak.com 文章: https://www.qikqiak.com/post/manual-install-hi ...

  3. 【原】二进制部署 k8s 1.18.3

    二进制部署 k8s 1.18.3 1.相关前置信息 1.1 版本信息 kube_version: v1.18.3 etcd_version: v3.4.9 flannel: v0.12.0 cored ...

  4. centos7.8 安装部署 k8s 集群

    centos7.8 安装部署 k8s 集群 目录 centos7.8 安装部署 k8s 集群 环境说明 Docker 安装 k8s 安装准备工作 Master 节点安装 k8s 版本查看 安装 kub ...

  5. 在Azure Container Service创建Kubernetes(k8s)群集运行ASP.NET Core跨平台应用程序

    引子 在此前的一篇文章中,我介绍了如何在本地docker环境中运行ASP.NET Core跨平台应用程序(http://www.cnblogs.com/chenxizhang/p/7148657.ht ...

  6. 微服务架构 - 离线部署k8s平台并部署测试实例

    一般在公司部署或者真实环境部署k8s平台,很有可能是内网环境,也即意味着是无法连接互联网的环境,这时就需要离线部署k8s平台.在此整理离线部署k8s的步骤,分享给大家,有什么不足之处,欢迎指正. 1. ...

  7. 部署 k8s Cluster(上)[转]

    我们将部署三个节点的 Kubernetes Cluster. k8s-master 是 Master,k8s-node1 和 k8s-node2 是 Node. 所有节点的操作系统均为 Ubuntu ...

  8. ubuntu18.04使用kubeadm部署k8s单节点

    实验目的: 体验kubeadm部署k8s服务,全流程体验! 实验环境: ubuntu18.04 联网在线部署 kubeadm 01.系统检查 节点主机名唯一,建议写入/etc/hosts 禁止swap ...

  9. Kubeasz部署K8s基础测试环境简介

    下面介绍使用Kubeasz部署K8s集群环境. https://github.com/easzlab/kubeasz在需要使用kubeeasz项目安装的k8s时,需要将所有需要它来部署的节点上,都安装 ...

随机推荐

  1. AtCoder Beginner Contest 146_E - Rem of Sum is Num

    预处理即可 我们要找的是 (f[i] - f[j]) % k == i - j 移项可得 f[i] - i = f[j] - j 在 i - j <= k 的条件下 因此题目变成了,对于每个右端 ...

  2. Codeforces Round #739 (Div. 3)

    A. Dislike of Threes 简单的水题,预处理即可 AC_CODE #include <bits/stdc++.h> using namespace std; templat ...

  3. 布客&#183;ApacheCN 编程/后端/大数据/人工智能学习资源 2020.7

    公告 我们的群共享文件有备份到 IPFS 的计划,具体时间待定. 我们的机器学习群(915394271)正式改名为财务提升群,望悉知. 请关注我们的公众号"ApacheCN",回复 ...

  4. 布客&#183;ApacheCN 翻译/校对/笔记整理活动进度公告 2020.1

    注意 请贡献者查看参与方式,然后直接在 ISSUE 中认领. 翻译/校对三个文档就可以申请当负责人,我们会把你拉进合伙人群.翻译/校对五个文档的贡献者,可以申请实习证明. 请私聊片刻(52981514 ...

  5. 读取数据库Blob类型的文本数据

    开发一个查询功能时,遇到了一个ORM的问题:数据库字段是 Blob 类型,里面实际存储的是文本数据,Java 后端代码中用字符串 String 类型去接收这个字段的数据时,报错,提示没有对应的sett ...

  6. bom案例3-放大镜

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  7. 对JSP中的Session 简单理解

    我的理解: 简单来说,要使用服务器端的session对象,就是要有其对应的key,即sessionid,它只认识sessionid. 下面我说的cookie,url重写或者隐藏表单,都是为了将其对应的 ...

  8. JFrame实现圆角窗体

    感谢大佬:https://blog.csdn.net/Mr_Pang/article/details/47808299?utm_source=blogxgwz0 注:使用AWTUtilities类跨平 ...

  9. 数组中包含多个对象 按照对象中的时间进行排序 适用与Angular.js、Jquery、微信小程序等

         LiveList.sort(this.compare('StartDate'))   //StartData:需要排序的时间   compare: function (property) { ...

  10. shell——trap捕捉信号(附信号表)

    trap捕捉信号有三种形式 第一种:trap "commands" signal-list 当脚本收到signal-list清单内列出的信号时,trap命令执行双引号中的命令. 例 ...