前言
这篇博客是属于对《Kubernetes Operator 进阶开发》的初步章节一个笔记总结,作为 2023 第一篇博文,也作为重新深入梳理 K8s 的基础,往后会逐步将之前的坑给填上
Operator的基本概念
作为最入门的篇章,我们将从写一个 Demo 开始,在这里将默认已经存在了一个可用的集群环境
控制器模式
控制器模式在日常生活中的应用非常广泛,也是根据原书的例子进行举例,当然这里缩减了非常多,也加入了些个人的想法
夏天我们需要调整空调制冷,现在过程如下:
- 空调启动后设置一个温度,例如 25 度
- 空调检测室温,确定室温是否高于目标值
- 如果高于目标阈值,例如室温 27 度,则开始制冷操作
- 如果低于目标阈值,保持静默到下一个探测周期
这其实就是控制器模式典型的工作流程,外部输入一个 “期望值”,期间一个 “控制器” 不断按照 “周期” 观测 “环境状态” 的 “实际值” 和 “期望值” 之间的差异,然后不断调整两者,以便维持平衡,这个过程则被称为 “调谐”
Kubernetes中的控制器
Kubernetes 中通过 “声明式API” 定义了一系列的资源对象,然后通过许多的 Controllers 来 “调谐” 这些资源对象的实际状态以向期待状态靠拢,从而实现整个集群 “尽可能” 靠拢配置中声明的期望状态
一个Deployment的创建
我们都知道集群中有个组件,叫做 Kube-Controller-Manager
,这个组件就是一系列控制器的集合,现在可以重新梳理一下这个面试中经常被问到的问题了
在编辑好一个 Deployment YAML 配置文件并使用 Kubectl 提交后,这个资源声明就被传递给了 Kube-ApiServer
,接着 Kube-Controller-Manager
中的 Deployment 控制器监听到了消息,注意 K8s 中的组件传递原则 — 是上层组件先将自身置于被修改后的状态,即先假设资源已经被创建,而下层组件监听到了上游变化后,将自身或者环境状态 “调谐” 为上游一致,在这里 Deployment Controller 根据 Spec
字段的定义创建对应的 ReplicaSet
资源,而 RS Controller 监听到了 RS 的变化,并也根据 Spec
字段中声明创建了 Pod
,这里其实还有一个 Kubelet
的环节在中间,这里被我们抽象掉了
Operator模式
Operator 模式能让用户通过自定义资源来管理自己的应用。这种模式的本质是将一个领域运维人员的运维经验,也就是把他们所维护的应用该怎么部署、出现异常后怎么去恢复等一系列过程在 Kubernetes 上的操作程序化,并交给自定义控制器去实现
还是按照书中的例子,让我们来了解一下 Operator 的工作过程:
- 定义一个名为 SampleDB 的 Custom Resource(CRD)
- 通过 Deployment 方式部署一个 Operator 的 Controller 部分
- 在 Controller 的代码逻辑中查询 ApiServer,从而获得 SampleDB 的具体内容
- 和写 Deployment 的 YAML 一样,写一个资源声明提交,只是 Kind 为 SampleDB 而已,Operator 中的核心逻辑是告诉 ApiServer 怎么让集群的实际状态和自定义资源中的声明状态保持一致
这里的资源就是 Kubernetes API 的一个端点,包含一组特定类型对象的集合,比如 Pods 资源包含了 Pod 对象的集合。资源可以做 CURD 操作,对应了 ApiServer 代码中定义的某个结构体,如内存中的一个对象,ETCD 中的一组数据。而所谓自定义资源则是用户提交的一个类似 Deployment 声明的结构定义给 Kubernetes,并执行类似的操作逻辑(当然还是要看 Operator Controller 代码的实现)
从写一个Demo开始
Kubebuilder安装配置
Kubebuilder 是一个用于 Operator 程序构建和发布的工具,我们先将其安装到本地,然后利用 Kubebuilder 快速开发一个 Demo Operator。关于安装的方式,直接参考二进制安装即可,注意只能使用 Linux / Mac 平台。
kubebuilder
CLI tool for building Kubernetes extensions and tools.
Usage:
kubebuilder [flags]
kubebuilder [command]
Examples:
The first step is to initialize your project:
kubebuilder init [--plugins=<PLUGIN KEYS> [--project-version=<PROJECT VERSION>]]
<PLUGIN KEYS> is a comma-separated list of plugin keys from the following table
and <PROJECT VERSION> a supported project version for these plugins.
Plugin keys | Supported project versions
------------------------------------------+----------------------------
base.go.kubebuilder.io/v3 | 3
base.go.kubebuilder.io/v4-alpha | 3
declarative.go.kubebuilder.io/v1 | 2, 3
deploy-image.go.kubebuilder.io/v1-alpha | 3
go.kubebuilder.io/v2 | 2, 3
go.kubebuilder.io/v3 | 3
go.kubebuilder.io/v4-alpha | 3
grafana.kubebuilder.io/v1-alpha | 3
kustomize.common.kubebuilder.io/v1 | 3
kustomize.common.kubebuilder.io/v2-alpha | 3
For more specific help for the init command of a certain plugins and project version
configuration please run:
kubebuilder init --help --plugins=<PLUGIN KEYS> [--project-version=<PROJECT VERSION>]
Default plugin keys: "go.kubebuilder.io/v3"
Default project version: "3"
我们要通过一个 Application 类型来定义一个自己的资源对象,然后在控制器中获取这个资源对象的详细配置,接着根据它的配置去创建相应数量的 Pod,就像 Deployment 那样工作,因为是 Demo,所以这里不会考虑异常或者程序健硕等问题。
创建项目
我们直接使用 Kubebuilder 初始化一个新项目,注意需要配置好 go 环境与代理,并且 make / gcc / build-essential 等基础工具也是必备的
$ kubebuilder init --domain=sxueck.com --repo=github.com/sxueck/operator --owner sxueck
$ ls -al
total 112
drwxrwxr-x 4 ubuntu ubuntu 4096 Jan 28 14:52 .
drwxr-x--- 8 ubuntu ubuntu 4096 Jan 29 14:41 ..
drwx------ 6 ubuntu ubuntu 4096 Jan 28 14:51 config
-rw------- 1 ubuntu ubuntu 1250 Jan 28 14:51 Dockerfile
-rw------- 1 ubuntu ubuntu 129 Jan 28 14:49 .dockerignore
-rw------- 1 ubuntu ubuntu 384 Jan 28 14:49 .gitignore
-rw------- 1 ubuntu ubuntu 2932 Jan 28 14:52 go.mod
-rw-rw-r-- 1 ubuntu ubuntu 60004 Jan 28 14:52 go.sum
drwx------ 2 ubuntu ubuntu 4096 Jan 28 14:51 hack
-rw------- 1 ubuntu ubuntu 3491 Jan 28 14:51 main.go
-rw------- 1 ubuntu ubuntu 7184 Jan 28 14:51 Makefile
-rw------- 1 ubuntu ubuntu 335 Jan 28 14:52 PROJECT
-rw------- 1 ubuntu ubuntu 2724 Jan 28 14:51 README.md
接着我们在目录下面继续执行命令,用以添加 API