Operator 是 Kubernetes 的重要扩展机制,本文从 Operator 概念开始,解释并实践了 Operator 的创建,希望可以帮助大家进一步了解其概念和作用。
Operator
Operator 概念
Kubernetes 文档中 Operator 定义是这样的:
Operator 模式旨在捕获(正在管理一个或一组服务的)运维人员的关键目标。负责特定应用和 service 的运维人员,在系统应该如何运行、如何部署以及出现问题时如何处理等方面有深入的了解。
在 Kubernetes 上运行工作负载的人们都喜欢通过自动化来处理重复的任务。Operator 模式会封装我们编写的(Kubernetes 本身提供功能以外的)任务自动化代码。
Operator 的工作方式
《Kubernetes Operator》一书定义为:
Operator 通过扩展 Kubernetes 控制平面和 API 进行工作。Operator 将一个 endpoint(称为自定义资源 CR)添加到 Kubernetes API 中,该 endpoint 还包含一个监控和维护新类型资源的控制平面组件。
Operator 和 Controller 之间的联系是什么
Operator 由一组监听 Kubernetes 资源的 Controller 组成。Controller 可以实现调协(reconciliation loop),另外每个 Controller 都负责监视一个特定资源,当创建、更新或删除受监视的资源时就会触发调协。
Operator 创建工具
有一些用于创建 Kubernetes Operator 的开源项目,例如:
- Operator SDK
- Kubebuilder
- KUDO
- Metacontroller
下文将介绍 Operator-SDK 和 Kubebuilder,它们是我们最常用到的工具,这二者现在还在互相融合。
Kubernetes Controller
Controller 是一个非终止循环,用于调节系统状态,它会使 current 状态尽可能接近 desired 状态(亦称:调协,Reconciliation loop)。
reconciliation loop
我们设定温度,等于告诉恒温器我们所需状态。实际室温是当前状态。通过打开或关闭设备,恒温器会让当前状态更接近所需状态。
在 Kubernetes 中,有一组内置的 Controller 在主节点中的 controller-manager 内部运行。
内置 Controller
与内置 Controller 类似,我们可以创建自己的自定义 Operator 来管理应用程序资源的状态,无论是无状态还是有状态 。
创建 Operator
接下来是创建 Operator—Operator-SDK Scaffolding。
什么是 Operator-SDK?
Operator-SDK 是 Operator Framework 的组件,用于创建 Kubernetes 本机应用程序所需的代码。
Operator Framework 是一个开放源代码工具包,使用有效、自动化和可扩展的方式管理 Kubernetes 本地应用程序。
- Operator Framework 包括:
- Operator SDK
- Operator Lifecycle Management(OLM)
- Operator Metering
我应该创建哪种类型的运算符?
Operator-SDK 允许我们创建三种不同类型的运算符:
- Helm:我们可以创建一个 Operator,使用 Helm 图表并管理创建的 Kubernetes 资源生命周期(CRUD)。
- Ansible:与 Helm 类似,我们可以创建 Operator 来管理 Ansible playbook 和 role,以对跟踪的 Kubernetes 资源(通常是 CR)更改做出反应。
- Go:与 Helm 和 Ansible 不同,基于 Go-lang 的 Operator 需要创建自定义逻辑,以监控资源以及协调应用程序状态。相对而言,它更为复杂,但它可以提供自由灵活的方式来实现我们想要的逻辑,当然,这需要我们比较熟悉 Go 编程语言。
Operator Libraries
Operator 利用 library 与 Kubernetes API 进行交互,例如 client-go 和 controller-runtime。了解它们的工作方式(Informer、Lister、WorkQueue、runtime.Object 和 Scheme)非常重要,如果创建 Go Operator,那就需要编写代码。
Operator-SDK 和 Kubebuilder 融合
在 GitHub 上,层级有两个不同的开源项目用于创建 Operator,现在它们为实现同一目标而共同努力。它们之前生成代码,是不同的项目结构,但现在可以使用相同的结构样式。
Operator 例子
Operator 通常会对资源(Deployment、Job、Secret、Service、Pod 等)进行 CRUD 操作,并更新它们的状态。利用 go 模板或第三方库(例如 Manisfestival)可以使用程序模板或声明性方法来创建或编辑资源。
GitHub 上有一个不错的精选列表,叫 Awesome Operators,它有很多 Operator 脚手架工具(scaffolding tool)创建的不同项目。
列表地址:github.com/operator-framework/awesome-operators
Operator Hub
Kubernetes 社区创建了一个 Operator 托管场所,称为 Operator Hub。在这里,我们可以发布我们的 Operator,类似于其他 Hub,例如 Docker、Helm 等。
Helm vs Operator
大家可能有这么一个疑问,如果使用 Operator 管理 Kubernetes 生命周期资源(例如 CRUD 操作),为什么不用 Helm?我们可以这么理解,Helm 是针对第 1 天的操作,而 Operator 则针对第 2 天的操作。
- 第 0 天:在软件开发中,它代表了设计阶段,在此阶段我们收集解决方案的所有要求。
- 第 1 天:这是我们首次安装应用程序和基础架构的时间。
- 第 2 天:这个时间我们在管理生产中应用程序和软件的生命周期,以确保一切都正常运行,如备份、还原、故障转移、后备。
例如,我们通过 Helm 图表安装了一个应用程序(假设它创建了 Deployment、Service 和 Ingress),然后不小心删除了 Service,应用程序将停止运行。从 Helm 角度来看,在应用新配置之前,它看上去是正常的,我们不会意识到更改。这就是 Operator 发挥作用的地方,在这个例子中,如果有人误删除了 Service,并且 Operator 正在监控该资源,它将在恢复过程中重新创建,因此应用程序将恢复正常。Helm 和 Operators 是互补的,不是互斥的。
Operation Days
一个简单的 CI/CD Operator
现在开始创建一个简单的 CI/CD Operator,我们可以在 GitHub、Bitbucket 存储库中获取源代码,构建镜像,将其推送到 Docker 注册表,再部署在 Kubernetes 上。
目的
一定程度的自动化可以减少我们的工作量,Operator 就可以帮助我们有更多的时间工作,并改善和增强其他功能。
创建 Kubernetes 集群测试 Operator
首先,我们创建 Kubernetes 集群,以便部署自定义 Operator。我们使用 KinD,这是一个使用 Docker 容器创建 Kubernetes 集群的开源工具。
创建 KinD 集群非常简单,我们创建一个具有一个主节点、两个工作节点和一个 docker 注册表的集群,以便我们构建、推送和部署 Operator 到 Kubernetes 中。
这里创建了一个 GitHub Gist,它使用简单的 bash 脚本。对了,作为运行脚本的先决条件,需要在计算机上安装 Docker 引擎(engine)和 kubectl。
运行 KinD 集群
在本地计算机上执行上述脚本后,我们就有了一个功能齐全的 Kubernetes 集群。另外,集群的每个节点都有一个已安装的目录,以备将来需要创建持久卷时使用。
CI/CD Operator 架构
下图是 CI/CD Operator 的体系结构拓扑,它描述了 Operator 安装到 Kubernetes 集群后是如何工作的。
a)在 Kubernetes 集群上安装了 Operator 后,human Operator 或管道(pipeline)便会通过 kubectl 创建自定义资源。
b)Operator 控制器循环(controllers loop)监控通过 API Server 创建的资源,并触发协调方法。
c)CI 控制器(controller)将触发协调方法,该方法会创建 Job 以构建代码。
d)Job 包含一个带有 Git-Sync 的 init 容器,将 Git 存储库代码克隆到容器上的工作区目录中。
e)初始化容器完成其任务时,带有 Kaniko 镜像的主容器将构建代码并将其推送到内部 Docker 注册表。
f)Job完成(complete 状态)后,将启动 CD 控制器以创建 Deployment 资源。
g)Deployment 被创建后,会被步骤 e 中推送的镜像从注册表中拉取。目前还没有为应用程序创建 Service 和 Ingress。
生成 Operator 代码
我们使用 Operator-SDK CLI 生成样板代码,并开始对其进行迭代。我们要先在本地计算机上安装 Operator-SDK、Go-lang 和 Git。
现在我们已经搭建了 Operator 代码,最初生成的代码能够监视自定义资源,然后创建一个由 Operator 管理的简单 Pod。
下一步:创建 type 或数据结构,我们再将其作为 Operator 逻辑的一部分实现。在示例中有几个属性,如 GitHub 存储库 endpoint、连接到凭据的 SSH secret、在 mono 存储库下的 subContext(subPath)、Docker Registry 中的镜像目标以及 GitHub 分支获取并构建代码。
CIBuild Type
在控制器(controller)中定义了数据结构(Spec)和自定义逻辑后,就可以进行构建并推送到注册表。
成功构建 Operator 后,我们就可以在 Kubernetes 上运行、部署它了。
一旦 Operator 启动并运行,我们为 GitHub、Bitbucket 和 CI/CD 自定义资源创建一个 secret 。
Bitbucket SSH 配置
GitHub SSH 配置
这样,我们在 Kubernetes 上启动并运行 Operator 和 controller,再由 Operator 创建的 Job(git-sync)复制源代码的 Git secret。接着,我们创建自定义资源(CR),将 CR 安装到 Kubernetes API 扩展中。CI controller 将调用和解方法(reconcile method)来创建 Job,以构建、push 容器到 Docker 注册表。Job 完成后,CD controller 将基于注册表提取镜像来创建应用程序 deployment 资源。
Ace 应用程序
Java 应用程序
配置 Admission Webhook
Admission Webhook 是一种用于接收准入请求并对其进行处理的 HTTP 回调机制。Admission Webhook 有两种类型:validating 和 mutating 。
Validating webhook 可用于执行超出 OpenAPI 架构验证功能的验证,例如确保字段在常见后是不可变的,或者对向 API Server 发出请求的用户进行更高级别的权限检查。
通过 Validating admission webhook,我们可以拒绝自定义准入策略的请求。
Mutating webhook 常用于默认设置,在创建时往在资源中添加未设置字段的默认值。
Mutating webhook 是 Istio 将 Sidecar proxy 自动注入用户 Pod 的方法。
Mutating and Validating Webhook
为了使 Webhook 正常工作,我们需要在 Kubernetes 上安装 Cert Manager,并在 Operator 的 Dockerfile 中设置环境属性 ENABLE_WEBHOOKS = true,以便 controller 启用 Webhook 逻辑。
Cert-manager 是 Kubernetes 的附加组件,用于自动管理和颁发各种发行来源的 TLS 证书。它可以确保证书有效并定期更新,在到期前的适当时间还会更新证书。
安装 Cert Manager:
运行上述命令后,将在 cert-manager 命名空间(cert-manager、ca-injector 和 webhook)中创建具有 3 个 deployment 的新命名空间。
cert-manager 对象
总结
希望这篇文章对大家了解 Operator 有帮助。Kubernetes 上的几乎所有内容都依赖于控制器(controller),掌握它可以减少我们了解 Kubernetes 生态系统中其他项目的时间。