在client-go中,informer是一个核心的概念,用于从Kubernetes API服务器中读取对象。它可以监视一个或多个API对象,并在对象发生变化时自动更新本地缓存。

Informer主要组成部分:

  1. SharedInformerFactory

    SharedInformerFactory是创建并管理一组 informer 的入口。它会根据资源类型复用同一个 SharedIndexInformer,避免同一资源重复创建多个 informer。

  2. Reflector

    Reflector负责和 Kubernetes API Server 交互。它会先执行一次 List 拉取当前对象集合,然后进入 Watch 循环持续监听变更。它把 List/Watch 的结果包装成 Delta,并交给后续的 FIFO 缓存。

  3. DeltaFIFO

    DeltaFIFO是一个带去重和顺序处理能力的队列,用来缓存 Reflector 产生的增删改事件。它会把对象的变化状态按 Delta 组织起来,供 controller 处理。

  4. SharedIndexInformer

    SharedIndexInformer是 informer 的核心实现。它负责把 Reflector 的结果落到本地缓存中,并把变化事件分发给注册的事件处理器。它内部通常包含一个 controller、一个 store/indexer,以及一个 sharedProcessor。

  5. Indexer/Store

    Indexer 是 informer 本地缓存的核心抽象,底是一个线程安全的 store。它可以按对象名和索引进行查询,供 lister 和 handler 使用。

  6. ResourceEventHandler

    ResourceEventHandler 是事件处理器接口,实现是 cache.ResourceEventHandlerFuncs,其中包含 AddFunc、UpdateFunc、DeleteFunc。它用于接收 informer 分发出来的对象变化事件。

  7. 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为例,说明它如何将上面几个组件关联起来

示例程序

  1. 创建Informer对象
  2. 注册事件处理程序
  3. 启动Informer

以下面代码为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
func main() {
    var err error
    var config *rest.Config
    var kubeconfig *string

    if home := homedir.HomeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "[可选] kubeconfig 绝对路径")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "kubeconfig 绝对路径")
    }
    flag.Parse()

    // 初始化 *rest.Config 对象
    if config, err = rest.InClusterConfig(); err != nil {
        if config, err = clientcmd.BuildConfigFromFlags("", *kubeconfig); err != nil {
            panic(err.Error())
        }
    }

    // 创建 *ClientSet 对象
    clientSet, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    // 初始化 SharedInformerFactory,10s 做一次 resync:Reflector 定时遍历 Indexer 缓存,把全部对象以 Sync 事件重新入队(不访问 API Server)
    sharedInformerFactory := informers.NewSharedInformerFactory(clientSet, time.Second*10)

    // 每种kubernetes内置资源都实现了Informer
    // 如创建podInformer:podInformer := sharedInformerFactory.Core().V1().Pods()
    // 下面创建deploymentInformer
    deployInformer := sharedInformerFactory.Apps().V1().Deployments()

    // 实际上调用了 InformerFor(&appsv1.Deployment{}, f.defaultInformer) 构造 deployInformer 中的 SharedIndexInformer
    informer := deployInformer.Informer()

    // 创建 DeploymentLister,拥有list方法
    //type deploymentLister struct {
    //    indexer cache.Indexer
    //}
    deployLister := deployInformer.Lister()

    // 注册事件处理程序
    informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
        AddFunc:    onAdd,
        UpdateFunc: onUpdate,
        DeleteFunc: onDelete,
    })

    // 程序进程退出前,通知 informer 退出
    stopper := make(chan struct{})
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	go func() { <-quit; close(stopper) }()

    // 启动所有由 factory 创建出来的 informer
    // 这里会触发 SharedIndexInformer 的 Run,进而启动 Reflector/DeltaFIFO/controller
    sharedInformerFactory.Start(stopper)
    // 等待所有启动的 informer 的缓存同步完成
    sharedInformerFactory.WaitForCacheSync(stopper)

    // 从本地缓存中获取 default 中的所有 deployment 列表
    deployments, err := deployLister.Deployments("default").List(labels.Everything())
    if err != nil {
        panic(err)
    }
    for idx, deploy := range deployments {
        fmt.Printf("%d -> %s\n", idx+1, deploy.Name)
    }
    <-stopper
}

