20、K8S-Pod驱逐
文章目录一、Pod驱逐1、为什么要有驱逐2、驱逐机制3、Pod evictionPod 驱逐3.1、resource 的 requests 和 limits3.2、QoS 类别3.3、PriorityClass 和 Priority二、Pod驱逐实战案例1、k8s pod内存驱逐问题解决1.1、查看pod状态1.2、查看pod事件日志1.3、排查节点内存监控1.4、思考内存驱逐的原理配置案例核心概念驱逐信号Eviction Signals与阈值Thresholds案例一基础驱逐配置案例二为系统守护进程预留资源案例三仅使用软驱逐阈值实现平滑处理案例四高级镜像垃圾收集策略最佳实践与总结一、Pod驱逐1、为什么要有驱逐pod.spec.containers[].resources中会存在cpu或memory的request和limit。即该pod请求的最小资源和Node结点可以给的最大资源。当一个容器的cpu使用率超过limit时会被进行流控而当内存超过limit时则会被oom_kill。完全依赖于oom_kill并不是一个很好的方案一来对于cpu要求高的容器没有作用二来单纯将pod杀死并不能根本上解决困局比如pod占用node绝大部分内存假如pod被kill后再次调度到这个node上oom的情况还会复现。所以kubelet增加了一套驱逐机制。eviction中要设置触发驱逐的阈值Eviction Thresholds这个阈值的配置可以是一个定值或一个百分比。如memory.available10% memory.available1Gi2、驱逐机制Soft Eviction Thresholds软驱逐机制当node的内存/磁盘空间达到一定的阈值后我要观察一段时间如果改善到低于阈值就不进行驱逐若这段时间一直高于阈值就进行驱逐。Hard Eviction Thresholds 强制驱逐机制简单的多一旦达到阈值立刻把pod从本地kill。3、Pod evictionPod 驱逐当资源使用情况触发了驱逐条件时kubelet会启动一个任务去轮流停止运行中的pod直到资源使用状况恢复到阈值以下。以硬驱逐为例整体流程是每隔一段时间从cadvisor中获取资源使用情况发现触发了阈值从运行中的pod里找到QoS策略最开放的一个比如策略为bestEffort的一个pod即便这个pod没有吃多少内存大部分内存是另一个策略为burstable但内存使用率也很高的podkubelet停止该pod对应的所有容器然后将pod状态更新为Failed。如果该pod长时间没有被成功kill掉kubelet会再找一个pod进行驱逐。检查内存用量是否恢复到阈值以下如果没有则重复第二步这里就要干掉那个罪魁祸首了。一直到内存使用情况恢复到阈值以下为止。在 Kubernetes 中当资源不足需要驱逐 Pod 时系统会根据 Pod 的优先级由 PriorityClass 的 value 决定和 Pod 的 Quality of Service (QoS) 类别等进行决策。而调度优先级主要由 Priority 值确定。3.1、resource 的 requests 和 limitsRequests请求Requests 是指容器在运行时所需的资源的最小数量。它们用于告诉 Kubernetes 调度器在选择节点时要为 Pod 预留多少资源。如果没有足够的请求资源可用Pod 可能无法被调度到节点上。Limits限制Limits 是指容器在运行时所允许使用的资源的最大数量。它们用于限制容器的资源使用以防止容器占用过多的资源导致其他容器或节点受到影响。如果容器尝试使用超过其限制的资源量Kubernetes 将会限制其资源使用并可能触发容器的重新启动。3.2、QoS 类别BestEffort没有设置 resource requests 和 limits 的 Pod。Burstable设置了 requests 或者 limits但不完全相同。Guaranteedrequests 和 limits 都设置了并且两者值相等。驱逐顺序BestEffort(lowest) - Burstable - Guaranteed(highest)。不影响调度的优先级。3.3、PriorityClass 和 PriorityPriorityClass优先级类PriorityClass 是一种用于调度和优先级管理的对象。它允许您为 Pod 分配优先级。PriorityClass 定义了一个优先级类别其中包含一个整数值 value 表示优先级的相对值。较高的 value 值表示较高的优先级。通过将 Pod 与特定的 PriorityClass 关联可以影响 Pod 的调度和驱逐顺序。Priority优先级Priority 是一个整数值直接应用于 Pod 对象。它表示 Pod 的绝对优先级。较高的 Priority 值表示较高的优先级。同样可以影响 Pod 的调度和驱逐顺序。查看 PriorityClasskubectl get priorityclasses查看系统组件 controller-manager 使用的 PriorityClass[rootk8s-master ~]# kubectl describe pod -n kube-system kube-controller-manager-k8s-master | grep -i priority Priority: 2000001000 Priority Class Name: system-node-critical当集群中没有默认的 PriorityClass也没有手动指定 Priority那优先级的值就为 0。优先级的值越小驱逐顺序越靠前调度顺序越靠后。还有一种情况是尽管 PriorityClass 的 value 值大但是 BestEffort 类型的 qos class 会比Burstable 或 Guaranteed 类别更容易被驱逐。当然还会有其他因素也会影响 pod 的驱逐顺序但是影响力不如上面两种大例如Pod资源使用量越接近 limits和 pod 运行时长越短等那么这些 Pod 会被优先考虑驱逐。当集群内有比较重要的服务时可以把 Qos Class 设置为 Guaranteed也就是都指定了 requests 和 limits 并且二者值相等会有长时间运行稳定性的优势。且 Priority 的值尽可能设置大些会有优先占用集群资源资源的优势。在K8s 1.6之后还引入了Taint的两个新特性TaintNodesByCondition与TaintBasedEvictions用来改善出现异常时对Pod的调度与驱逐问题TaintNodesByCondition特性如下为节点添加NoSchedule的污点Node节点会不断的检查Node的状态并且设置对应的Condition不断地根据Condition的变更设置对应的Taint不断地根据Taint驱逐Node上的Pod主要污点如下:node.kubernetes.io/not-ready 节点未就绪节点Ready为Falsenode.kubernetes.io/unreachable 节点不可达node.kubernetes.io/out-of-disk 磁盘空间已满node.kubernetes.io/network-unavailable 网络不可用node.kubernetes.io/unschedulable 节点不可调度node.cloudprovider.kubernetes.io/uninitialized 如果 kubelet 从 外部 云服务商启动的该污点用来标识某个节点当前为不可用状态当云控制器 cloud-controller-manager 初始化这个节点后kubelet 会将此污点移除TaintBasedEvictions特性添加的是NoExecute的污点例如内存与磁盘有压力时如果Pod没有设置容忍这些污点则会被驱逐以保证Node不会崩溃主要污点如下:node.kubernetes.io/memory-pressure 内存不足node.kubernetes.io/disk-pressure 磁盘不足1.13版本之后TaintNodesByCondition 与 TaintBasedEvictions 都是默认开启二、Pod驱逐实战案例1、k8s pod内存驱逐问题解决**背景**突然收到 web 无法访问告警然后发现前段应用pod状态为Evicted证明pod是被驱逐了排查过程1.1、查看pod状态kubectl get podskubectl get pods-A|grep0/1 web-nginx-865674789f-c7bv40/1 Evicted025hnone192.168.3.10noneweb-nginx-865674789f-ggb270/1 Evicted025hnone192.168.3.10noneweb-nginx-865674789f-fwp940/1 Evicted025hnone192.168.3.10noneweb-nginx-865674789f-djj460/1 Evicted025mnone192.168.3.10none1.2、查看pod事件日志kubectl describe pods web-nginx-xxx从日志上可以看出来是内存不足导致了驱逐Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning Evicted 2m(x1 over 2m)kubelet Thenodewas low on resource:[MemoryPressure].1.3、排查节点内存监控发现利用率在50%没理由会导致内存不足1.4、思考内存驱逐的原理1.4.1 K8S通过kubelet来配置pod的驱逐参数如果没有配置则使用默认值。检查下驱逐阈值。# 硬性驱逐条件evictionHard: memory.available:200Minodefs.available:10%nodefs.inodesFree:5%imagefs.available:15%# 软性驱逐条件evictionSoft: memory.available:300Minodefs.available:15%imagefs.available:20%# 软性驱逐条件的宽限期evictionSoftGracePeriod: memory.available:1mnodefs.available:1mimagefs.available:1m# 驱逐Pod前的最大宽限期evictionMaxPodGracePeriod:60#驱逐开始前等待资源压力状态稳定的时间evictionPressureTransitionPeriod:5m硬性驱逐和软性驱逐的区别硬性驱逐是当资源达到或超过设定的硬性驱逐阈值时Kubelet立即执行驱逐操作。硬性驱逐的特点是直接且无延迟。软性驱逐是在资源使用达到设定的软性驱逐阈值后给Pod一个宽限期Grace Period。如果在宽限期结束后资源使用仍然没有降低Kubelet才会驱逐Pod。1.4.2 查看node可用内存kubectl describe nodeAllocatable: cpu: 15400m ephemeral-storage: 1043358208Ki hugepages-1Gi:0hugepages-2Mi:0memory: 63242364Ki#可分配60G内存pods:253可分配内存为60G而服务器内存为100G和现场同学一线工程师确认问题出现前由于内存占用很高做过一次在线扩容。**故障复盘**故障原因为前期内存资源不足后虚拟机采用在线扩容内存的方式服务器没有重启并且K8S的kubelet服务也没有重启获取到的内存配置仍然是60G所以当主机内存达到60G的时候出现pod由于内存不足产生驱逐。至于监控node-exporter可以动态获取主机物理资源所以过于依赖监控却忽略了检查kubelet。优化方案对node内存和kubelet可分配内存做对比如果相差大于1G则触发告警配置案例好的这里提供一些 Kubernetes Pod 驱逐Eviction参数设置的典型案例。这些参数主要配置在 Kubelet 上用于控制节点资源压力时的驱逐行为。核心概念驱逐信号Eviction Signals与阈值ThresholdsKubelet 监控多种资源信号当这些信号达到设定的阈值时就会触发驱逐。驱逐信号描述memory.available节点可用内存nodefs.available节点根磁盘/可用空间nodefs.inodesFree节点根磁盘/可用 inodeimagefs.available容器运行时存储镜像和可写层的磁盘可用空间imagefs.inodesFree容器运行时磁盘的可用 inodepid.available节点可用进程 ID (PID)案例一基础驱逐配置这是一个最常见的配置案例用于防止节点因内存或磁盘耗尽而完全宕机。kubelet 启动参数通常在/var/lib/kubelet/config.yaml或 systemd 的kubelet.service中配置# /var/lib/kubelet/config.yaml 片段apiVersion:kubelet.config.k8s.io/v1beta1kind:KubeletConfigurationevictionHard:memory.available:500Mi# 可用内存低于500Mi时开始驱逐nodefs.available:10%# 根磁盘可用空间低于10%时开始驱逐nodefs.inodesFree:5%# 根磁盘inode低于5%时开始驱逐imagefs.available:15%# 容器镜像磁盘可用空间低于15%时开始驱逐evictionSoft:memory.available:700Minodefs.available:15%evictionSoftGracePeriod:memory.available:1m30s# 软阈值持续1分30秒后才触发驱逐nodefs.available:2m# 软阈值持续2分钟后才触发驱逐evictionMaxPodGracePeriod:60# 驱逐Pod时允许Pod体面终止的最大宽限期秒evictionPressureTransitionPeriod:30s# 脱离压力状态后需要持续多久才报告状态正常对应 systemd 参数如果使用命令行参数/usr/bin/kubelet\--eviction-hardmemory.available500Mi,nodefs.available10%,nodefs.inodesFree5%,imagefs.available15%\--eviction-softmemory.available700Mi,nodefs.available15%\--eviction-soft-grace-periodmemory.available1m30s,nodefs.available2m\--eviction-max-pod-grace-period60\--eviction-pressure-transition-period30s\...其他参数案例二为系统守护进程预留资源这是强烈推荐的生产环境配置。通过为系统进程和 kubelet 本身预留资源可以防止它们因资源竞争而被饿死从而保证节点的稳定性。kubelet 启动参数# /var/lib/kubelet/config.yaml 片段apiVersion:kubelet.config.k8s.io/v1beta1kind:KubeletConfiguration# 1. 设置驱逐阈值evictionHard:memory.available:500Minodefs.available:10%# 2. 为核心系统预留资源非常重要systemReserved:memory:1Gicpu:500mephemeral-storage:5GikubeReserved:memory:1Gicpu:250mephemeral-storage:1Gi# 3. 强制执行预留策略enforceNodeAllocatable:-pods-system-reserved-kube-reservedsystemReserved: 为操作系统守护进程如 sshd、udev预留的资源。kubeReserved: 为 Kubernetes 系统守护进程如 kubelet、容器运行时预留的资源。enforceNodeAllocatable: 指定 kubelet 需要强制执行哪些预留策略。pods必须包含在内。工作原理节点的总资源 Allocatable可分配给 Pod 的资源 SystemReservedKubeReserved驱逐阈值是基于Allocatable来计算的吗不是驱逐阈值是基于节点的总容量Capacity来监控的。但预留机制确保了系统核心组件有资源可用即使 Pod 已经耗尽了Allocatable部分。案例三仅使用软驱逐阈值实现平滑处理软阈值搭配宽限期可以让 Pod 有机会在被迫驱逐前完成一些清理工作如通知中心、完成当前请求适用于对中断敏感的应用。kubelet 启动参数evictionSoft:memory.available:5%nodefs.available:10%imagefs.available:10%evictionSoftGracePeriod:memory.available:2m# 内存压力持续2分钟后才驱逐nodefs.available:3m# 磁盘压力持续3分钟后才驱逐imagefs.available:3mevictionMaxPodGracePeriod:90# 给予Pod更长的体面终止时间案例四高级镜像垃圾收集策略驱逐经常与镜像磁盘空间不足有关配置积极的镜像垃圾收集可以预防驱逐。kubelet 启动参数# 镜像垃圾收集策略imageGCHighThresholdPercent:85# 当磁盘使用率达到85%时触发镜像GCimageGCLowThresholdPercent:80# GC会一直清理直到使用率降到80%imageMinimumGCAge:2m0s# 镜像必须至少存在2分钟才会被GC清理避免误删正在使用的中间层最佳实践与总结始终设置evictionHard这是防止节点完全宕机的安全网。必须配置systemReserved和kubeReserved这是生产环境的黄金准则能极大提高节点稳定性。预留值大小需根据节点规格和实际系统开销调整。理解软阈值的用途用于需要“优雅驱逐”的场景给应用和运维人员预留反应时间。监控驱逐事件使用kubectl get events -w --field-selector reasonEvicted或监控平台来关注集群中的驱逐事件它们是指标应用资源规划不合理或节点压力过大的重要信号。合理设置 Pod 的requests和limits这是防止 Pod 被驱逐的第一道防线。Kubelet 在决定驱逐哪个 Pod 时会优先驱逐那些实际使用量远超其requests的BurstablePod。使用 Pod 优先级PriorityClass对于关键应用可以创建高优先级的PriorityClass并配置到 Pod 上。这样即使节点压力巨大低优先级的 Pod 也会在高优先级的 Pod 之前被驱逐。通过组合使用这些参数你可以精细地控制 Kubernetes 节点的驱逐行为在保证应用可用性的同时最大限度地维护节点本身的健康与稳定。