Controller的实现基本上都是通过SharedInformer的结构去监听etcd上某种资源的变更,然后再执行对应的业务逻辑。
本文以ReplicaSetController为例,介绍一个controller如何与整个manager组合在一起。
controller启动
controllers都是在NewControllerInitializers()方法中引入到manager里的:
|
startReplicaSetController是启动函数,如下:
|
创建过程如下:
|
Replica Set资源变更回调
Informer监听到的变更最终会回调到syncReplicaSet方法上,但当中会穿越多个协程,逻辑比较复杂。用一个时序图近似表示如下:
1.Controller变更通知
这里的controller是Informer层的结构,对于资源变更会触发HandleDeltas()方法。HandleDeltas方法会调用sharedProcessor.distribute方法,将Delta传入到processListener的channel上,等待被处理。
2.processorListener.run
run方法会不断拉取listener自己本地channel中的变更,并根据ActionType分发到注册的handler上的不同方法里。
在上文介绍的NewReplicaSetController()函数里,可以看到AddFunc对应的回调函数是enqueueReplicaSet。最终会把delta放入ReplicaSetController自己的queue队列中,等待controller处理。
3.ReplicaSetController.processNextItem
processNextItem方法会处理RepliaSetController.queue当中的变更信息,最终调用syncReplicaSet方法来处理变更,确保Pods和配置一致。
总结
每个Controller的处理逻辑都不相同,但与manager & informer的交互大体类似。
ReplicaSetController的分析中可以再次看出go实现中,调用顺序和传统面向对象语言有很大差异。