// 注意这些回调不能阻塞,handler 在 processorListener 的独立协程中执行,一旦阻塞,事件堆积,容易导致整个Informer事件消费卡住
func onAdd(obj interface{}) {
    deploy := obj.(*v1.Deployment)
    fmt.Println("add a deployment:", deploy.Name)
}

func onUpdate(old, new interface{}) {
    oldDeploy := old.(*v1.Deployment)
    newDeploy := new.(*v1.Deployment)
    fmt.Println("update deployment:", oldDeploy.Name, newDeploy.Name)
}

func onDelete(obj interface{}) {
    deploy := obj.(*v1.Deployment)
    fmt.Println("delete a deployment:", deploy.Name)
}

执行逻辑

  1. NewSharedInformerFactory创建工厂对象,函数中传入了clientset和defaultResync参数,clientset是访问APIServer的具体实现。resyncPeriod若为0则表示不做周期性 resync。sharedInformerFactory 的 informers 字段是一个 map,每种资源类型为 key,对应 value 是 SharedIndexInformer。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
func NewSharedInformerFactory(client kubernetes.Interface, defaultResync time.Duration) SharedInformerFactory

factory := &sharedInformerFactory{
    client:           client,
    namespace:        v1.NamespaceAll,
    defaultResync:    defaultResync, // 示例中我们传入的是10s
    informers:        make(map[reflect.Type]cache.SharedIndexInformer),
    startedInformers: make(map[reflect.Type]bool),
    customResync:     make(map[reflect.Type]time.Duration),
}
  1. 每种kubernetes内置资源都已经实现了资源对应的Informer,通过sharedInformerFactory.Apps().V1().Deployments()链式调用构造出deployInformer,遵循组、版本、资源(即GVR)格式,其他k8s资源的informer创建也是一样的操作
1
2
3
4
5
6
type deploymentInformer struct {
    factory          internalinterfaces.SharedInformerFactory
    // TweakListOptionsFunc is a function that transforms a v1.ListOptions
    tweakListOptions internalinterfaces.TweakListOptionsFunc
    namespace        string
}
  1. deployInformer.Informer() 用deployInformer创建deployment对应的SharedIndexInformer。这里面初始化了重要的两个对象:cache.Indexers和ListerWatcher
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 给InformerFor传入两个参数:
// 1. Deployment对象空结构体
// 2. Deployment的默认Informer构造函数(它在调用后返回SharedIndexInformer)
// 返回Deployment对应的SharedIndexInformer
func (f *deploymentInformer) Informer() cache.SharedIndexInformer {
    return f.factory.InformerFor(&appsv1.Deployment{}, f.defaultInformer)
}

// InformerFor的参数defaultInformer方法的实现,返回了构造出的SharedIndexInformer
func (f *deploymentInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
    // 传入了参数cache.Indexers
    // Indexers的键是索引分类名,为常量namespace,值为IndexFunc,取出对象的namespace值
    return NewFilteredDeploymentInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}

func NewFilteredDeploymentInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
    // 传入了ListerWatcher对象和Indexer参数来构造SharedIndexInformer
    return cache.NewSharedIndexInformer(
        &cache.ListWatch{
            // ListFunc/WatchFunc函数就是来list和watch APIServer资源的动作,具体实现在clientset里面
            ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
                if tweakListOptions != nil {
                    tweakListOptions(&options)
                }
                return client.AppsV1().Deployments(namespace).List(context.TODO(), options)
            },
            WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
                if tweakListOptions != nil {
                    tweakListOptions(&options)
                }
                return client.AppsV1().Deployments(namespace).Watch(context.TODO(), options)
            },
        },
        &appsv1.Deployment{},
        resyncPeriod, // NewSharedInformerFactory时传入的10s
        indexers,
    )
}

