K8s 全部 Controller 都会朝着最终一致性不断 sync

声明式API对象与控制器模型相辅相成,声明式API对象定义出期望的资源状态,实际状态往往来自于 Kubernetes 集群本身,比如kubelet 通过心跳汇报的容器状态和节点状态,或者监控系统中保存的应用监控数据,或者控制器主动收集的它自己感兴趣的信息。控制器模型则通过控制循环(Control Loop)将Kubernetes内部的资源调整为声明式API对象期望的样子。因此可以认为声明式API对象和控制器模型,才是Kubernetes项目编排能力“赖以生存”的核心所在。

Reconcile 是什么?在 K8s 中 Pod 是调度的基本单元,所谓编排最终落地就是更新 Pod 的 Spec、Condition、Container Status 等数据,非基本单位的 Deployment/StatefulSet 的变更更多是数据的持久化

整体架构

K8s 控制平面大量使用事件和松散耦合的组件,Controller 监听 API Server 中的对象增删更新操作,触发后执行业务逻辑,监听事件通过 API Server 和 Controller 之间的 HTTP 长连接发送,从而驱动 Informer

IMG_0035.png

Informer:如何高效监听一个 HTTP Server

In order to retrieve an object’s information, the controller sends a request to Kubernetes API server.However, repeatedly retrieving information from the API server can become expensive. Thus, in order to get and list objects multiple times in code, Kubernetes developers end up using cachewhich has already been provided by the client-go library. Additionally, the controller doesn’t really want to send requests continuously. It only cares about events when the object has been created, modified or deleted.

Informer 间接通过工作队列 WorkQueue 与 Controller 通信

  1. Informer 可以添加自定义回调函数,但 Controller 并不直接注册业务逻辑到 Informer 回调上,一旦有资源被 CUD 就会将相应事件加入到工作队列
  2. 工作队列用于状态更新事件的有序处理并协助实现重试,所有的控制器排队进行读取,一旦某个控制器发现这个事件与自己相关,就执行相应的操作。如果操作失败,就将该事件放回队列,等下次排到自己再试一次。如果操作成功,就将该事件从队列中删除。

单个 Controller 工作原理

从DeploymentController 及 ReplicaSetController 观察到的共同点

  1. struct 中都包含获取 决策所以依赖 资源的lister,对于DeploymentController 是DeploymentLister/ReplicaSetLister/PodLister ,对于ReplicaSetController 是ReplicaSetLister和 PodLister
  2. 都包含 workqueue, workqueue 数据生产者是 Controller 注册到所依赖的 Informer 的AddFunc/updateFunc/DeleteFunc,workqueue 数据消费者是 control loop ,每次循环都是 从workqueue.Get 数据开始的
  3. 都包含 kubeClient 类型为 clientset.Interface,controller 比对新老数据 将决策 具体为“指令”使用kubeClient写入 apiserver ,然后 scheduler 和 kubelet 负责干活儿
  4. 相同的执行链条 Run => go worker => for processNextWorkItem => syncHandler
  5. processNextWorkItem 逻辑:从 queue get 一个 key 使用 syncHandler 处理,处理成功就标记成功,失败就将 key 重入 queue