一般来说,智能系统和自动系统通常都会通过一个“操作系统”不断修正系统的工作状态。在Kubernetes集群中,每个Controller都是这样的一个“操作系统”,它们通过API Server 提供的(List-Watch)接口实时监控集群中特定资源的状态变化。

当发生各种故障导致某资源对象的状态变化时,Controller会尝试将其状态调整为期望的状态。比如当某个Node意外宕机时,Node Controller会及时发现此故障并执行自动化修复流程,确保集群此终处于预期的工作状态下。

Controller Manager是Kubernetes中各种操作系统的管理者,是集群内部的管理控制中心,也是Kubernetes自动化功能的核心。

Controller Manager内部包含Replication Controller、Node Controller、ResourceQuota Controller、Namespace Controller、ServiceAccount Controller、Token Controller、Service Controller、Endpoint Controller、Deployment Controller、Route Controller、Volume Controller等各种资源对象的控制器,每种Controller都负责一种特定资源的控制流程,而Controller Manager正是这些Controller的核心管理者。

在Kubernetes集群中与Controller Manager并重的另一个组件是Kubernetes Scheduler,作用是将待调度的Pod(包括通过API Server新创建的Pod及RC为补足副本而创建的Pod等)通过一些复杂的调度流程计算出最佳目标节点,将Pod绑定到目标节点上。

副本调度控制器

在Kubernetes中存在两个功能相似的副本控制器:Replication Controller及Deployment Controller。

将资源对象Replication Controller简写为RC,Replication Controller指副本控制器。

Replication Controller的核心作用是确保集群中某个RC关联的Pod副本数量在任何时候都保持预设值。如果发现Pod的副本数量超过预设值,则Replication Controller会销毁一些Pod副本;反之,Replication Controller会自动创建新的Pod副本,直到符合条件的Pod副本数量达到预设值。需要注意的是,只有当Pod的重启策略是Always时(RestartPolicy=Always),Replication Controller才会管理该Pod的操作(例如创建、销毁、重启等)。

随着Kubernetes的不断升级,旧的RC已不能满足需求,所以有了Deployment。Deployment可被视为RC 替代者,RC及对应的Replication Controller已不再升级、维护,Deployment及对应的Deployment Controller则不断更新、升级新特性。Deployment Controller在工作过程中实际上是在控制两类相关的资源对象:Deployment及ReplicaSet。在创建Deployment资源对象之后,Deployment Controller也默默创建了对应的ReplicaSet,Deployment的滚动升级也是Deployment Controller通过自动创建新的ReplicaSet来支持的。

总结Deployment Controller的作用:

  1. 确保在当前集群中有且仅有N个Pod实例,N是在RC中定义的Pod副本数量。
  2. 通过调整 spec.replicas 属性的值来实现系统扩容或缩容。
  3. 通过改变Pod模板(主要是镜像版本)来实现系统的滚动升级。

总结Deployment Controller的典型使用场景,如下所述。

  1. 重新调度(Rescheduling)。如前面所述,不管想运行1个副本还是1000个副本,副本控制器都能确保指定数量的副本存在于集群中,即使发生节点故障或Pod副本被终止运行等意外状况。
  2. 弹性伸缩(Scaling)。手动或者通过自动扩容代理修改副本控制器 spec.replicas 属性的值,非常容易实现增加或减少副本的数量。
  3. 滚动更新(Rolling Updates)。副本控制器被设计成通过逐个替换Pod来辅助服务的滚动更新。

Node Controller

kubelet进程在启动时通过API Server注册自身节点信息,并定时向API Server汇报状态信息,API Server在接收到这些信息后,会将这些信息更新到etcd中。在etcd中存储的节点信息包括节点健康状况、节点资源、节点名称、节点地址信息、操作系统版本、Docker版本、kubelet版本等。节点健康状况包括就绪(True)、未就绪(False)、未知(Unknow)三种。

Node Controller通过API Server实时获取Node的相关信息,实现管理和监控集群中各个Node的相关控制功能,Node Controller的核心工作流程如下所示:
kubernetes_node_controller

对流程中关键点的解释如下。

  1. Controller Manager在启动时如果设置了–cluster-cidr参数,那么为每个没有设置Spec.PodCIDR的Node都生成一个CIDR地址,并用该CIDR地址设置节点的Spec.PodCIDR属性,这样做的目的是防止不同节点的CIDR地址发生冲突。
  2. 逐个读取Node信息,多次尝试修改nodeStatusMap中的节点状态信息,将该节点信息和Node Controller的nodeStatusMap中保存的节点信息做比较:
  • 如果判断出没有收到kubelet发送的节点信息、第1次收到节点kubelet发送的节点信息,或在该处理过程中节点状态变成非“健康”状态,则在nodeStatusMap中保存该节点的状态信息,并用Node Controller所在节点的系统时间作为探测时间和节点状态变化时间。
  • 如果判断出在指定时间内收到新的节点信息,且节点状态发生变化,则在nodeStatusMap中保存该节点的状态信息,并用Node Controller所在节点的系统时间作为探测时间和节点状态变化时间。
  • 如果判断出在指定时间内收到新的节点信息,但节点状态没发生变化,则在nodeStatusMap中保存该节点的状态信息,并用Node Controller所在节点的系统时间作为探测时间,将上次节点信息中的节点状态变化时间作为该节点的状态变化时间。
  • 如果判断出在某段时间(gracePeriod)内没有收到节点状态信息,则设置节点状态为“未知”,并且通过API Server保存节点状态。
  1. 逐个读取节点信息,如果节点状态变为非“就绪”状态,则将节点加入待删除队列,否则将节点从该队列中删除。如果节点状态为非“就绪”状态,且系统指定了Cloud Provider,则Node Controller调用Cloud Provider查看节点,若发现节点故障,则删除etcd中的节点信息,并删除和该节点相关的Pod等资源的信息。