func NewSharedIndexInformer(lw ListerWatcher, exampleObject runtime.Object, defaultEventHandlerResyncPeriod time.Duration, indexers Indexers) SharedIndexInformer {
    realClock := &clock.RealClock{}
    // 最终返回的informer是这个sharedIndexInformer
    sharedIndexInformer := &sharedIndexInformer{
        processor:                       &sharedProcessor{clock: realClock},
        indexer:                         NewIndexer(DeletionHandlingMetaNamespaceKeyFunc, indexers),
        listerWatcher:                   lw,
        objectType:                      exampleObject,
        resyncCheckPeriod:               defaultEventHandlerResyncPeriod, // 10s
        defaultEventHandlerResyncPeriod: defaultEventHandlerResyncPeriod, // 10s
        cacheMutationDetector:           NewCacheMutationDetector(fmt.Sprintf("%T", exampleObject)),
        clock:                           realClock,
    }
    return sharedIndexInformer
}

// 入参:
// 1. 通用对象Object,此处即Deployment{}
// 2. deployment资源类型对应的sharedIndexInformer的构造函数
func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
    f.lock.Lock()
    defer f.lock.Unlock()

    // 反射取得对象类型为Deployment
    informerType := reflect.TypeOf(obj)
    informer, exists := f.informers[informerType]
    if exists {
        return informer
    }

    resyncPeriod, exists := f.customResync[informerType]
    if !exists {
        resyncPeriod = f.defaultResync // 默认是零值,所以赋予我们传入的10s
    }

    // 如果没有此类型的informer的话就新建一个,此例是deployment类型的informer
    informer = newFunc(f.client, resyncPeriod)
    // 填充了sharedInformerFactory的informers字段
    // informers map[reflect.Type]cache.SharedIndexInformer
    f.informers[informerType] = informer
    // 返回sharedIndexInformer实例
    return informer
}
  1. 创建 DeploymentLister,它里面就一个字段 indexer,indexer 是索引器对象,可以在本地缓存中根据索引取数。如从本地缓存 indexer 中获取 default 命名空间的所有 deployment 列表:deployments, err := deployLister.Deployments("default").List(labels.Everything())
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func (f *deploymentInformer) Lister() v1.DeploymentLister {
    // 传入一个参数为cache.Indexer,即前面func (f *deploymentInformer) defaultInformer方法中
    // 初始化的cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
    return v1.NewDeploymentLister(f.Informer().GetIndexer())
}

func (s *sharedIndexInformer) GetIndexer() Indexer {
    return s.indexer
}

func NewDeploymentLister(indexer cache.Indexer) DeploymentLister {
    return &deploymentLister{indexer: indexer}
}

// deploymentLister implements the DeploymentLister interface.
type deploymentLister struct {
    indexer cache.Indexer
}

至此,我们有了sharedIndexInformer,其中cache.Indexers与ListerWatcher两个重要字段已初始化,但目前还没有启动ListerWatcher去从APIServer拿数据,没有把这些数据包装为Delta缓存下来,没有存入到Indexer,也没有后续对数据的处理逻辑

  1. 给 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 函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

// 添加默认的ResyncPeriod事件处理器
func (s *sharedIndexInformer) AddEventHandler(handler ResourceEventHandler) {
    s.AddEventHandlerWithResyncPeriod(handler, s.defaultEventHandlerResyncPeriod)
}

type ResourceEventHandlerFuncs struct {
    AddFunc    func(obj interface{})
    UpdateFunc func(oldObj, newObj interface{})
    DeleteFunc func(obj interface{})
}

