更新时间:2024-10-14 GMT+08:00

工作负载异常:实例驱逐异常(Evicted)

驱逐原理

当节点出现异常时,为了保证工作负载的可用性,Kubernetes会通过驱逐机制(Eviction)将该节点上的Pod调离异常节点。

目前Kubernetes中存在两种Eviction机制,分别由kube-controller-managerkubelet实现。

  • kube-controller-manager实现的驱逐

    kube-controller-manager主要由多个控制器构成,而驱逐的功能主要由node controller这个控制器实现,它会周期性检查所有节点状态,当节点处于NotReady状态超过一段时间后,驱逐该节点上所有Pod。

    kube-controller-manager提供了以下启动参数控制驱逐:

    • pod-eviction-timeout:即当节点宕机时间超过一定的时间间隔后,开始驱逐宕机节点上的Pod,默认为5min。
    • node-eviction-rate:每秒需要排空的节点数量,默认为0.1,即每10s从一个节点驱逐Pod。
    • secondary-node-eviction-rate:第二档的排空节点的速率。当集群中宕机节点过多时,排空节点的速率会降低至第二档,默认为0.01。
    • unhealthy-zone-threshold:可用区的不健康阈值,默认为0.55,即当该可用区中节点宕机数目超过55%时,认为该可用区不健康。
    • large-cluster-size-threshold:集群的大规模阈值,默认为50,当集群节点数量超过该阈值时认为集群属于大规模集群。大规模集群的可用区节点宕机数目超过55%时,则将排空节点速率降为0.01;假如是小规模集群,则将速率直接降为0,即停止驱逐节点上的Pod。
  • kubelet的eviction机制

    如果节点处于资源压力,那么kubelet就会执行驱逐策略。驱逐会考虑Pod的优先级,资源使用和资源申请。当优先级相同时,资源使用/资源申请最大的Pod会被首先驱逐。

    kube-controller-manager的驱逐机制是粗粒度的,即驱逐一个节点上的所有Pod,而kubelet则是细粒度的,它驱逐的是节点上的某些Pod。此类驱逐会周期性检查本节点内存、磁盘等资源,当资源不足时,按照优先级驱逐部分Pod。关于Pod驱逐优先级,请参见kubelet驱逐时Pod的选择

    驱逐阈值分为软驱逐条件(Soft Eviction Thresholds)和硬驱逐条件(Hard Eviction Thresholds)两种机制,如下:

    • 软驱逐条件:当节点的内存/磁盘空间达到一定的阈值后,kubelet不会马上回收资源,如果改善到低于阈值就不进行驱逐,若这段时间一直高于阈值就进行驱逐。
      您可以通过以下参数配置软驱逐条件:
      • eviction-soft:软驱逐阈值设置。当节点驱逐信号满足一定阈值时,例如memory.available<1.5Gi时,kubelet不会立即执行Pod驱逐,而会等待eviction-soft-grace-period时间,假如该时间过后,依然还是达到了软驱逐阈值,则触发一次Pod驱逐。
      • eviction-soft-grace-period:当达到软驱逐阈值时,允许Pod优雅终止的时间,即软驱逐宽限期,软驱逐信号与驱逐处理之间的时间差。默认为90秒。
      • eviction-max-pod-grace-period:最大驱逐pod宽限期,停止信号与kill之间的时间差。
    • 硬驱逐条件:硬驱逐机制则简单的多,一旦达到阈值,直接把Pod从本地驱逐。

      您可以通过以下参数配置硬驱逐条件:

      eviction-hard硬驱逐阈值设置。当节点驱逐信号满足一定阈值时,例如memory.available<1Gi,即当节点可用内存低于1Gi时,会立即触发一次Pod驱逐。

      kubelet 具有以下默认硬驱逐条件:

      • memory.available<100Mi
      • nodefs.available<10%
      • imagefs.available<15%
      • nodefs.inodesFree<5%(Linux 节点)

    除此之外,kubelet还提供了其他的驱逐参数:

    • eviction-pressure-transition-period:驱逐等待时间。当出现节点压力驱逐时,节点需要等待一定的时间,才会被设置为DiskPressure或者MemoryPressure,然后开启Pod驱逐,该时间默认为5分钟。该参数可以防止在某些情况下,节点在软驱逐条件上下振荡而出现错误的驱逐决策。
    • eviction-minimum-reclaim:表示每一次驱逐必须至少回收多少资源。该参数可以避免在某些情况下,驱逐Pod只会回收少量的资源,导致kubelet反复触发多次驱逐。

