K8S源码分析Controller Manager - 4、Controller实现的一个例子-ReplicaSetController

Controller的实现基本上都是通过SharedInformer的结构去监听etcd上某种资源的变更,然后再执行对应的业务逻辑。

本文以ReplicaSetController为例,介绍一个controller如何与整个manager组合在一起。

controller启动

controllers都是在NewControllerInitializers()方法中引入到manager里的:

func NewControllerInitializers() map[string]InitFunc {

   controllers := map[string]InitFunc{}

   ....

   controllers["replicaset"] = startReplicaSetController

   ....

   return controllers

}

startReplicaSetController是启动函数,如下:

func startReplicaSetController(ctx ControllerContext) (bool, error) {

   if !ctx.AvailableResources[schema.GroupVersionResource{Group: "extensions", Version: "v1beta1", Resource: "replicasets"}] {

      return false, nil

   }

   // 获取监听ReplicaSets/Pods的Informer

   go replicaset.NewReplicaSetController(

      ctx.InformerFactory.Extensions().V1beta1().ReplicaSets(),

      ctx.InformerFactory.Core().V1().Pods(),

      ctx.ClientBuilder.ClientOrDie("replicaset-controller"),

      replicaset.BurstReplicas,

   ).Run(int(ctx.Options.ConcurrentRSSyncs), ctx.Stop)

   return true, nil

}

创建过程如下:

// NewReplicaSetController configures a replica set controller with the specified event recorder

func NewReplicaSetController(rsInformer extensionsinformers.ReplicaSetInformer, podInformer coreinformers.PodInformer, kubeClient clientset.Interface, burstReplicas int) *ReplicaSetController {

   ....

   // 初始化controller

   rsc := &ReplicaSetController{

      kubeClient: kubeClient,

      podControl: controller.RealPodControl{

         KubeClient: kubeClient,

         Recorder:   eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "replicaset-controller"}),

      },

      burstReplicas: burstReplicas,

      expectations:  controller.NewUIDTrackingControllerExpectations(controller.NewControllerExpectations()),

      queue:         workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "replicaset"),

   }

 

   // 在replica set informer上注册回调handler

   rsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{

      AddFunc:    rsc.enqueueReplicaSet,

      UpdateFunc: rsc.updateRS,

      // This will enter the sync loop and no-op, because the replica set has been deleted from the store.

      // Note that deleting a replica set immediately after scaling it to 0 will not work. The recommended

      // way of achieving this is by performing a `stop` operation on the replica set.

      DeleteFunc: rsc.enqueueReplicaSet,

   })

   rsc.rsLister = rsInformer.Lister()

   rsc.rsListerSynced = rsInformer.Informer().HasSynced

 

   // 在pod informer上注册回调

   podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{

      AddFunc: rsc.addPod,

      // This invokes the ReplicaSet for every pod change, eg: host assignment. Though this might seem like

      // overkill the most frequent pod update is status, and the associated ReplicaSet will only list from

      // local storage, so it should be ok.

      UpdateFunc: rsc.updatePod,

      DeleteFunc: rsc.deletePod,

   })

   rsc.podLister = podInformer.Lister()

   rsc.podListerSynced = podInformer.Informer().HasSynced

 

   // syncReplicaSet整个controller实际业务逻辑的入口,会被回调触发

   rsc.syncHandler = rsc.syncReplicaSet

 

   return rsc

}

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和配置一致。

K8S源码分析Controller Manager - 4、Controller实现的一个例子-ReplicaSetController_第1张图片

总结

每个Controller的处理逻辑都不相同,但与manager & informer的交互大体类似。

ReplicaSetController的分析中可以再次看出go实现中,调用顺序和传统面向对象语言有很大差异。

转载于:https://my.oschina.net/zhuhui/blog/3081714

你可能感兴趣的:(K8S源码分析Controller Manager - 4、Controller实现的一个例子-ReplicaSetController)