在机器人和自动化领域,控制回路(control loop)是一个非终止循环,用于调节系统的状态。
这里是一个控制回路的示例:房间里的恒温器。
当你设定温度时,你是在告诉恒温器你的期望状态(desired state)。实际的室温就是当前状态(current state)。恒温器通过开启或关闭设备,使当前状态尽可能接近期望状态。
在 Kubernetes 中,控制器是控制回路,它们监视集群的状态,然后在必要时做出更改或请求更改。每个控制器都试图将当前的集群状态向期望状态推进。控制器会追踪至少一种 Kubernetes 资源类型。这些对象具有一个 spec 字段,用于表示期望状态。该资源的控制器负责使当前状态尽可能接近该期望状态。
控制器可能会自行执行操作;但在 Kubernetes 中,更常见的情况是控制器向 API 服务器发送消息,这些消息会产生有用的副作用。你将在下文中看到相关的示例。
Job 控制器是 Kubernetes 内置控制器的一个示例。内置控制器通过与集群 API 服务器交互来管理状态。
Job 是一种 Kubernetes 资源,用于运行一个 Pod,或者可能是多个 Pod,以执行某项任务,然后停止。
(一旦被调度,Pod 对象就会成为 kubelet 所追求的期望状态的一部分)。
当 Job 控制器看到一个新任务时,它会确保集群中某处的一组节点上的 kubelet 正在运行适当数量的 Pod 来完成工作。Job 控制器本身并不运行任何 Pod 或容器。相反,Job 控制器会告诉 API 服务器创建或删除 Pod。控制平面中的其他组件会根据这些新信息采取行动(即有新的 Pod 需要调度和运行),最终工作得以完成。
在你创建一个新 Job 后,期望状态就是该 Job 完成。Job 控制器会使该 Job 的当前状态更接近你的期望状态:创建能够执行 Job 所需工作的 Pod,从而使 Job 更接近完成。
控制器还会更新配置它们的那些对象。例如:一旦 Job 的工作完成,Job 控制器会更新该 Job 对象,将其标记为 Finished。
(这有点像某些恒温器会关掉指示灯,以表明你的房间现在已经达到了你设定的温度)。
与 Job 不同,一些控制器需要对集群之外的事物进行更改。
例如,如果你使用控制回路来确保集群中有足够多的 节点,那么该控制器就需要集群之外的某种机制,以便在必要时设置新的节点。
与外部状态交互的控制器会从 API 服务器获取期望状态,然后直接与外部系统通信,使当前状态更接近期望状态。
(实际上确实存在一个控制器可以水平扩展集群中的节点。)
这里重点在于,控制器做出某些更改以实现你的期望状态,然后将当前状态报告回集群的 API 服务器。其他控制回路可以观察这些报告的数据并采取各自的行动。
在恒温器的例子中,如果房间非常冷,另一个控制器可能会同时开启防冻加热器。在 Kubernetes 集群中,控制平面通过扩展 Kubernetes 来实现这一点,从而间接地与 IP 地址管理工具、存储服务、云提供商 API 以及其他服务协同工作。
Kubernetes 采用了云原生视角来看待系统,并且能够处理持续的变化。
随着工作的进行和控制回路自动修复故障,你的集群可能会随时发生变化。这意味着你的集群可能永远无法达到一个完全稳定的状态。
只要集群的控制器在运行并能做出有用的改变,整体状态是否稳定并不重要。
作为其设计原则,Kubernetes 使用了大量的控制器,每个控制器管理集群状态的特定方面。最常见的情况是,特定的控制回路(控制器)使用一种资源作为其期望状态,并管理另一种资源来实现该期望状态。例如,Job 控制器跟踪 Job 对象(以发现新工作)和 Pod 对象(以运行 Job,并在工作完成后查看进度)。在这种情况下,由其他组件创建 Job,而 Job 控制器则负责创建 Pod。
拥有简单的控制器比拥有一个相互关联的单体控制回路集合更有用。控制器可能会失败,因此 Kubernetes 的设计允许这种情况发生。
可以有多个控制器创建或更新同一种对象。在底层,Kubernetes 控制器确保它们只关注与其所关联的资源相关的资源。
例如,你可以同时拥有 Deployment 和 Job;它们都会创建 Pod。Job 控制器不会删除 Deployment 创建的 Pod,因为控制器可以使用相关信息(标签)来区分这些 Pod。
Kubernetes 自带了一套运行在 kube-controller-manager 内的内置控制器。这些内置控制器提供了重要的核心行为。
Deployment 控制器和 Job 控制器是作为 Kubernetes 本身一部分提供的控制器示例(“内置”控制器)。Kubernetes 允许你运行一个具有弹性的控制平面,这样如果任何内置控制器发生故障,控制平面的其他部分就会接管该工作。
你可以找到在控制平面之外运行的控制器来扩展 Kubernetes。或者,如果你愿意,也可以自己编写一个新的控制器。你可以将自己的控制器作为一组 Pod 运行,也可以在 Kubernetes 外部运行。哪种方式最适合,取决于该特定控制器的功能。