在学习讲解执行kubectl run ...
命令时发生了什么的这篇文章时,想到一个问题,既然controller是状态驱动的,只有当资源发生了改变才会触发controller的处理,那如果在处理资源的过程中controller挂掉,因为apiserver是无状态的,不存在事件交付处理过期等机制,那这个资源就一直处于未处理的状态吗。例如新建了一个deployment,再deployment controller准备新增replicaset的时候挂掉,那这个deployment会一直没有replicaset吗。首先答案当然是否定的,controller会以某种机制,确保已知的资源是已经被正确处理了,那具体代码是怎么实现的,本文主要基于这篇博客进行一些源码阅读和分析,这篇博客已经讲得非常好了,但是基于的codebase比较老旧,本文从release-1.21分支出发去扒一下具体的实现过程,对大部分函数都进行了一定程度的简化。
首先看到deployment controller的核心代码,主要就是在几个informer中注册handler,这些handler主要是将相关的deployment enqueue到队列(deployment controller自己的队列,和informer的队列不是同一个)中,交给处理协程。
// pkg/controller/deployment/deployment_controller.go
func NewDeploymentController(
dInformer appsinformers.DeploymentInformer,
rsInformer appsinformers.ReplicaSetInformer,
podInformer coreinformers.PodInformer,
client clientset.Interface,
) (*DeploymentController, error) {
dc := &DeploymentController{
}
dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: dc.addDeployment,
UpdateFunc: dc.updateDeployment,
DeleteFunc: dc.deleteDeployment,
})
rsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: dc.addReplicaSet,
UpdateFunc: dc.updateReplicaSet,
DeleteFunc: dc.deleteReplicaSet,
})
podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
DeleteFunc: dc.deletePod,
})
}
既然deployment controller中只是根据到来的event进行处理,那么相关机制应该隐藏在了informer中。NewDeploymentController
在app中被调用:
// cmd/kube-controller-manager/app/apps.go
func startDeploymentController(ctx ControllerContext) (http.Handler, bool, error) {
dc, err := deployment.NewDeploymentController(
ctx.InformerFactory.Apps().V1().Deployments(),
ctx.InformerFactory.Apps().V1().ReplicaSets(),
ctx.InformerFactory.Core().V1().Pods(),
ctx.ClientBuilder.ClientOrDie("deployment-controller"),
)
if err != nil {
return nil, true, fmt.Errorf("error creating Deployment controller: %v", err)
<