Pod被驱逐的信号识别与初步定位
Kubernetes集群中Pod突然消失或重启,驱逐(Eviction)是最常见的原因之一。与CrashLoopBackOff不同,驱逐是Kubelet主动终止Pod的行为,通常与节点资源压力有关。
快速确认Pod是否被驱逐:
# 查看Pod状态,驱逐的Pod会显示Evicted
kubectl get pods -A | grep -i evict
# 查看Pod事件,获取驱逐原因
kubectl describe pod <pod-name> -n <namespace> | grep -A5 "Events"
# 常见的驱逐原因输出示例:
# Node is experiencing pressure: DiskPressure
# The node was low on resource: ephemeral-storage
# The node had condition: [MemoryPressure]
驱逐日志的关键信息在Reason字段:NodeUnderMemoryPressure表示内存不足,NodeUnderDiskPressure表示磁盘空间不足,NodeUnderPIDPressure表示进程ID耗尽。
节点资源压力的分层诊断
驱逐问题排查的第一步是定位哪个资源维度出了问题。Kubelet通过--eviction-hard和--eviction-soft参数配置驱逐阈值,默认值对内存和磁盘都有保护。
# 检查节点资源使用情况
kubectl describe node <node-name> | grep -A20 "Allocated resources"
# 输出示例:
# Allocated resources:
# CPU Requests CPU Limits Memory Requests Memory Limits
# 8.5 (53%) 12 (75%) 14Gi (87%) 16Gi (100%)
# 查看Kubelet的驱逐配置
ssh <node> "cat /var/lib/kubelet/config.yaml" | grep eviction
# 典型输出:
# evictionHard:
# imagefs.available<15%
# memory.available<100Mi
# nodefs.available<10%
# nodefs.inodesFree<5%
# evictionSoft:
# imagefs.available<20%
# memory.available<300Mi
# nodefs.available<15%
# evictionSoftGracePeriod:
# imagefs.available=1m30s
# memory.available=1m30s
# nodefs.available=1m30s
驱逐分硬性和软性两种:硬性驱逐立即执行没有宽限期,软性驱逐会给Pod一个优雅终止的宽限期。生产环境中合理配置软性驱逐可以让应用完成请求处理后再退出。
磁盘压力排查:存储泄漏的常见场景
磁盘压力导致的驱逐在实际运维中占比最高。容器日志、临时文件、镜像层残留是三大元凶。
# 登录节点检查磁盘使用
ssh <node> "df -h /var/lib/kubelet"
ssh <node> "df -h /var/lib/containerd"
# 查看容器日志占用的磁盘空间
ssh <node> "du -sh /var/log/pods/*"
ssh <node> "du -sh /var/log/containers/*"
# 找出磁盘占用最大的Pod
ssh <node> "du -sh /var/log/pods/* | sort -rh | head -10"
解决磁盘压力的短期手段是清理冗余日志和未使用的镜像层。长期方案是配置ContainerLogMaxSize和ContainerLogMaxFiles限制日志文件大小,以及为日志密集型Pod设置emptyDir.sizeLimit。
内存压力排查:OOM与驱逐的边界
内存压力导致的驱逐和OOM Kill是两种不同机制。OOM Kill是内核cgroups层面的行为,驱逐是Kubelet层面。两者都会导致Pod重启,但排查路径不同。
# 区分OOM和驱逐
# OOM Kill: Pod的lastState.terminated.reason = "OOMKilled"
# 驱逐: Pod的status.reason = "Evicted"
# 查看被OOM Kill的Pod
kubectl get pods -A -o json | jq '.items[] |
select(.status.containerStatuses[]?.lastState.terminated?.reason == "OOMKilled") |
{name: .metadata.name, ns: .metadata.namespace}'
# 查看节点内存使用趋势
kubectl top nodes
kubectl top pods -A --sort-by=memory | head -20
# 检查Pod的内存limit设置
kubectl get pods -A -o json | jq '.items[] |
{name: .metadata.name, ns: .metadata.namespace,
containers: [.spec.containers[] |
{name: .name,
memoryLimit: .resources.limits?.memory // "not set",
memoryRequest: .resources.requests?.memory // "not set"}]} | head -50'
一个常见坑:Pod没设置memory limit,运行在共享节点上,当其他Pod吃满内存时,这个无辜Pod可能被优先驱逐——因为Kubelet按QoS等级选择驱逐对象,BestEffort(无request/limit)的Pod最先被驱逐。
资源配额与LimitRange的连锁效应
命名空间级别的ResourceQuota和LimitRange配置不当也会间接导致驱逐。比如LimitRange设置了默认limit但值过高,导致Pod调度到节点后实际内存超出了节点可用量。
# 检查命名空间的ResourceQuota
kubectl get resourcequota -n <namespace> -o yaml
# 检查LimitRange默认值
kubectl get limitrange -n <namespace> -o yaml
# 常见问题:LimitRange设置了过高的默认memory limit
# apiVersion: v1
# kind: LimitRange
# metadata:
# name: default-limits
# spec:
# limits:
# - default:
# memory: 8Gi # 默认limit过高,容易触发驱逐
# defaultRequest:
# memory: 256Mi
# type: Container
合理的做法是根据应用实际内存需求设置limit,为JVM类应用预留堆外内存空间,在ResourceQuota中为系统组件预留buffer。
预防性配置与告警体系
驱逐问题最好的处理方式是预防。几个关键配置:
第一,所有生产Pod必须设置requests和limits,避免BestEffort QoS。第二,配置Pod Disruption Budget保障最小可用副本数。第三,节点预留资源通过kube-reserved和system-reserved参数保障Kubelet和系统进程的资源。
# Kubelet资源预留配置
# /var/lib/kubelet/config.yaml
systemReserved:
cpu: "500m"
memory: "1Gi"
ephemeral-storage: "10Gi"
kubeReserved:
cpu: "500m"
memory: "2Gi"
ephemeral-storage: "5Gi"
enforceNodeAllocatable:
- pods
- system-reserved
- kube-reserved
# 配合Prometheus告警规则
# - alert: NodeMemoryPressure
# expr: kube_node_status_condition{condition="MemoryPressure",status="true"} == 1
# for: 2m
# labels:
# severity: warning
驱逐告警要设置在Kubelet触发驱逐之前,给运维团队足够的时间干预。内存可用量低于500Mi时发Warning,低于200Mi时发Critical——而不是等到Pod已经被驱逐才告警。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/kubernetespod-qu-zhu-gu-zhang-pai-cha-quan-liu-cheng-cong/