通过本文的讲解, 你将大体了解 Kubebuilder 的开发流程, 及其中的关注要点;
本文实践的代码示例请参考: kube-falcon
下载与安装
我们可以到 kubebuilder 在 github 上的 releases 页面, 下载支持当前系统的二进制包;
以 mac 系统为例, 具体的安装步骤如下:
1 | # 解压安装包 |
创建一个项目
1 | # 创建项目目录 |
创建一个 API
这里我们创建一个 group 为 app, version 为 v1, kind 为 DeployObject 的 api:1
2# 创建 API
$ kubebuilder create api --group app --version v1 --kind DeployObject
执行后, 项目中的 api/
controllers/
会分别生成对应的文件;
目录结构
当我们使用 kubebuilder 脚手架初始化了一个项目目录, 并创建了一个 API 后, 可以大致看到如下结构:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30.
├── Dockerfile # 用于构建控制器镜像的 Dockerfile
├── Makefile # 用于控制器构建及部署的 Makefile
├── PROJECT # 勇于生成组件的 kubebuilder 元数据
├── README.md
├── api # API 模板代码所在目录
│ └── v1
│ ├── deployobject_types.go # API 类型文件, 主要关注 Spec 与 Status 结构体
│ ├── groupversion_info.go # 此文件包含了 Group Version 的一些元信息
│ └── zz_generated.deepcopy.go # 自动生成的 runtime.Object 实现
├── bin
│ └── manager
├── config # 采用 Kustomize YAML 定义的配置
│ ├── certmanager/ # 证书管理相关
│ ├── crd/ # CRD 相关, 当 make install 将 apply 此目录 yaml
│ ├── default/ # 控制器相关, 当 make deploy 将 apply 此目录 yaml
│ ├── manager/
│ ├── prometheus/ # 监控相关
│ ├── rbac/ # RBAC 权限管理
│ ├── samples/ # CR 样例
│ └── webhook/ # webhook相关
├── controllers # 控制器逻辑所在目录
│ ├── deployobject_controller.go # 控制器 reconcile 逻辑实现所在文件
│ └── suite_test.go # 测试文件
├── cover.out
├── go.mod # Go Mod 配置文件,记录依赖信息
├── go.sum
├── hack
│ └── boilerplate.go.txt
└── main.go # 程序入口
开发阶段
我们使用 kubebuilder 的目的是为了扩展 Kubernetes API, 实现我们的自定义需求;
换言之, 我们是要利用声明式 API 的方式, 扩展及构建属于我们自己的自定义资源(CRD);
那么什么是声明式 API 呢?
其实通俗的讲就是”告知处理者, 你的最终需求是什么, 而不是告知处理者, 他该怎么做”;
即我们定义一个 K8S 对象的终态(Custom Resource), 让处理者自行处理实现, 其中的处理过程不需要关心, 这里的处理者就是控制器(Controller);
所以对于开发者来讲, 实现自定义资源的扩展, 需要进行两个步骤:
- 编写 CRD 并将其部署至 K8S 集群中;
- 编写 Controller 并将其部署至 K8S 集群中;
以上提及的这两个步骤, 在 kubebuilder 的开发流程中都有所对应;
1. 编写 CRD
编写 CRD, 本质上是设计及定义声明式 API 的属性字段;
这里面着重关注${ProjectName}/api/${Version}/${Kind}_types.go
这个文件;
在这个文件中, 我们着重关注 ${Kind}Spec
与 ${Kind}Status
这两个结构体;
这个两个结构体分别代表着一个 k8s 自定义资源所必须的两个部分spec
及status
;
我们需要将设计好的属性字段添加到所提及的上述结构体中,
然后在此之后执行 make
将会更新 config/crd/
内的 yaml 定义;
如下是实例展示:
1 | $ vi api/v1/deployobject_types.go |
1 | // DeployObjectSpec defines the desired state of DeployObject |
2. 编写 Controller
我们知道, Controller 的工作原理其实就是将自定义资源(CR)定义的预期状态与当前资源的实际状态进行比对, 若无差异则略过, 若有差异则需要将实际状态更新为预期的状态值;
这个比对更新的过程在 Controller 中被称为调谐(Reconcile);
而我们编写 Controller 的主要逻辑, 大部分都集中在这个调谐的逻辑上;
在生成的脚手架目录中, 我们主要关注 ${ProjectName}/controllers/${Kind}_controller.go
这个文件;
再此文件中, 我们要关注 Reconcile()
这个方法, 此方法中的实现即是调谐的整个逻辑;
这里展示的是一段示例的调谐逻辑,
主要功能实现了通过一个自定义资源(CR)来管理 Deployment 以及 Service 的逻辑:
1 | $ vi controllers/deployobject_controller.go |
1 | func (r *DeployObjectReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { |
测试运行
执行如下命令将 config/crd
中 CRD 部署到 k8s 集群中:1
$ make install
本地运行 controller:1
$ make run
安装自定义资源(CR):1
$ kubectl apply -f config/samples/
构建及部署
构建 docker 镜像及将镜像推送镜像仓库:1
$ make docker-build docker-push IMG=<some-registry>/<project-name>:tag
使用 docker 镜像, 部署 controller 到 k8s 集群:1
$ make deploy IMG=<some-registry>/<project-name>:tag
卸载 CRDs:1
$ make uninstall
参考: