
K8s Pod 驱逐链分析内存压力、磁盘压力与进程 OOM 的关系一、Pod 被驱逐了但节点内存还很充足排查过这样一个问题节点显示 16GB 内存只用了 10GB但 Pod 还是被驱逐了。看日志发现EvictionThreshold被触发——Kubelet 为了防止节点资源耗尽在内存达到某个阈值时会主动驱逐 Pod。这和进程 OOM 是两套机制驱逐EvictionKubelet 层面的保护主动杀 Pod给集群调度留出反应时间OOM KillLinux 内核层面的保护被动杀进程没有调度缓冲所以 Pod 被驱逐时节点内存不一定满了——可能只是触发了软驱逐阈值。flowchart TD A[节点资源监控] -- B{资源压力检测} B --|内存| C[Memory Available EvictionSoft?] C --|是| D[进入宽限期 grace period] C --|否| E[正常运行] B --|磁盘| F[NodeFS Available 10%?] F --|是| G[立刻驱逐] F --|否| E D -- H{宽限期内恢复?} H --|是| E H --|否| I[硬驱逐触发] I -- J[驱逐排序] J -- K[PriorityClass 最低的先驱] J -- L[QoS: BestEffort Burstable] J -- M[超出 Request 最多的先驱] G -- J K L M -- N[Pod 被驱逐] N -- O[调度到其他节点]二、驱逐的三个关键阈值软驱逐Soft EvictionevictionSoft: memory.available: 500Mi nodefs.available: 10% evictionSoftGracePeriod: memory.available: 1m30s nodefs.available: 2m节点可用内存低于 500Mi 时Kubelet 给 90 秒的宽限期。宽限期内如果资源恢复不驱逐。这给应用程序内存释放或垃圾回收争取时间。硬驱逐Hard EvictionevictionHard: memory.available: 200Mi nodefs.available: 5%直接驱逐不给宽限期。这是最后的防线。OOM Killer vs Kubelet Eviction触发者粒度行为后果Kubelet EvictionPod 级别删除 Pod API 对象Pod 重新调度Linux OOM Killer进程级别发送 SIGKILL容器 restart关键区别Kubelet 驱逐后 Pod 会调度到其他节点OOM Kill 后容器在本节点重启。如果你的服务没有做优雅下线graceful shutdown驱逐可能比 OOM Kill 更糟——因为连接彻底断了。三、Pod 驱逐优先级的生产配置apiVersion: v1 kind: Pod metadata: name: high-priority-service spec: # PriorityClass 决定驱逐顺序 # 数字越小越先被驱逐 # system-cluster-critical 2000000000 的不会被驱逐 priorityClassName: high-priority containers: - name: app image: myapp:v2 resources: # requests 和 limits 的设置直接决定 QoS 等级 # QoS 等级决定驱逐顺序: Guaranteed Burstable BestEffort requests: memory: 512Mi cpu: 500m limits: memory: 512Mi # 与 request 一致 → Guaranteed QoS cpu: 1000m # 内存压力下的行为——这个配置往往被忽视 env: - name: NODE_OPTIONS value: --max-old-space-size400 # 略小于 limit留出 overhead --- apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 globalDefault: false description: 核心服务最后被驱逐QoS 等级与驱逐顺序BestEffort最先被驱逐没有设置任何 requests/limitsBurstable中等requests limitsGuaranteed最后被驱逐requests limits且所有容器都设置Kubelet 在驱逐时会计算每个 Pod 的驱逐分数驱逐分数 (memory_usage - memory_request) / memory_request分数越高的 Pod 越先被驱逐——这确保了超出 request 最多的 Pod 先被清理。四、常见误区与定位方法误区一limit 2Gi 就不会 OOMlimit 只限制容器的 cgroup 内存上限。应用还有 JVM 堆外内存、glibc malloc、page cache——这些也在 limit 范围内但不可控。正确的做法是 limit 至少比 request 大 20%预留 overhead。误区二驱逐只发生在内存不够时磁盘压力nodefs.available和 inode 压力nodefs.inodesFree也会触发驱逐。特别是 Docker 镜像存储和容器日志会快速消耗 nodefs 空间。定位驱逐原因# 查看节点状态——条件字段显示驱逐原因 kubectl describe node node-name | grep -A5 Conditions # 查看 Kubelet 日志中的驱逐事件 journalctl -u kubelet | grep -i evict # 查看被驱逐的 Pod 状态 kubectl get events --all-namespaces | grep Evicted五、总结驱逐是 K8s 自我保护机制中最容易被误解的一层。关键记住三点驱逐阈值可以配置、驱逐顺序由 QoS PriorityClass 决定、驱逐和 OOM Kill 是两层保护。避免驱逐的最佳策略不是提高 limit而是给每个 Pod 精确设置 request——request 越精确Kubelet 越不容易误判节点资源紧张。