合作机构:阿里云 / 腾讯云 / 亚马逊云 / DreamHost / NameSilo / INWX / GODADDY / 百度统计
我们知道 k8s 里重要概念之一就是 声明式 API,比如 kubectl apply 就是声明式 API的实现。
效果就是资源对象的运行状态要与我们声明的一致。比如kubectl apply 一个 deployment 的 yml,他要求的状态就是: 该 deployment 成功运行。
那么问题来了,k8s 是如何 "监视" 资源对象,以确保其始终保持我们声明的状态的呢?答案就是 -- Controller。除了组件中的 kube-controller-manager,我们可以编写自己的 Controller,也叫自定义控制器(为了方便下文统称为自定义 Controller)。
接下来,我们就来剖析一下 Controller 背后的"秘密"
我们先看看社区给出的 Controller 的架构图:
其中有几个主要对象(结构体) -- Reflector、Informer、Indexer。Reflector 和 Indexer 我们会在之后的文章中会一一讲解 。
本文主要是讲解一下 Informer。
从图中可以看到主要有9个步骤,这里我将9个步骤合并成3个大步骤:
(画的有点丑-__- !!!)
大步骤1: Reflector 将资源对象的事件添加进 Delta FIFO queue 中。
这里先提前介绍一下 Delta FIFO queue。所谓 Delta 就是变化的意思,什么的变化呢?就是资源对象的变化。
即 资源对象的变化都会被添加到 Delta FIFO queue 中!这样是不是就很好理解了。
大步骤2: Informer 将 Delta FIFO queue 中的对象数据 添加到本地 cache 中。
补充一下这个本地 cache 缓存的就是监听资源对象的最新版。就是缓存的当前集群里面的资源信息。
大步骤3: 使用 workqueue 处理业务逻辑。
咱们结合社区给的编写的 自定义Controller用例 来做源码分析。这里使用的版本是 client-go v0.20.5。
用例中用到的是普通 informer,介绍的也是普通 informer。但很更多用的是sharedInformer,比如 manager、SharedInformerFactory 都是对普通 informer 的一个再封装,本质的东西是一样的。感兴趣的话,后面再出介绍 sharedInformer、manager 的文章。
我们看到架构图中间有一个分界线,将流程分割为上下两半, 而上半部主要包括大步骤 1、2。
这两个步骤其实是连在一起的,其入口代码就是这一行 : informer.Run(),可以先不管这。
我们先看用例中Informer的初始化入口代码。
NewIndexerInformer 的代码如下:
再真正的Informer初始化,就是 newInformer :
注意第381行 就是 Delta FIFO 的初始化,架构图中的 Delta FIFO queue 就是在这实例化的。
我们发现 newInformer 返回的 是一个 low-level Controller 接口。这个接口抽象的很简单,就三个方法:
Run(stopCh <-chan struct{}):
运行逻辑。
TOP