ResourceQuota Controller

作为完备的企业级的容器集群管理平台,Kubernetes也提供了ResourceQuota Controller(资源配额管理)这一高级功能,资源配额管理确保指定的资源对象在任何时候都不会超量占用系统物理资源,避免由于某些业务进程在设计或者实现上的缺陷导致整个系统运行紊乱甚至意外宕机,对整个集群的平稳运行和稳定性都有非常重要的作用。

目前Kubernetes支持如下三个层次的资源配额管理。

  1. 容器级别,可以对CPU和Memory进行限制。
  2. Pod级别,可以对一个Pod内所有容器的可用资源进行限制。
  3. Namespace级别,为Namespace(多租户)级别的资源限制,包括:Pod数量、Replication Controller数量、Service数量、ResourceQuota数量、Secret数量和可持有的PV数量。

Kubernetes的配额管理是通过Admission Control(准入控制)来控制的,Admission Control当前提供了两种方式的配额约束,分别是LimitRanger与ResourceQuota。其中LimitRanger作用于Pod和Container;ResourceQuota则作用于Namespace,限定一个Namespace里的各类资源的使用总额。

如图所示,如果在Pod定义中同时声明了LimitRanger,则用户通过API Server请求创建或修改资源时,Admission Control会计算当前配额的使用情况,如果不符合配额约束,则创建对象失败。

对于定义了ResourceQuota的Namespace,ResourceQuota Controller组件会定期统计和生成该Namespace下各类对象的资源使用总量,统计结果包括Pod、Service、RC、Secret和Persistent Volume等对象实例个数,以及该Namespace下所有Controller实例的资源使用量(目前包括CPU和内存),然后将这些统计结果写入etcd的resourceQuotaStatusStorage目录(resourceQuotas/status)下。写入resourceQuotaStatusStorage的内容包含Resource名称、配额值(ResourceQuota对象中spec.hard域下包含的资源的值)、当前使用的值(ResourceQuota Controller统计的值)。

随后这些统计信息被Admission Control使用,以确保相关Namespace下的资源配额总量不会超过ResourceQuota中的限定值。
kubernetes_ResourceQuota_Controller

Namespace Controller

用户通过API Server可以创建新的Namespace并将其保存在etcd中,Namespace Controller定时通过API Server读取这些Namespace的信息。如果Namespace被API识别为优雅删除(通过设置删除期限实现,即设置DeletionTimestamp)属性,则将该Namespace的状态设置成 Terminating并保存etcd中。同时,Namespace Controller删除该Namespace下的ServiceAccount、RC、Pod、Secret、Persistent Volume、ListRange、ResourceQuota和Event等资源对象。

在Namespace的状态被设置成Terminating后,由Admission Controller 的 NamespaceLifecycle插件来阻止为该Namespace创建新的资源。同时,在Namespace Controller删除该Namespace中的所有资源对象后,NamespaceController会对该Namespace执行finalize操作,删除Namespace的spec.finalizers域中的信息。

如果Namespace Controller观察到Namespace设置了删除期限,同时Namespace的spec.finalizers域值是空的,那么Namespace Controller将通过API Server删除该Namespace资源。

Service Controller与Endpoints Controller

Service、Endpoints与Pod的关系如图所示:
kubernetes_service_Controller&Endpoints_Controller

Endpoints表示一个Service对应的所有Pod副本的访问地址,Endpoints Controller就是负责生成和维护所有Endpoints对象的控制器。

Endpoints Controller负责监听Service和对应的Pod副本的变化:

  • 如果监测到Service被删除,则删除和该Service同名的Endpoints对象。
  • 如果监测到新的Service被创建或者修改,则根据该Service信息获得相关的Pod列表,然后创建或者更新Service对应的Endpoints对象。
  • 如果监测到Pod的事件,则更新它所对应的Service的Endpoints对象(增加、删除或者修改对应的Endpoint条目)。

那么,Endpoints对象是在哪里被使用的呢?答案是每个Node上的kube-proxy进程,kube-proxy进程获取每个Service的Endpoints,实现了Service的负载均衡功能。

Service Controller的作用,它其实是属于Kubernetes集群与外部的云平台之间的一个接口控制器。Service Controller监听Service的变化,如果该Service是一个LoadBalancer类型的Service(externalLoadBalancers=true),则Service Controller确保在外部的云平台上该Service对应的LoadBalancer实例被相应地创建、删除及更新路由转发表(根据Endpoints的条目)。

参考:《Kubernetes权威指南(第五版)》