在client-go中,informer是一个核心的概念,用于从Kubernetes API服务器中读取对象。它可以监视一个或多个API对象,并在对象发生变化时自动更新本地缓存。
Informer主要组成部分:
-
SharedInformerFactory
SharedInformerFactory是创建并管理一组 informer 的入口。它会根据资源类型复用同一个 SharedIndexInformer,避免同一资源重复创建多个 informer。
-
Reflector
Reflector负责和 Kubernetes API Server 交互。它会先执行一次 List 拉取当前对象集合,然后进入 Watch 循环持续监听变更。它把 List/Watch 的结果包装成 Delta,并交给后续的 FIFO 缓存。
-
DeltaFIFO
DeltaFIFO是一个带去重和顺序处理能力的队列,用来缓存 Reflector 产生的增删改事件。它会把对象的变化状态按 Delta 组织起来,供 controller 处理。
-
SharedIndexInformer
SharedIndexInformer是 informer 的核心实现。它负责把 Reflector 的结果落到本地缓存中,并把变化事件分发给注册的事件处理器。它内部通常包含一个 controller、一个 store/indexer,以及一个 sharedProcessor。
-
Indexer/Store
Indexer 是 informer 本地缓存的核心抽象,底是一个线程安全的 store。它可以按对象名和索引进行查询,供 lister 和 handler 使用。
-
ResourceEventHandler
ResourceEventHandler 是事件处理器接口,实现是
cache.ResourceEventHandlerFuncs,其中包含 AddFunc、UpdateFunc、DeleteFunc。它用于接收 informer 分发出来的对象变化事件。 -
ListerWatcher
ListerWatcher 是 informer 用来执行 List/Watch 的接口,底层通常由 clientset 对应的资源 client 实现。
在运行时,Reflector 负责从 API Server 拿到变化,DeltaFIFO 负责缓存和去重,SharedIndexInformer 再把这些变化写入 Indexer,并通过 sharedProcessor 分发给注册的事件处理器。处理链路是:Reflector -> DeltaFIFO -> SharedIndexInformer -> SharedProcessor -> ResourceEventHandler。
画了一个可能不太标准的图:
flowchart TB
subgraph k8s
APIServer["APIServer + etcd<br/>数据源"]
end
subgraph SharedIndexInformer["SharedIndexInformer"]
Reflector["Reflector<br/>ListAndWatch<br/>1.启动全量List,生成Sync Delta<br/>2.长连接Watch接收增量变更(Add/Update/Delete)"]
DeltaFIFO["DeltaFIFO<br/>存放 Delta{Type,Object}<br/>去重、顺序排序"]
ProcessLoop["processLoop 单协程循环<br/>Pop取出Delta"]
Indexer["Indexer(内存缓存)<br/>Lister的数据源"]
EventHandler["ResourceEventHandlerFuncs<br/>AddFunc / UpdateFunc / DeleteFunc<br/>【钩子回调,轻量】"]
%% Resync定时分支
ResyncTimer["Resync定时器(resyncPeriod)<br/>遍历Indexer缓存对象,生成Sync Delta送入DeltaFIFO"]
end
%% 生产控制器标准分层:EventHandler只入队,业务交给worker
subgraph Controller["自定义控制器"]
WorkQueue["WorkQueue<br/>存放资源NamespacedName Key<br/>去重、限速、重试、延迟重入"]
Worker["Worker协程池<br/>循环取出Key执行业务调谐"]
Reconcile["Reconcile 业务调谐逻辑<br/>幂等:对比期望状态和实际状态<br/>调用APIServer创建/更新/删除资源<br/>更新Status"]
end
%% 链路
APIServer -->|Watch长连接事件流| Reflector
Reflector -->|生成Delta| DeltaFIFO
ResyncTimer -->|生成Sync Delta| DeltaFIFO
DeltaFIFO -->|Pop Delta| ProcessLoop
ProcessLoop -->|"1. 更新Indexer缓存"| Indexer
ProcessLoop -->|"2. 触发EventHandler钩子"| EventHandler
%% EventHandler只做入队,不执行业务
EventHandler -->|提取资源NamespacedName Key| WorkQueue
WorkQueue -->|取出Key| Worker
Worker -->|a. 从Indexer读取最新资源对象| Indexer
Worker -->|b. 执行业务| Reconcile
Reconcile -->|调用client操作资源| APIServer
Reconcile -->|返回error/Requeue结果| WorkQueue
以如下示例中的SharedInformer为例,说明它如何将上面几个组件关联起来
示例程序
- 创建Informer对象
- 注册事件处理程序
- 启动Informer
以下面代码为例:
|
|
执行逻辑
- NewSharedInformerFactory创建工厂对象,函数中传入了clientset和defaultResync参数,clientset是访问APIServer的具体实现。resyncPeriod若为0则表示不做周期性 resync。sharedInformerFactory 的 informers 字段是一个 map,每种资源类型为 key,对应 value 是 SharedIndexInformer。
|
|
- 每种kubernetes内置资源都已经实现了资源对应的Informer,通过
sharedInformerFactory.Apps().V1().Deployments()链式调用构造出deployInformer,遵循组、版本、资源(即GVR)格式,其他k8s资源的informer创建也是一样的操作
|
|
deployInformer.Informer()用deployInformer创建deployment对应的SharedIndexInformer。这里面初始化了重要的两个对象:cache.Indexers和ListerWatcher
|
|
- 创建 DeploymentLister,它里面就一个字段 indexer,indexer 是索引器对象,可以在本地缓存中根据索引取数。如从本地缓存 indexer 中获取 default 命名空间的所有 deployment 列表:
deployments, err := deployLister.Deployments("default").List(labels.Everything())
|
|
至此,我们有了sharedIndexInformer,其中cache.Indexers与ListerWatcher两个重要字段已初始化,但目前还没有启动ListerWatcher去从APIServer拿数据,没有把这些数据包装为Delta缓存下来,没有存入到Indexer,也没有后续对数据的处理逻辑
-
给 SharedIndexInformer 添加事件处理器方法,
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{AddFunc: onAdd, UpdateFunc: onUpdate, DeleteFunc: onDelete})这里把事件对象处理函数 onAdd、onUpdate、onDelete 封装进
ResourceEventHandlerFuncs,随后由sharedProcessor中的processorListener进行分发。processorListener负责把事件缓冲和转发给用户注册的 handler;在没有事件时会阻塞,在有事件时则交给 handler 处理。若处理速度跟不上,后续事件会被放到 RingGrowingBuffer 中等待。从事件链路上看,流程是:Reflector 产生 Delta -> DeltaFIFO 暂存/去重 -> controller 从 FIFO 取出事件 -> SharedIndexInformer 处理并转发 -> sharedProcessor 的 processorListener 调用我们注册的 Add/Update/Delete 函数。
|
|
|
|
至此,我们添加了事件的处理函数,并等待事件的到来。但目前还是没有启动ListerWatcher去从APIServer拿数据,没有把这些数据包装为Delta缓存下来,没有存入到Indexer
- 启动SharedIndexInformer,
sharedInformerFactory.Start(stopper),在此过程中,首先构造了DeltaFIFO、Config和Controller三个对象,并执行controller.Run(stopCh),Run方法中构造了Reflector对象,并启动Reflector开始ListAndWatch,并执行controller.processLoop方法,它从DeltaFIFO中pop出对象,交给sharedIndexInformer.HandleDeltas()处理
|
|
Controller通过DeltaFIFO.Pop()函数弹出Deltas,并由sharedIndexInformer.HandleDeltas()函数处理,此函数的逻辑就是更新indexer,并分发Deltas到事件处理器,分发实际上就是把Deltas对象发送到processorListener的addCh通道,至此从监听事件到消费事件形成一个完整的处理流程
|
|
总结
controller是Informer机制的控制核心,它把Reflector、DeltaFIFO、ResourceEventHandlerFuncs、Indexer、Pop等组件串了起来,使其成为一个运行中的完整功能。