Kubernetes PodGC Controller怎么配置

77次阅读
没有评论

共计 7114 个字符,预计需要花费 18 分钟才能阅读完成。

本篇内容介绍了“Kubernetes PodGC Controller 怎么配置”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

PodGC Controller 配置

关于 PodGC Controller 的相关配置(kube-controller-manager 配置),一共只有两个:

flagdefault valuecomments–controllers stringSlice* 这里配置需要 enable 的 controlllers 列表,podgc 当然也可以在这里设置是都要 enable or disable,默认 podgc 是在 enable 列表中的。–terminated-pod-gc-threshold int3212500Number of terminated pods that can exist before the terminated pod garbage collector starts deleting terminated pods. If = 0, the terminated pod garbage collector is disabled. (default 12500)PodGC Controller 入口

PodGC Controller 是在 kube-controller-manager Run 的时候启动的。CMServer Run 时会 invoke StartControllers 将预先注册的 enabled Controllers 遍历并逐个启动。

cmd/kube-controller-manager/app/controllermanager.go:180
func Run(s *options.CMServer) error {
 ...
 err := StartControllers(newControllerInitializers(), s, rootClientBuilder, clientBuilder, stop)
}

在 newControllerInitializers 注册了所有一些常规 Controllers 及其对应的 start 方法,为什么说这些是常规的 Controllers 呢,因为还有一部分 Controllers 没在这里进行注册,比如非常重要的 service Controller,node Controller 等,我把这些称为非常规 Controllers。

func newControllerInitializers() map[string]InitFunc {controllers := map[string]InitFunc{}
 controllers[endpoint] = startEndpointController
 controllers[podgc] = startPodGCController
 return controllers
}

因此 CMServer 最终是 invoke startPodGCController 来启动 PodGC Controller 的。

cmd/kube-controller-manager/app/core.go:66
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
}

startPodGCController 内容很简单,启动一个 goruntine 协程,创建 PodGC 并启动执行。

PodGC Controller 的创建

我们先来看看 PodGCController 的定义。

pkg/controller/podgc/gc_controller.go:44
type PodGCController struct {
 kubeClient clientset.Interface
 podLister corelisters.PodLister
 podListerSynced cache.InformerSynced
 deletePod func(namespace, name string) error
 terminatedPodThreshold int
}

kubeClient: 用来跟 APIServer 通信的 client。

PodLister: PodLister helps list Pods.

podListerSynced: 用来判断 PodLister 是否 Has Synced。

deletePod: 调用 apiserver 删除对应 pod 的接口。

terminatedPodThreshold: 对应 –terminated-pod-gc-threshold 的配置,默认为 12500。

