本文已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已失效。

GSoC 2020 - 为集群插件构建操作器

引言

Google 夏日代码开源活动 (Google Summer of Code) 是一个面向全球学生的项目,旨在引导他们接触开源。学生会与开源组织匹配,在暑期与他们合作三个月。

我是 Somtochi Onyekwere,来自尼日利亚奥韦里联邦科技大学。今年,我有幸与 Kubernetes(隶属于 CNCF 组织)合作,度过了一个在学习、贡献和社区互动中精彩的夏天。

具体来说,我参与了 集群插件:打包所有东西! 项目。该项目专注于构建操作器,以便更好地管理各种集群插件,扩展构建这些操作器的工具,并使操作器的创建过程更加顺畅。

背景

过去几年,Kubernetes 取得了巨大进步,社区繁荣,贡献者众多。代码库正逐步从所有代码都位于 kubernetes/kubernetes 仓库的单体结构,转向拆分成多个子项目。集群插件的重点之一是让这些子项目以易于组合、自监控、自修复和 Kubernetes 原生的方式协同工作。这使它们能够无缝运行,无需人工干预。

社区正在探索使用操作器作为一种机制来监控集群中的各种资源并妥善管理这些资源。此外,它提供了自修复能力,并且是一种 Kubernetes 原生模式,可以将这些插件的最佳工作方式编码进去并妥善管理它们。

什么是集群插件?集群插件是资源的集合(如 Service 和 Deployment),用于为 Kubernetes 集群提供附加功能。它们涵盖从简单的 Kubernetes Dashboard(用于可视化)到更复杂的 Calico(用于网络)等各种功能。这些插件对于在集群中运行的不同应用以及集群本身至关重要。插件操作器提供了一种更好的方式来管理这些插件并了解构成插件的各种资源的健康状况和状态。你可以在这篇文章中获得更深入的概述。

操作器是带有自定义资源定义的自定义控制器,它们编码了应用特定的知识,并用于管理复杂有状态的应用。这是一种被广泛接受的模式。通过操作器管理插件,这些操作器编码了插件最佳工作方式的知识,带来了许多优势,同时也设定了易于遵循和扩展的标准。这篇文章很好地解释了操作器。

插件操作器可以解决很多问题,但也面临挑战。cluster-addons 项目下的那些操作器存在缺失的部分,并且仍处于概念验证阶段。为操作器生成 RBAC 配置曾令人头疼,有时操作器会被赋予过多权限。操作器可扩展性不强,因为它只能从本地文件系统或 HTTP(s) 服务器拉取清单,而且许多简单的插件都在生成相同的代码。我整个夏天都在研究这些问题,用全新的视角审视它们,并为已知和未知的问题寻求解决方案。

kubebuilder-declarative-pattern 的各项新增功能

kubebuilder-declarative-pattern (下文简称 KDP) 仓库是在 kubebuilder SDK 之上的一层额外的插件特定工具,通过向 kubebuilder create 命令传递实验性的 --pattern=addon 标志来启用。它们共同为插件操作器创建基础代码。在实习期间,我在 KDP 和 cluster-addons 中开发了一些功能。

操作器版本检查

启用操作器版本检查有助于更安全地升级/降级到不同版本的插件,即使操作器本身逻辑复杂。这是一种将插件版本与知道如何良好管理该插件版本的操作器版本进行匹配的方式。大多数插件都有不同的版本,并且这些版本可能需要不同的管理方式。此功能会检查自定义资源中名为 addons.k8s.io/min-operator-version 的注解,该注解声明了管理当前插件版本所需的最低操作器版本。如果操作器版本低于所需的最低版本,操作器将暂停并报错,告知用户操作器版本太低。这有助于确保为插件使用了正确的操作器。

用于存储清单的 Git 仓库

之前,仅支持本地文件目录和 HTTPS 仓库来存储清单。让插件操作器的创建者能够在 GitHub 仓库中存储清单,可以加快开发速度并实现版本控制。启动控制器时,你可以传递一个标志来指定你的 channels 目录的位置。channels 目录包含不同版本的清单,控制器会从该目录拉取清单并将其应用到集群。在实习期间,我对其进行了扩展,使其支持包含 Git 仓库。

临时禁用协调的注解

确保期望状态与实际状态一致的协调循环会阻止修改集群中的对象。这使得在集群中进行实验或调查问题变得困难,因为任何更改都会被迅速恢复。我通过允许用户在不希望控制器协调的资源上添加一个 addons.k8s.io/ignore 注解来解决这个问题。控制器会检查此注解并且不会协调该对象。要恢复协调,可以从资源中移除该注解。

kubebuilder-declarative-pattern 中的 Unstructured 支持

我参与开发的一个操作器是一个通用控制器,可以管理多个不需要额外配置的集群插件。为此,该操作器不能使用特定类型,并且需要 kubebuilder-declarative-repo 支持使用 unstructured.Unstructured 类型。kubebuilder-declarative-pattern 中有许多函数无法处理此类型,如果传入的对象不是 addonsv1alpha1.CommonObject 类型,则会返回错误。这些函数被修改以同时处理 unstructured.Unstructuredaddonsv1alpha.CommonObject 类型。

