上图是整个 client-go 的完整架构图,或者说是我们要去实现一个自定义的控制器的一个整体流程,其中黄色图标是开发者需要自行开发的部分,而其它的部分是 client-go 已经提供的,直接使用即可。 由于 client-go 实现非常复杂,我们这里先对上图中最核心的部分 Informer 进行说明。在 Informer 的架构中包含如下几个核心的组件:
Reflector(反射器)
Reflector 用于监控(List、Watch)指定的 Kubernetes 特定的资源,当监控的资源发生变化时,触发相应的变更事件,例如 Add 事件、Update 事件、Delete 事件,并将其资源对象存放到本地缓存 DeltaFIFO 中。
DeltaFIFO
DeltaFIFO 是一个生产者-消费者的队列,生产者是 Reflector,消费者是 Pop 函数,FIFO 是一个先进先出的队列,而 Delta 是一个资源对象存储,它可以保存资源对象的操作类型,也就是说 DeltaFIFO
队列里面主要的事件类型的话例如 Add 操作类型、Update 操作类型、Delete 操作类型、Sync 操作类型等。
Indexer
Indexer 是 client-go 用来存储资源对象并自带索引功能的本地存储,Informer(sharedIndexInformer) 从 DeltaFIFO 中将消费出来的资源对象存储至 Indexer。Indexer 与 Etcd 集群中的数据保持完全一致。这样我们就可以很方便地从本地存储中读取相应的资源对象数据,而无须每次从远程 APIServer 中读取,以减轻服务器的压力。
这个地方的 Pop Object 就是把这个资源对象弹出来之后还会有一些事件的分发
总结:
首先当 informer 启动的时候会将对应的资源对象全量获取下来,获取下来会放到 delta Fifo queue
的本地存储队列
然后除了 List 以外还有一个 watch 的操作,用于不断监听我们指定的资源对象,比如隔一段时间新增一个 deployment,那么 informer 就会拿到新增 deployment 的这么一个事件,当然增删改查这些操作都能够被监听
这里通过 list、watch 就能保证我们在 APIServer 拿到的数和 delta fifo
中存储的数据一致性,然后我们后续的操作其实就是对 delta fifo
存储的数据进行操作不用再连接 ApiServer 进行操作,当然最终 delta fifo
中的数据会给他存储在本地的 indexer 中,这个 indexer 是可以用来进行索引的这样一个存储
流程解析:
这里理论知识太多,直接去查看源码显得有一定困难,我们可以用一个实际的示例来进行说明,比如现在我们删除一个 Pod,一个 Informers 的执行流程是怎样的:
- 首先初始化 Informer,Reflector 通过 List 接口获取所有的 Pod 对象
- Reflector 拿到所有 Pod 后,将全部 Pod 放到 Store(本地缓存)中
- 如果有人调用 Lister 的 List/Get 方法获取 Pod,那么 Lister 直接从 Store 中去拿数据
- Informer 初始化完成后,Reflector 开始 Watch Pod 相关的事件
- 此时如果我们删除 Pod1,那么 Reflector 会监听到这个事件,然后将这个事件发送到 DeltaFIFO 中
- DeltaFIFO 首先先将这个事件存储在一个队列中,然后去操作 Store 中的数据,删除其中的 Pod1
- DeltaFIFO 然后 Pop 这个事件到事件处理器(资源事件处理器)中进行处理
- LocalStore 会周期性地把所有的 Pod 信息重新放回 DeltaFIFO 中去