深入分析Kubernetes Critical Pod(二)

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
简介: [深入分析Kubernetes Critical Pod(一)](https://yq.aliyun.com/articles/603541)介绍了Scheduler对Critical Pod的处理逻辑,下面我们再看下Kubelet Eviction Manager对Critical Pod的处理逻辑是怎样的,以便我们了解Kubelet Evict Pod时对Critical Pod是否有保护措施,如果有,又是如何保护的。

深入分析Kubernetes Critical Pod(一)介绍了Scheduler对Critical Pod的处理逻辑,下面我们再看下Kubelet Eviction Manager对Critical Pod的处理逻辑是怎样的,以便我们了解Kubelet Evict Pod时对Critical Pod是否有保护措施,如果有,又是如何保护的。

Kubelet Eviction Manager Admit

kubelet在syncLoop中每个1s会循环调用syncLoopIteration,从config change channel | pleg channel | sync channel | houseKeeping channel | liveness manager's update channel中获取event,然后分别调用对应的event handler进行处理。

  • configCh: dispatch the pods for the config change to the appropriate handler callback for the event type
  • plegCh: update the runtime cache; sync pod
  • syncCh: sync all pods waiting for sync
  • houseKeepingCh: trigger cleanup of pods
  • liveness manager's update channel: sync pods that have failed or in which one or more containers have failed liveness checks

特别提一下,houseKeeping channel是每隔houseKeeping(10s)时间就会有event,然后执行HandlePodCleanups,执行以下清理操作:

  • Stop the workers for no-longer existing pods.(每个pod对应会有一个worker,也就是goruntine)
  • killing unwanted pods
  • removes the volumes of pods that should not be running and that have no containers running.
  • Remove any orphaned mirror pods.
  • Remove any cgroups in the hierarchy for pods that are no longer running.
pkg/kubelet/kubelet.go:1753

func (kl *Kubelet) syncLoopIteration(configCh <-chan kubetypes.PodUpdate, handler SyncHandler,
    syncCh <-chan time.Time, housekeepingCh <-chan time.Time, plegCh <-chan *pleg.PodLifecycleEvent) bool {
    select {
    case u, open := <-configCh:
        
        if !open {
            glog.Errorf("Update channel is closed. Exiting the sync loop.")
            return false
        }

        switch u.Op {
        case kubetypes.ADD:
            
            handler.HandlePodAdditions(u.Pods)
        ...
        case kubetypes.RESTORE:
            glog.V(2).Infof("SyncLoop (RESTORE, %q): %q", u.Source, format.Pods(u.Pods))
            // These are pods restored from the checkpoint. Treat them as new
            // pods.
            handler.HandlePodAdditions(u.Pods)
        ...
        }

        if u.Op != kubetypes.RESTORE {
            ...
        }
    case e := <-plegCh:
        ...
    case <-syncCh:
        ...
    case update := <-kl.livenessManager.Updates():
        ...
    case <-housekeepingCh:
        ...
    }
    return true
}

syncLoopIteration中定义了当kubelet配置变更重启后的逻辑:kubelet会对正在running的Pods进行Admission处理,Admission的结果有可能会让该Pod被本节点拒绝。

HandlePodAdditions就是用来处理Kubelet ConficCh中的event的Handler。

// HandlePodAdditions is the callback in SyncHandler for pods being added from a config source.
func (kl *Kubelet) HandlePodAdditions(pods []*v1.Pod) {
    start := kl.clock.Now()
    sort.Sort(sliceutils.PodsByCreationTime(pods))
    for _, pod := range pods {
        ...

        if !kl.podIsTerminated(pod) {
            ...
            // Check if we can admit the pod; if not, reject it.
            if ok, reason, message := kl.canAdmitPod(activePods, pod); !ok {
                kl.rejectPod(pod, reason, message)
                continue
            }
        }
        ...
    }
}

如果该Pod Status不是属于Terminated,就调用canAdmitPod对该Pod进行准入检查。如果准入检查结果表示该Pod被拒绝,那么就会将该Pod Phase设置为Failed。

pkg/kubelet/kubelet.go:1643

func (kl *Kubelet) canAdmitPod(pods []*v1.Pod, pod *v1.Pod) (bool, string, string) {
    // the kubelet will invoke each pod admit handler in sequence
    // if any handler rejects, the pod is rejected.
    // TODO: move out of disk check into a pod admitter
    // TODO: out of resource eviction should have a pod admitter call-out
    attrs := &lifecycle.PodAdmitAttributes{Pod: pod, OtherPods: pods}
    for _, podAdmitHandler := range kl.admitHandlers {
        if result := podAdmitHandler.Admit(attrs); !result.Admit {
            return false, result.Reason, result.Message
        }
    }

    return true, "", ""
}

canAdmitPod就会调用kubelet启动时注册的一系列admitHandlers对该Pod进行准入检查,其中就包括kubelet eviction manager对应的admitHandle。

pkg/kubelet/eviction/eviction_manager.go:123

// Admit rejects a pod if its not safe to admit for node stability.
func (m *managerImpl) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAdmitResult {
    m.RLock()
    defer m.RUnlock()
    if len(m.nodeConditions) == 0 {
        return lifecycle.PodAdmitResult{Admit: true}
    }
    
    if utilfeature.DefaultFeatureGate.Enabled(features.ExperimentalCriticalPodAnnotation) && kubelettypes.IsCriticalPod(attrs.Pod) {
        return lifecycle.PodAdmitResult{Admit: true}
    }

    if hasNodeCondition(m.nodeConditions, v1.NodeMemoryPressure) {
        notBestEffort := v1.PodQOSBestEffort != v1qos.GetPodQOS(attrs.Pod)
        if notBestEffort {
            return lifecycle.PodAdmitResult{Admit: true}
        }
    }

        return lifecycle.PodAdmitResult{
        Admit:   false,
        Reason:  reason,
        Message: fmt.Sprintf(message, m.nodeConditions),
    }
}

eviction manager的Admit的逻辑如下:

  • 如果该node的Conditions为空,则Admit成功;
  • 如果enable了ExperimentalCriticalPodAnnotation Feature Gate,并且该Pod是Critical Pod(Pod有Critical的Annotation,或者Pod的优先级不小于SystemCriticalPriority),则Admit成功;

    • SystemCriticalPriority的值为2 billion。
  • 如果该node的Condition为Memory Pressure,并且Pod QoS为非best-effort,则Admit成功;
  • 其他情况都表示Admit失败,即不允许该Pod在该node上Running。

Kubelet Eviction Manager SyncLoop

另外,在kubelet eviction manager的syncLoop中,也会对Critical Pod有特殊处理,代码如下。

pkg/kubelet/eviction/eviction_manager.go:226

// synchronize is the main control loop that enforces eviction thresholds.
// Returns the pod that was killed, or nil if no pod was killed.
func (m *managerImpl) synchronize(diskInfoProvider DiskInfoProvider, podFunc ActivePodsFunc) []*v1.Pod {
    ...

    // we kill at most a single pod during each eviction interval
    for i := range activePods {
        pod := activePods[i]
        
        if utilfeature.DefaultFeatureGate.Enabled(features.ExperimentalCriticalPodAnnotation) &&
            kubelettypes.IsCriticalPod(pod) && kubepod.IsStaticPod(pod) {
            continue
        }
        ...
        return []*v1.Pod{pod}
    }
    glog.Infof("eviction manager: unable to evict any pods from the node")
    return nil
}

当触发了kubelet evict pod时,如果该pod满足以下所有条件时,将不会被kubelet eviction manager kill掉。

  • 该Pod Status不是Terminated;
  • Enable ExperimentalCriticalPodAnnotation Feature Gate;
  • 该Pod是Critical Pod;
  • 该Pod时Static Pod;

总结

经过上面的分析,我们得到以下Kubelet Eviction Manager对Critical Pod处理的关键点:

  • kubelet重启后,eviction manager的Admit流程中对Critical Pod做如下特殊处理:如果enable了ExperimentalCriticalPodAnnotation Feature Gate,则允许该Critical Pod准入该node,无视该node的Condition。
  • 当触发了kubelet evict pod时,如果该Critical Pod满足以下所有条件时,将不会被kubelet eviction manager kill掉。

    • 该Pod Status不是Terminated;
    • Enable ExperimentalCriticalPodAnnotation Feature Gate;
    • 该Pod是Static Pod;
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
7天前
|
存储 Kubernetes Docker
【赵渝强老师】Kubernetes中Pod的基础容器
Pod 是 Kubernetes 中的基本单位,代表集群上运行的一个进程。它由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。基础容器负责维护 Pod 的网络空间,对用户透明。文中附有图片和视频讲解,详细介绍了 Pod 的组成结构及其在网络配置中的作用。
【赵渝强老师】Kubernetes中Pod的基础容器
|
7天前
|
运维 Kubernetes Shell
【赵渝强老师】K8s中Pod的临时容器
Pod 是 Kubernetes 中的基本调度单位,由一个或多个容器组成,包括业务容器、基础容器、初始化容器和临时容器。临时容器用于故障排查和性能诊断,不适用于构建应用程序。当 Pod 中的容器异常退出或容器镜像不包含调试工具时,临时容器非常有用。文中通过示例展示了如何使用 `kubectl debug` 命令创建临时容器进行调试。
|
7天前
|
Kubernetes 调度 容器
【赵渝强老师】K8s中Pod中的业务容器
Pod 是 Kubernetes 中的基本调度单元,由一个或多个容器组成。除了业务容器,Pod 还包括基础容器、初始化容器和临时容器。本文通过示例介绍如何创建包含业务容器的 Pod,并提供了一个视频讲解。示例中创建了一个名为 &quot;busybox-container&quot; 的业务容器,并使用 `kubectl create -f firstpod.yaml` 命令部署 Pod。
|
7天前
|
Kubernetes 容器 Perl
【赵渝强老师】K8s中Pod中的初始化容器
Kubernetes的Pod包含业务容器、基础容器、初始化容器和临时容器。初始化容器在业务容器前运行,用于执行必要的初始化任务。本文介绍了初始化容器的作用、配置方法及优势,并提供了一个示例。
|
8天前
|
存储 Kubernetes 调度
深入理解Kubernetes中的Pod与Container
深入理解Kubernetes中的Pod与Container
16 0
|
8天前
|
Kubernetes Java 调度
Kubernetes中的Pod垃圾回收策略是什么
Kubernetes中的Pod垃圾回收策略是什么
|
8天前
|
存储 Kubernetes 调度
深度解析Kubernetes中的Pod生命周期管理
深度解析Kubernetes中的Pod生命周期管理
|
22天前
|
JSON Kubernetes 容灾
ACK One应用分发上线:高效管理多集群应用
ACK One应用分发上线,主要介绍了新能力的使用场景
|
23天前
|
Kubernetes 持续交付 开发工具
ACK One GitOps:ApplicationSet UI简化多集群GitOps应用管理
ACK One GitOps新发布了多集群应用控制台,支持管理Argo CD ApplicationSet,提升大规模应用和集群的多集群GitOps应用分发管理体验。
|
1月前
|
Kubernetes Cloud Native 云计算
云原生之旅:Kubernetes 集群的搭建与实践
【8月更文挑战第67天】在云原生技术日益成为IT行业焦点的今天,掌握Kubernetes已成为每个软件工程师必备的技能。本文将通过浅显易懂的语言和实际代码示例,引导你从零开始搭建一个Kubernetes集群,并探索其核心概念。无论你是初学者还是希望巩固知识的开发者,这篇文章都将为你打开一扇通往云原生世界的大门。
120 17

相关产品

  • 容器服务Kubernetes版