func (s *sharedIndexInformer) AddEventHandlerWithResyncPeriod(handler ResourceEventHandler, resyncPeriod time.Duration) {
    s.startedLock.Lock()
    defer s.startedLock.Unlock()

    if s.stopped {
        klog.V(2).Infof("Handler %v was not added to shared informer because it has stopped already", handler)
        return
    }

    // 这里示例中是传入的10s
    if resyncPeriod > 0 {
        // 同步周期不能小于1s
        // const minimumResyncPeriod = 1 * time.Second
        if resyncPeriod < minimumResyncPeriod {
            klog.Warningf("resyncPeriod %v is too small. Changing it to the minimum allowed value of %v", resyncPeriod, minimumResyncPeriod)
            resyncPeriod = minimumResyncPeriod
        }

        // 若通过AddEventHandler添加的任何handler的默认resync周期 小于 Reflector定期检查是否需要resync的同步周期
        if resyncPeriod < s.resyncCheckPeriod {
            // 已启动,那么同步周期是resyncCheckPeriod
            if s.started {
                klog.Warningf("resyncPeriod %v is smaller than resyncCheckPeriod %v and the informer has already started. Changing it to %v", resyncPeriod, s.resyncCheckPeriod, s.resyncCheckPeriod)
                resyncPeriod = s.resyncCheckPeriod
            } else {
                // 如果没有启动,则更新resyncCheckPeriod为resyncPeriod,并调整所有监听器的同步周期
                s.resyncCheckPeriod = resyncPeriod
                s.processor.resyncCheckPeriodChanged(resyncPeriod)
            }
        }
    }

    // 用ResourceEventHandler创建processorListener,里面有ringbuffer和两个通道
    listener := newProcessListener(handler, resyncPeriod, determineResyncPeriod(resyncPeriod, s.resyncCheckPeriod), s.clock.Now(), initialBufferSize)

    // 如果sharedIndexInformer未启动,则把processorListener添加到sharedProcessor里面去。addListener方法在下文有说明
    if !s.started {
        s.processor.addListener(listener)
        return
    }

    // 下面是listener已启动的情况下再添加processorListener
    // 为了安全的加入,按照以下顺序:
    // 1. stop sending add/update/delete notifications
    // 2. do a list against the store
    // 3. send synthetic "Add" events to the new handler
    // 4. unblock
    s.blockDeltas.Lock()
    defer s.blockDeltas.Unlock()

    s.processor.addListener(listener)
    for _, item := range s.indexer.List() {
        listener.add(addNotification{newObj: item})
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// 添加processorListener到sharedProcessor里面去,并开启两个协程运行processorListener.run/pop
func (p *sharedProcessor) addListener(listener *processorListener) {
    p.listenersLock.Lock()
    defer p.listenersLock.Unlock()

    p.addListenerLocked(listener)
    // 若已启动,则新添加的listener开启俩协程分别执行run和pop方法
    if p.listenersStarted {
        p.wg.Start(listener.run)
        p.wg.Start(listener.pop)
    }
}

func (p *sharedProcessor) addListenerLocked(listener *processorListener) {
    p.listeners = append(p.listeners, listener)
    p.syncingListeners = append(p.syncingListeners, listener)
}

func (p *processorListener) run() {
    // 开启一个协程周期性调用一个匿名函数,从nextCh里面接收事件并根据事件类型交给对应的handler处理
    stopCh := make(chan struct{})
    wait.Until(func() {
        for next := range p.nextCh {
            switch notification := next.(type) {
            case updateNotification:
                p.handler.OnUpdate(notification.oldObj, notification.newObj)
            case addNotification:
                p.handler.OnAdd(notification.newObj)
            case deleteNotification:
                p.handler.OnDelete(notification.oldObj)
            default:
                utilruntime.HandleError(fmt.Errorf("unrecognized notification: %T", next))
            }
        }
        // the only way to get here is if the p.nextCh is empty and closed
        close(stopCh)
    }, 1*time.Second, stopCh)
}

// 
func (p *processorListener) pop() {
    defer utilruntime.HandleCrash()
    defer close(p.nextCh) // Tell .run() to stop

    var nextCh chan <- interface{}
    var notification interface{}
    // 死循环不停的接收notification并发送给handler
    for {
        select {
        // 未初始化的通道进行读写会阻塞的
        // nextCh通道有数据了,这个case段会立马执行,run 的 for range 持续阻塞读取 nextCh,消费跟不上时事件才暂存进环形缓冲区
        // 如果环状buffer里面没数据,则下次有notification了意味着可以直接放到nextCh
        // 如果环状buffer里面有数据,那么后来的notification应该放到buffer里面去
        // 假设第一个notification由run正在处理中的1s内,这时又来了两个notification
        // 第一个notification由于未被run消费,使得nextCh阻塞,第二个notification就会被存入到环状buffer
        case nextCh <- notification:
            // Notification dispatched
            var ok bool
            // 环形缓冲区顺序读取
            notification, ok = p.pendingNotifications.ReadOne()
            if !ok { // Nothing to pop
                nextCh = nil // Disable nextCh通道
            }
        // addCh通道有数据了的情况
        case notificationToAdd, ok := <- p.addCh:
            if !ok {
                // 通道已关闭则直接退出
                return
            }
            // 如果notification为空,说明还没有发送事件给handler
            if notification == nil { // No notification to pop (and pendingNotifications is empty)
                // 把从addCh获取到的notification写入到p.nextCh通道,run函数里面会消费此通道
                notification = notificationToAdd
                nextCh = p.nextCh
            } else { // There is already a notification waiting to be dispatched
                // 到这里说明还有未被消费的notification,先存入到buffer
                p.pendingNotifications.WriteOne(notificationToAdd)
            }
        }
    }
}

至此,我们添加了事件的处理函数,并等待事件的到来。但目前还是没有启动ListerWatcher去从APIServer拿数据,没有把这些数据包装为Delta缓存下来,没有存入到Indexer

  1. 启动SharedIndexInformer, sharedInformerFactory.Start(stopper),在此过程中,首先构造了DeltaFIFO、Config和Controller三个对象,并执行controller.Run(stopCh),Run方法中构造了Reflector对象,并启动Reflector开始ListAndWatch,并执行controller.processLoop方法,它从DeltaFIFO中pop出对象,交给sharedIndexInformer.HandleDeltas()处理
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Start initializes all requested informers.
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
    f.lock.Lock()
    defer f.lock.Unlock()

    for informerType, informer := range f.informers {
        if !f.startedInformers[informerType] {
            go informer.Run(stopCh)
            f.startedInformers[informerType] = true
        }
    }
}

func (s *sharedIndexInformer) Run(stopCh <-chan struct{}) {
    defer utilruntime.HandleCrash()

    // 构造一个DeltaFIFO对象
    fifo := NewDeltaFIFOWithOptions(DeltaFIFOOptions{
        KnownObjects:          s.indexer,
        EmitDeltaTypeReplaced: true,
    })

    // 构造Config对象,包含需要的所有配置
    cfg := &Config{
        Queue:            fifo, // DeltaFIFO
        ListerWatcher:    s.listerWatcher, // 在创建资源对应的informer时定义的,每种资源都有其对应的ListerWatcher
        ObjectType:       s.objectType, // 关注的对象类型
        FullResyncPeriod: s.resyncCheckPeriod,
        RetryOnError:     false,
        ShouldResync:     s.processor.shouldResync,

        Process:           s.HandleDeltas, // sharedIndexInformer的方法
        WatchErrorHandler: s.watchErrorHandler,
    }

    func() {
        s.startedLock.Lock()
        defer s.startedLock.Unlock()

        // 构造一个controller对象,
        s.controller = New(cfg)
        s.controller.(*controller).clock = s.clock
        s.started = true
    }()

    // Separate stop channel because Processor should be stopped strictly after controller
    processorStopCh := make(chan struct{})
    var wg wait.Group
    defer wg.Wait()              // Wait for Processor to stop
    defer close(processorStopCh) // Tell Processor to stop
    wg.StartWithChannel(processorStopCh, s.cacheMutationDetector.Run)
    wg.StartWithChannel(processorStopCh, s.processor.run) // 启动listener

    defer func() {
        s.startedLock.Lock()
        defer s.startedLock.Unlock()
        s.stopped = true // Don't want any new listeners
    }()
    s.controller.Run(stopCh)
}

func (c *controller) Run(stopCh <-chan struct{}) {
    defer utilruntime.HandleCrash()
    go func() {
        <-stopCh // 阻塞以等待有情况关闭队列
        c.config.Queue.Close()
    }()
    r := NewReflector(
        c.config.ListerWatcher,
        c.config.ObjectType,
        c.config.Queue,
        c.config.FullResyncPeriod,
    )
    r.ShouldResync = c.config.ShouldResync
    r.WatchListPageSize = c.config.WatchListPageSize
    r.clock = c.clock
    if c.config.WatchErrorHandler != nil {
        r.watchErrorHandler = c.config.WatchErrorHandler
    }

    c.reflectorMutex.Lock()
    c.reflector = r
    c.reflectorMutex.Unlock()

    var wg wait.Group

    // Reflector开始运行ListAndWatch
    wg.StartWithChannel(stopCh, r.Run)

    // 也是周期性地执行,需要从DeltaFIFO中弹出对象供后续处理
    wait.Until(c.processLoop, time.Second, stopCh)
    wg.Wait()
}

// 调用ListAndWatch获取对象和对应的事件类型
func (r *Reflector) Run(stopCh <-chan struct{}) {
    klog.V(3).Infof("Starting reflector %s (%s) from %s", r.expectedTypeName, r.resyncPeriod, r.name)
    wait.BackoffUntil(func() {
        if err := r.ListAndWatch(stopCh); err != nil {
            r.watchErrorHandler(r, err)
        }
    }, r.backoffManager, true, stopCh)
    klog.V(3).Infof("Stopping reflector %s (%s) from %s", r.expectedTypeName, r.resyncPeriod, r.name)
}

// 周期性的执行
func (c *controller) processLoop() {
    for {
        // 从队列中弹出一个对象然后处理它
        // 此处的c.config.Process就是func (s *sharedIndexInformer) HandleDeltas
        obj, err := c.config.Queue.Pop(PopProcessFunc(c.config.Process))
        if err != nil {
            if err == ErrFIFOClosed {
                return
            }
            if c.config.RetryOnError {
                // 重新入队
                c.config.Queue.AddIfNotPresent(obj)
            }
        }
    }
}

Controller通过DeltaFIFO.Pop()函数弹出Deltas,并由sharedIndexInformer.HandleDeltas()函数处理,此函数的逻辑就是更新indexer,并分发Deltas到事件处理器,分发实际上就是把Deltas对象发送到processorListener的addCh通道,至此从监听事件到消费事件形成一个完整的处理流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
func (s *sharedIndexInformer) HandleDeltas(obj interface{}) error {
    s.blockDeltas.Lock()
    defer s.blockDeltas.Unlock()

    // from oldest to newest
    for _, d := range obj.(Deltas) {
        switch d.Type { 
        case Sync, Replaced, Added, Updated:
            s.cacheMutationDetector.AddObject(d.Object)
            if old, exists, err := s.indexer.Get(d.Object); err == nil && exists {
                if err := s.indexer.Update(d.Object); err != nil {
                    return err
                }

                isSync := false
                switch {
                case d.Type == Sync:
                    // Sync events are only propagated to listeners that requested resync
                    isSync = true
                case d.Type == Replaced:
                    if accessor, err := meta.Accessor(d.Object); err == nil {
                        if oldAccessor, err := meta.Accessor(old); err == nil {
                            // Replaced events that didn't change resourceVersion are treated as resync events
                            // and only propagated to listeners that requested resync
                            isSync = accessor.GetResourceVersion() == oldAccessor.GetResourceVersion()
                        }
                    }
                }
                s.processor.distribute(updateNotification{oldObj: old, newObj: d.Object}, isSync)
            } else {
                if err := s.indexer.Add(d.Object); err != nil {
                    return err
                }
                s.processor.distribute(addNotification{newObj: d.Object}, false)
            }
        case Deleted:
            if err := s.indexer.Delete(d.Object); err != nil {
                return err
            }
            s.processor.distribute(deleteNotification{oldObj: d.Object}, false)
        }
    }
    return nil
}

// 这儿就把从DeltaFIFO中pop出来的对象,给到processorListener的addCh通道中,中间可以经过ringbuffer放入到nextCh通道,由事件处理器消化它
func (p *sharedProcessor) distribute(obj interface{}, sync bool) {
    p.listenersLock.RLock()
    defer p.listenersLock.RUnlock()

    if sync {
        for _, listener := range p.syncingListeners {
            listener.add(obj)
        }
    } else {
        for _, listener := range p.listeners {
            listener.add(obj)
        }
    }
}

func (p *processorListener) add(notification interface{}) {
    p.addCh <- notification
}

总结

controller是Informer机制的控制核心,它把Reflector、DeltaFIFO、ResourceEventHandlerFuncs、Indexer、Pop等组件串了起来,使其成为一个运行中的完整功能。