源码基于k8s 1.9 release

源码目录结构

cmd/kube-controller-manager/app/core.go:237    // PodGc Controller的启动代码,包含很多其它controller的启动

/pkg/controller/podgc
.
├── BUILD
├── OWNERS
├── doc.go
├── gc_controller.go // podGc的核心代码逻辑
├── gc_controller_test.go    
├── OWNERS

podGc的启动代码如下,初始化podGcController,通过sharedInformerFactory(client-go/informers/factory.go)对象的Core().V1().Pods()方法,将会构建PodInformer对象,TerminatedPodGCThreshold为pod中terminating个数的上限,在kube-controller-manager的参数中设置。

func startPodGCController(ctx ControllerContext) (bool, error) {
    go podgc.NewPodGC(
        ctx.ClientBuilder.ClientOrDie("pod-garbage-collector"),
        ctx.InformerFactory.Core().V1().Pods(),
        int(ctx.Options.TerminatedPodGCThreshold),
    ).Run(ctx.Stop)
    return true, nil
}

Run函数如下,其中go wait.Until(gcc.gc, gcCheckPeriod, stop)中的gcCheckPeriod在代码中固定为20秒,即没20s执行一次pod的清理工作。

func (gcc *PodGCController) Run(stop <-chan struct{}) {
    defer utilruntime.HandleCrash()

    glog.Infof("Starting GC controller")
    defer glog.Infof("Shutting down GC controller")

    if !controller.WaitForCacheSync("GC", stop, gcc.podListerSynced) {
        return
    }

    go wait.Until(gcc.gc, gcCheckPeriod, stop)

    <-stop
}

gc函数如下

func (gcc *PodGCController) gc() {
    pods, err := gcc.podLister.List(labels.Everything())
    if err != nil {
        glog.Errorf("Error while listing all Pods: %v", err)
        return
    }
    if gcc.terminatedPodThreshold > 0 {
        gcc.gcTerminated(pods)
    }
    gcc.gcOrphaned(pods)
    gcc.gcUnscheduledTerminating(pods)
}

其基本逻辑是每次都获取所有的pod列表
(a) 如果设定的terminatedPodThreshold值大于0,则执行gcc.gcTerminated函数,挑选出所有状态为terminating的pod,并按照时间从旧到新的顺序排序,如果当前的terminating大于terminatedPodThreshold值,则按时间顺序删掉旧的,个数为terminating的pod数减去terminatedPodThreshold值数量的terminating状态pod。
(b) 运行gcc.gcOrphaned函数,该函数主要作用是寻找那些已经分配了节点但节点已经不存在集群中的pod,检查逻辑是遍历(a)中处理过的pod列表,剔除那些未分配节点的和已经分配节点并且集群总存在该节点的pod,不满足这两种情况的pod将被删除。
(c) 运行gcc.gcUnscheduledTerminating函数,该函数主要作用是找出那些目前状态是Terminating并且改pod还没被调度到节点中的pod,将它删除。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