pkg/controller/podgc/gc_controller.go:54
func NewPodGC(kubeClient clientset.Interface, podInformer coreinformers.PodInformer, terminatedPodThreshold int) *PodGCController {if kubeClient != nil   kubeClient.Core().RESTClient().GetRateLimiter() != nil {metrics.RegisterMetricAndTrackRateLimiterUsage( gc_controller , kubeClient.Core().RESTClient().GetRateLimiter())
 gcc :=  PodGCController{
 kubeClient: kubeClient,
 terminatedPodThreshold: terminatedPodThreshold,
 deletePod: func(namespace, name string) error {glog.Infof( PodGC is force deleting Pod: %v:%v , namespace, name)
 return kubeClient.Core().Pods(namespace).Delete(name, metav1.NewDeleteOptions(0))
 gcc.podLister = podInformer.Lister()
 gcc.podListerSynced = podInformer.Informer().HasSynced
 return gcc
}

创建 PodGC Controller 时其实只是把相关的 PodGCController 元素进行赋值。注意 deletePod 方法定义时的参数 metav1.NewDeleteOptions(0),表示立即删除 pod,没有 grace period。

PodGC Controller 的运行

创建完 PodGC Controller 后,接下来就是执行 Run 方法启动执行了。

pkg/controller/podgc/gc_controller.go:73
func (gcc *PodGCController) Run(stop  -chan struct{}) {if !cache.WaitForCacheSync(stop, gcc.podListerSynced) {utilruntime.HandleError(fmt.Errorf( timed out waiting for caches to sync))
 return
 go wait.Until(gcc.gc, gcCheckPeriod, stop)
 -stop
}

每 100ms 都会去检查对应的 PodLister 是否 Has Synced,直到 Has Synced。

启动 goruntine 协程,每执行完一次 gcc.gc 进行 Pod 回收后,等待 20s,再次执行 gcc.gc,直到收到 stop 信号。

pkg/controller/podgc/gc_controller.go:83
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)
}

gcc.gc 是最终的 pod 回收逻辑:

调从 PodLister 中去除所有的 pods(不设置过滤)

如果 terminatedPodThreshold 大于 0,则调用 gcc.gcTerminated(pods)回收那些超出 Threshold 的 Pods。

调用 gcc.gcOrphaned(pods)回收 Orphaned pods。

调用 gcc.gcUnscheduledTerminating(pods)回收 UnscheduledTerminating pods。

注意:

gcTerminated 和 gcOrphaned,gcUnscheduledTerminating 这三个 gc 都是串行执行的。

gcTerminated 删除超出阈值的 pods 的删除动作是并行的,通过 sync.WaitGroup 等待所有对应的 pods 删除完成后,gcTerminated 才会结束返回,才能开始后面的 gcOrphaned.

gcOrphaned,gcUnscheduledTerminatin,gcUnscheduledTerminatin 内部都是串行 gc pods 的。

回收那些 Terminated 的 pods

func (gcc *PodGCController) gcTerminated(pods []*v1.Pod) {terminatedPods := []*v1.Pod{}
 for _, pod := range pods {if isPodTerminated(pod) {terminatedPods = append(terminatedPods, pod)
 terminatedPodCount := len(terminatedPods)
 sort.Sort(byCreationTimestamp(terminatedPods))
 deleteCount := terminatedPodCount - gcc.terminatedPodThreshold
 if deleteCount   terminatedPodCount {
 deleteCount = terminatedPodCount
 if deleteCount   0 {glog.Infof( garbage collecting %v pods , deleteCount)
 var wait sync.WaitGroup
 for i := 0; i   deleteCount; i++ {wait.Add(1)
 go func(namespace string, name string) {defer wait.Done()
 if err := gcc.deletePod(namespace, name); err != nil {
 // ignore not founds
 defer utilruntime.HandleError(err)
 }(terminatedPods[i].Namespace, terminatedPods[i].Name)
 wait.Wait()}

遍历所有 pods,过滤出所有 Terminated Pods(Pod.Status.Phase 不为 Pending, Running, Unknow 的 Pods).

计算 terminated pods 数与 terminatedPodThreshold 的 (超出) 差值 deleteCount。

启动 deleteCount 数量的 goruntine 协程,并行调用 gcc.deletePod(invoke apiserver s api)方法立刻删除对应的 pod。

回收那些 Binded 的 Nodes 已经不存在的 pods

// gcOrphaned deletes pods that are bound to nodes that don t exist.
func (gcc *PodGCController) gcOrphaned(pods []*v1.Pod) {glog.V(4).Infof(GC ing orphaned)
 // We want to get list of Nodes from the etcd, to make sure that it s as fresh as possible.
 nodes, err := gcc.kubeClient.Core().Nodes().List(metav1.ListOptions{})
 if err != nil {
 return
 nodeNames := sets.NewString()
 for i := range nodes.Items {nodeNames.Insert(nodes.Items[i].Name)
 for _, pod := range pods {
 if pod.Spec.NodeName ==   {
 continue
 if nodeNames.Has(pod.Spec.NodeName) {
 continue
 glog.V(2).Infof(Found orphaned Pod %v assigned to the Node %v. Deleting. , pod.Name, pod.Spec.NodeName)
 if err := gcc.deletePod(pod.Namespace, pod.Name); err != nil {utilruntime.HandleError(err)
 } else {glog.V(0).Infof(Forced deletion of orphaned Pod %s succeeded , pod.Name)
}

gcOrphaned 用来删除那些 bind 的 node 已经不存在的 pods。

调用 apiserver 接口,获取所有的 Nodes。

遍历所有 pods,如果 pod bind 的 NodeName 不为空且不包含在刚刚获取的所有 Nodes 中,则串行逐个调用 gcc.deletePod 删除对应的 pod。

回收 Unscheduled 并且 Terminating 的 pods

pkg/controller/podgc/gc_controller.go:167
// gcUnscheduledTerminating deletes pods that are terminating and haven t been scheduled to a particular node.
func (gcc *PodGCController) gcUnscheduledTerminating(pods []*v1.Pod) {glog.V(4).Infof(GC ing unscheduled pods which are terminating.)
 for _, pod := range pods {if pod.DeletionTimestamp == nil || len(pod.Spec.NodeName)   0 {
 continue
 glog.V(2).Infof(Found unscheduled terminating Pod %v not assigned to any Node. Deleting. , pod.Name)
 if err := gcc.deletePod(pod.Namespace, pod.Name); err != nil {utilruntime.HandleError(err)
 } else {glog.V(0).Infof(Forced deletion of unscheduled terminating Pod %s succeeded , pod.Name)
}

gcUnscheduledTerminating 删除那些 terminating 并且还没调度到某个 node 的 pods。

遍历所有 pods,过滤那些 terminating(pod.DeletionTimestamp != nil)并且未调度成功的 (pod.Spec.NodeName 为空) 的 pods。

串行逐个调用 gcc.deletePod 删除对应的 pod。

“Kubernetes PodGC Controller 怎么配置”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-16发表,共计7114字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)