目录
开发背景
operator模式 in K8S
operator 的 作用及其构成
operator 实现
简易流程
关键功能(持续更新)
状态显示
事件支持
watch 子资源
集联删除
开发背景
operator模式 in K8S
Kubernetes 为自动化而生。无需任何修改,你即可以从 Kubernetes 核心中获得许多内置的自动化功能。 你可以使用 Kubernetes 自动化部署和运行工作负载, 甚至 可以自动化 Kubernetes 自身。
Kubernetes 的 Operator 模式概念允许你在不修改 Kubernetes 自身代码的情况下, 通过为一个或多个自定义资源关联控制器来扩展集群的能力。 Operator 是 Kubernetes API 的客户端, 充当自定义资源的控制器。
operator 的 作用及其构成
使用 Operator 可以自动化的事情包括:
- 按需部署应用
- 获取/还原应用状态的备份
- 处理应用代码的升级以及相关改动。例如,数据库 schema 或额外的配置设置
- 发布一个 service,要求不支持 Kubernetes API 的应用也能发现它
- 模拟整个或部分集群中的故障以测试其稳定性
- 在没有内部成员选举程序的情况下,为分布式应用选择首领角色
以上释义来自官方文档;我以组件化的表达方式去描述 operator,它大概由三部分组成,包括了:
- CRD
- webhook
- controller
crd 是指我们定义了什么样的一种资源,定义它需要什么字段(schema),这些字段的值描述了我们对于这个资源的预期(终态);
webhook 是指我们在描述这个资源时的校验规则(显式),以及它必须包含什么字段(隐式);
controller 里实现了list&watch自定义资源,去不断触发 Reconsile 函数来响应,这个过程叫做调谐循环(Reconsile Loop)。
在本文中,我们将使用 kubebuilder 脚手架 撸一个简单的 redisCluster 出来。
operator 实现
简易流程
创建一个 New Project 并创建 go.mod。
初始化工程。
kubebuilder init --domain xxx.com
创建api,其中定义了 CR 的 GVK。
kubebuilder create api --group myapp --version v1 --kind Redis
生成了如下的目录结构:
.
├── Dockerfile
├── Makefile
├── PROJECT
├── README.md
├── api
├── bin
├── config
├── controllers
├── go.mod
├── go.sum
├── hack
└── main.go
首先到 /api/v1/redis_types.go 文件下对 CRD 的 api 添加字段,也就是我们最后 apply 的 yaml 中包含的字段。
// RedisSpec defines the desired state of Redis
type RedisSpec 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 Redis. Edit redis_types.go to remove/update
//Foo string `json:"foo,omitempty"`
// +kubebuilder:validation:Maximum:=40000
// +kubebuilder:validation:Minimum:=80
Port int `json:"port,omitempty"` //我们添加了一个Port字段
}
添加了一个 Port 字段,最终我们会创建一个 ContainerPort 为其值的 redis pod,其中,我们可以通过添加注释的方式去限制Port字段的范围为 80~40000,还可以通过正则表达式来校验,参考文档:
CRD Validation - The Kubebuilder Book
在 /config/samples/myapp_v1_redis.yaml 中,我们可以添加刚才的字段以及属性值,以应用测试用。
apiVersion: myapp.xxx.com/v1
kind: Redis
metadata:
name: myredis
spec:
port: 1011
至此,我们完成了对 CRD 的基本定义,然后执行
make install
安装 crd 到集群里,这里其实是通过 kubectl 和 kustomize 去 apply 的,所以会安装 CRD 到我本机的~/.kube/config中配置的集群里去。
接下里就要实现 controller ,包括其中最核心的 Reconcile 调谐函数,目录在 /controller/redis_controller.go。
func (r *RedisReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
// TODO(user): your logic here
redis := &myappv1.Redis{}
if err := r.Get(ctx, req.NamespacedName, redis); err != nil {
fmt.Println(err)
} else {
fmt.Println("得到对象", redis)
// TODO client-go创建pod
}
return ctrl.Result{}, nil
}
以上代码实现了一段最简单的控制器逻辑,当然我们也可以继续扩充,使用 client-go 以及获取到的 redis 对象来创建对应的 redis pod。
编写完成后,我们可以通过执行 make run 本地启动 controller,并通过执行 kubectl apply redis.yaml 来测试控制器。
当测试完成后,我们需要实际应用 controller 到我们的集群中去时,执行
make docker-build docker-push IMG=registryurl
推送镜像,然后执行
make deploy IMG=registryurl
将 controller 部署到集群中去。
至此,我们就完成了最简单的 operator 开发。
关键功能(持续更新)
参考 deployment 和 pod 之前的关系,在实际的应用过程中,我们可能还要实现以下功能:
- 状态显示
- 事件支持
- watch 子资源
- 集联删除
- webhook校验yaml字段有效性
- 副本伸缩处理
这部分后续将缓慢更新。
状态显示
指的是 kubectl get 我们的 crd 时,命令行返回结果的字段展示;以及 kubectl describe 对应资源时yaml里面的字段
找到 redis CRD 对象的 schema,其位于 /api/v1/redis_types.go
// Redis is the Schema for the redis API
type Redis struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec RedisSpec `json:"spec,omitempty"`
Status RedisStatus `json:"status,omitempty"`
}
其中已经为我们定义好了 type struct RedisStatus ,这里面的字段都是用于展示资源列表中资源的状态字段,默认为空。
我们可以在结构体内添加我们预期的状态字段:
// RedisStatus defines the observed state of Redis
type RedisStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
RedisNum int `json:"num"`
}
当 Reconcile 函数中触发了副本的伸缩,num 字段需要更新时,我们可以做如下处理:
redis.Status.RedisNum = 预期值
err := r.Status().Update(ctx, redis)
至此,我们可以通过 kubectl describe 对应资源获得其中的 num 字段以及值。
另外,我们需要将这个字段在 kubectl get 的返回结果也展示出来,通过在 Redis 结构体上添加注释即可:
//+kubebuilder:printcolumn:name="Num",type=integer,JSONPath=`.status.num`
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// Redis is the Schema for the redis API
type Redis struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec RedisSpec `json:"spec,omitempty"`
Status RedisStatus `json:"status,omitempty"`
}
具体的添加规则以及范例参考,可以转到:
Generating CRDs - The Kubebuilder Book
事件支持
指的是在 reconcile 过程中发生的一些关键事件,通过 event 机制持久化,方便问题的定位
watch 子资源
当子资源(Pod)删除时,发生的自动重建
集联删除
当删除对应的 CR 时,所关联的子资源也要一并删除