Kubernetes 开发【4】—— 基于kubebuilder开发简单的Operator

目录

开发背景

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 时,所关联的子资源也要一并删除

Kubernetes二次开发系列文章:

Kubernetes 开发【1】——webhook 实现 API Server 请求拦截和修改

Kubernetes开发【2】—— Informer的简单应用,构建Event List&Watch机制并推送到钉/企微机器人

Kubernetes 开发【3】——kubectl插件开发

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

常鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值