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

Informer主要组成部分:

  1. sharedIndexInformer

    sharedIndexInformer是informer的核心组件。它负责从API服务器获取对象并更新本地缓存。在更新缓存后,它会触发事件处理器,以便通知其他组件对象已经更新。

  2. informerSyncHandler

    informerSyncHandler是sharedIndexInformer的事件处理程序,它将缓存中的对象与API服务器中的对象进行比较,并更新缓存。当处理完所有的更新操作后,informerSyncHandler会将更新后的对象发送到事件队列。

  3. informerEventHandler

    informerEventHandler是事件处理程序的接口,用于接收事件并执行特定的操作。当sharedIndexInformer接收到更新事件时,它将调用informerEventHandler来处理事件

  4. indexer

    indexer是informer的本地缓存,用于存储从API服务器获取的对象。indexer使用map数据结构存储对象,其中键是对象的名称,值是对象本身。此外,indexer还使用索引数据结构(例如Set、List)来优化查找和筛选操作。每个indexer都关联一个ObjectStore,ObjectStore是一个更高级别的抽象,用于管理一组API对象

  5. watcher

    watcher是informer的事件源,用于从API服务器中获取对象并将它们发送到事件队列中。watcher实现了Kubernetes API服务器上的watch机制,它会定期向API服务器发送请求,以获取当前对象的状态。在获取状态后,watcher将对比上一次请求的结果,找到任何发生变化的对象,并将它们发送到事件队列中

在运行时,informer将indexer和watcher组合在一起,以便实现对象的监视和更新。当watcher从API服务器中获取到对象时,它会将它们添加到indexer中。如果对象已经存在于indexer中,则watcher将更新对象的状态。一旦对象被更新,informerSyncHandler将被触发,以便将更新后的对象发送到事件队列中。在事件处理程序中,可以通过调用indexer对象的方法来访问缓存中的对象

画了一个可能不太标准的图: informer

了解了Informer架构和Reflector、DeltaFIFO、Indexer几个组件后,再回头来看示例中的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
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 relist一次
    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退出,informer以goroutine运行
    stopper := make(chan struct{})
    defer close(stopper)

    // 启动 informer 去 list & watch
    // 即 SharedIndexInformer 的 run方法,new了DeltaFIFO,然后new出sharedIndexInformer.controller,调用Controller的run方法(即Reflector的run方法),run里面创建了Reflector并执行
    sharedInformerFactory.Start(stopper)
    // 等待所有启动的 Informer 的缓存被同步
    sharedInformerFactory.WaitForCacheSync(stopper)
    informer.Run(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
}

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创建Informer对象,函数中传入了clientset和defaultResync参数,clientset是访问APIServer的具体实现,resyncPeriod指定了informer在从API服务器中获取数据之间等待的时间,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,遵循组、版本、资源(即GVK)格式,其他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结构体封装,然后由processorListener管理,这个processorListener也是比较核心的一个对象,拥有一个RingGrowingBuffer和两个通道addCh、nextCh,它实现了事件的缓冲和处理,无事件时阻塞等待,有事件时发送给handlers,处理不过来呢就先放到环形缓冲区中。processorListener会由sharedProcessor管理,若sharedProcessor已启动,则开启俩协程分别运行新添加的processorListener的run和pop两个方法,这两个方法利用无缓冲通道相互依赖,没有事件的时候都处于阻塞状态。

    其中,run方法里面用for range不断轮询nextCh通道,接收事件数据并交给我们添加的对应的EventHandlerFunc处理,那么nextCh通道里面的事件从哪里来呢?从addCh通道来

    pop方法的实现就很巧妙,从addCh通道接收到数据后,发送给nextCh通道,并由run方法消费(随即交给EventHandlerFunc处理),run消费的慢喽那么后续的notification会被放到ringbuffer里面。addCh通道的数据从哪里来呢?是DeltaFIFO,controller.processLoop方法调用DeltaFIFO的pop方法,最终将Deltas交给了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
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函数是每秒去轮询消费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等组件串了起来,使其成为一个运行中的完整功能。