问题定位

若节点故障时,实例未被驱逐,请先按照如下方法进行问题定位。

使用如下命令发现很多pod的状态为Evicted:

kubectl get pods
在节点的kubelet日志中会记录Evicted相关内容,搜索方法可参考如下命令:
cat /var/log/cce/kubernetes/kubelet.log | grep -i Evicted -C3

排查思路

以下排查思路根据原因的出现概率进行排序,建议您从高频率原因往低频率原因排查,从而帮助您快速找到问题的原因。

如果解决完某个可能原因仍未解决问题,请继续排查其他可能原因。

排查项一:节点是否存在资源压力

当满足硬性或软性驱逐条件时,即存在资源压力时,kubelet会根据驱逐信号将节点设置为相应的节点状况,并为节点打上对应的污点。请通过以下步骤查看节点是否存在对应的污点。

$ kubectl describe node 192.168.0.37
Name:               192.168.0.37
...
Taints:             key1=value1:NoSchedule
...
表1 存在资源压力的节点状况及解决方案

节点状况

节点污点

驱逐信号

描述

MemoryPressure

node.kubernetes.io/memory-pressure

memory.available

节点上的可用内存已满足驱逐条件。

DiskPressure

node.kubernetes.io/disk-pressure

nodefs.available、nodefs.inodesFree、imagefs.available 或 imagefs.inodesFree

节点的根文件系统或镜像文件系统上的可用磁盘空间和 inode 已满足驱逐条件。

PIDPressure

node.kubernetes.io/pid-pressure

pid.available

节点上的可用进程标识符已低于驱逐条件。

排查项二:是否在实例上设置了tolerations

通过kubectl工具或单击对应工作负载后的“更多 > 编辑YAML”,检查工作负载上是不是设置了容忍度,具体请参见污点和容忍度

排查项三:是否满足停止驱逐实例的条件

若属于小规格的集群(集群节点数小于50个节点),如果故障的节点大于总节点数的55%,实例的驱逐将会被暂停。此情况下Kubernetes将不再尝试驱逐故障节点的工作负载,具体请参见节点驱逐速率限制

排查项四:容器与节点上的“资源分配量”是否一致

容器被驱逐后还会频繁调度到原节点。

问题原因:

节点驱逐容器是根据节点的“资源使用率”进行判断;容器的调度规则是根据节点上的“资源分配量”进行判断。由于判断标准不同,所以可能会出现被驱逐后又再次被调度到原节点的情况。

解决方案:

遇到此类问题时,请合理分配各容器的资源分配量即可解决。

排查项五:工作负载实例不断失败并重新部署

工作负载实例出现不断失败,不断重新部署的情况。

问题分析:

pod驱逐后,如果新调度到的节点也有驱逐情况,就会再次被驱逐;甚至出现pod不断被驱逐的情况。

如果是由kube-controller-manager触发的驱逐,会留下一个状态为Terminating的pod;直到容器所在节点状态恢复后,pod才会自动删除。如果节点已经删除或者其他原因导致的无法恢复,可以使用“强制删除”删除pod。

如果是由kubelet触发的驱逐,会留下一个状态为Evicted的pod,此pod只是方便后期定位的记录,可以直接删除。

解决方案:

使用如下命令删除旧驱赶的遗留:

kubectl get pods <namespace> | grep Evicted | awk '{print $1}' | xargs kubectl delete pod <namespace> 

<namespace>为命名空间名称,请根据需要指定。