工具和命令行程序

我还编写了一些命令行程序,可以用来简化使用插件操作器的过程。其中大多数在插件操作器之外也有用武之地,因为它们试图解决在使用 Kubernetes 时可能遇到的特定问题。我鼓励你在有机会时查看它们

RBAC 生成器

操作器最大的问题之一是 RBAC。你需要手动查看清单并为每个资源添加 RBAC 规则,因为在集群内运行时,操作器需要有 RBAC 权限才能创建、获取、更新和删除清单中的资源。构建 RBAC 生成器自动化了编写 RBAC 角色和角色绑定的过程。RBAC 生成器的功能很简单。它接受清单的文件名作为标志。然后,它解析清单并获取资源的 API 组和资源名称,并将其添加到角色中。如果解析了 --out 标志,它将角色和角色绑定输出到标准输出或文件。

此外,该工具允许你通过分离清单中的集群角色来拆分 RBAC。这减轻了操作器权限过高的安全顾虑,因为它需要拥有集群角色具有的所有权限。如果你想自己应用集群角色而不赋予操作器这些权限,你可以传入一个 --supervisory 布尔标志,这样生成器就不会将这些权限添加到角色中。该命令行程序位于此处

Kubectl Ownerref

很难一眼看出哪些对象是由插件自定义资源创建的。这个 kubectl 插件通过显示集群中一个资源具有 ownerrefs 的所有对象来缓解这个问题。你只需将资源的 kind 和 name 作为参数传递给程序,它就会检查集群中的对象,并给出这些对象的 kind、name 和 namespace。通过传入自定义资源的名称和 kind,这对于全面了解控制器正在协调的所有对象可能很有用。CLI 程序位于此处

插件 Operator

要充分理解插件 Operator 并更改它们的创建方式,你需要尝试创建和使用它们。夏天的一部分时间花在了为一些流行的插件构建 Operator 上,例如 Kubernetes dashboard、flannel、NodeLocalDNS 等等。请查看cluster-addons仓库以了解不同的插件 Operator。在本节中,我将重点介绍一个与其他插件 Operator 略有不同的。

通用控制器

通用控制器可以在不需要太多配置的插件之间共享。这通过减少需要运行的控制器数量,最大限度地降低了集群上的资源消耗。此外,你无需构建自己的 Operator,只需使用通用控制器即可,并且当你觉得需求增长,需要更复杂的 Operator 时,你随时可以使用 kubebuilder 脚手架代码,从通用控制器停止的地方继续。要使用通用控制器,你可以使用此工具 (generic-addon) 生成 CustomResourceDefinition(CRD)。你传入 kind、group 和你的通道目录的位置(也可以是 Git 仓库!)。该工具会为你生成 CRD、RBAC 清单和两个自定义资源。

过程如下

此工具创建

  1. 你的插件的 CRD
  2. CustomResourceDefinitions 的 RBAC 规则
  3. 应用清单的 RBAC 规则
  4. 你的插件的自定义资源
  5. 一个通用自定义资源

通用自定义资源看起来像这样

apiVersion: addons.x-k8s.io/v1alpha1
kind: Generic
metadata:
 	name: generic-sample
spec:
  objectKind:
  kind: NodeLocalDNS
  version: "v1alpha1"
  group: addons.x-k8s.io
channel: "../nodelocaldns/channels"

应用这些清单,但请确保在应用 CR 之前应用 CRD。然后,运行通用控制器,可以在你的机器上或集群内运行。

如果你对构建 Operator 感兴趣,请查看此指南

相关链接

后续工作

在 GSoC 期间,集群插件方面确实做了很多工作。但我们需要更多的人构建 Operator 并在集群中使用它们。我们需要在社区中获得更广泛的应用。为你喜欢的插件构建 Operator,并告诉我们进展如何以及是否遇到任何问题。查看此README.md以开始。

致谢

我真的要感谢我的导师Justin Santa Barbara (Google) 和Leigh Capili (Weaveworks)。我的实习经历很棒,因为他们很棒。他们为导师制设定了黄金标准。他们平易近人,随时都能解答任何困惑。我认为我最喜欢的是,他们不只是分配任务,而是我们公开讨论问题所在以及如何改进。他们确实是最好的,我希望将来还能与他们合作!此外,我要非常感谢Lubomir I. Ivanov审阅了这篇博客文章!

结论

到目前为止,我学到了很多关于 Go、Kubernetes 内部机制和 Operator 的知识。最后,我想鼓励大家积极贡献开源(尤其是 Kubernetes :)),无论你的经验水平如何。这对我来说是一次全面的体验,我爱上了这个社区。这是一个很棒的倡议,也是一个学习和结识优秀人才的好途径。特别感谢 Google 组织了这个项目。

如果你对集群插件或想进一步了解插件 Operator 感兴趣,欢迎加入我们在 Kubernetes Slack 上的#cluster-addons 频道。


Somtochi Onyekwere 是一位热爱贡献开源并探索云原生解决方案的软件工程师。