bigywater.tech
Kubernetes · 37

节点压力驱逐:谁先被驱逐

节点内存吃紧时 kubelet 会驱逐 Pod,但谁先走?这篇把工作节点的内存阈值调高,让四个不同 QoS、不同 requests 的 Pod 同时占内存,看 kubelet 真正驱逐了谁、message 里怎么解释,以及节点的 MemoryPressure 条件和污点什么时候出现、什么时候消失。

先 a 后 c
a(BestEffort 用 413908Ki,requests 0)与 c(用 311288Ki,requests 50Mi)先后被驱逐
b、d 幸存
用量低于 requests 的 Burstable 与 Guaranteed Pod 始终 Running
20 秒
最后一次驱逐之后 MemoryPressure 还保持的时间(evictionPressureTransitionPeriod)

制造压力

实测 · 本机执行输出
  把工作节点 kubelet 的 evictionHard.memory.available 设成 6851Mi(比当时的可用量少 900 MiB)、evictionPressureTransitionPeriod 设成 20s,重启 kubelet;重启后 MemoryPressure=False
  a-besteffort   BestEffort,将占 400 MiB,没有 requests
  b-burst-under  Burstable,将占 400 MiB,requests 500 MiB(用量低于 requests)
  c-burst-over   Burstable,将占 300 MiB,requests 50 MiB(用量超出 requests 250 MiB)
  d-guaranteed   Guaranteed,将占 300 MiB,requests = limits = 400 MiB
  四个 Pod 都在 Running、还没有分配内存时 memory.available = 7695 MiB(阈值 6851);同时对四个 Pod 执行 touch /tmp/go,它们各自分配 400 / 400 / 300 / 300 MiB(合计 1400 MiB,会越过阈值)

kind 写进 kubelet 配置的 evictionHard 只有三个磁盘类阈值(都是 0%),没有 memory.available,而 Docker 虚拟机有 8GB 内存,一般的实验压不到。这里把工作节点 kubelet 的 evictionHard.memory.available 设成 6851Mi(比当时的可用量 7752 MiB 少 900 MiB)并重启 kubelet,再让四个已经就绪的 Pod 同时分配内存:a BestEffort 400 MiB,b Burstable 400 MiB(requests 500 MiB),c Burstable 300 MiB(requests 50 MiB),d Guaranteed 300 MiB(requests = limits = 400 MiB)。memory.available 是节点容量减去节点 cgroup 的工作集。

谁先走

实测 · 本机执行输出
  + 10.3s a-besteffort   phase=Failed reason=Evicted
  + 12.6s c-burst-over   phase=Failed reason=Evicted
  节点 memory.available 每隔约 5 秒的采样(MiB):7695, 7695, 6694, 7008, 7008, 7008, 7008, 7008(阈值 6851)

可用内存从 7695 MiB 掉到 6694 MiB(低于阈值)。+10.3 秒 a 被驱逐,+12.6 秒 c 被驱逐,之后可用内存回到 7008 MiB,压力解除。b(实际用 400 MiB,低于 requests 500 MiB)和 d(用 300 MiB,低于 requests 400 MiB)全程没被动。规律:用量超过 requests 的 Pod 最先被驱逐,其中超出得多的更靠前;没超出的、尤其是 Guaranteed,留到最后。kubelet 一次只驱逐一个,再看有没有回到阈值之上。

驱逐留下的信息

实测 · 本机执行输出
  a-besteffort:phase=Failed reason=Evicted;STATUS 列=Error
    message=The node was low on resource: memory. Threshold quantity: 6851Mi, available: 6676700Ki. Container c was using 413908Ki, request is 0, has larger consumption of memory. 
  c-burst-over:phase=Failed reason=Evicted;STATUS 列=Error
    message=The node was low on resource: memory. Threshold quantity: 6851Mi, available: 6854264Ki. Container c was using 311288Ki, request is 50Mi, has larger consumption of memory. 
  没有被驱逐的(仍在 Running):['b-burst-under', 'd-guaranteed']

被驱逐的 Pod phase=Failed、reason=Evicted(STATUS 列显示 Error),对象还在,要靠控制器另建新 Pod 或者自己清理。message 写得很具体:The node was low on resource: memory. Threshold quantity: 6851Mi, available: 6676700Ki. Container c was using 413908Ki, request is 0, has larger consumption of memory.——阈值、当时的可用量、容器用量、requests 都在里面,这是排查“Pod 为什么被驱逐”的第一手资料。

节点上的变化

实测 · 本机执行输出
  第 8 秒 MemoryPressure 变成 True,同时节点出现污点 ['node.kubernetes.io/memory-pressure:NoSchedule']
  最后一次越过阈值大约在第 13 秒(最后一次驱逐);MemoryPressure 在第 40 秒回到 False(evictionPressureTransitionPeriod=20s,压力消失后条件还要保持 20 秒);此时 taints=[]

第 8 秒节点的 MemoryPressure 变成 True,同时出现污点 node.kubernetes.io/memory-pressure:NoSchedule;最后一次驱逐在第 13 秒,但条件到第 40 秒才回到 False——evictionPressureTransitionPeriod 设成 20 秒,压力消失后条件还要保持 20 秒,避免在阈值边缘来回抖动。

这个脚本更早的几次不干净的运行里还见到过三种现象,没有放进上面的结论:同时创建的 Pod 因为还没有统计数据被优先驱逐(一个 Guaranteed Pod 最先被驱逐,message 里没有容器用量);统计每 10 秒才刷新,两个都超出 requests 的 Pod 的先后在不同运行里互换过;重启 kubelet 时 BestEffort Pod 因节点有 MemoryPressure 条件被准入拒绝(Pod was rejected: The node had condition: [MemoryPressure])。

分步演示

节点压力驱逐
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。独立的两节点 kind 集群 kx-evict(1 控制面 + 1 工作节点,Kubernetes v1.37.0),实验后删除;kubelet 配置在工作节点里改 /var/lib/kubelet/config.yaml 后重启 kubelet;节点 memory.available 取自 /api/v1/nodes//proxy/stats/summary;Python 容器(python:3.12-alpine)在 /tmp/go 出现之前一直待命,出现后分配指定大小的内存(b"x" * N);状态用每秒一次的轮询得到;每种情形各一次,时间每次运行不同
    • 没有验证:压力期间新 Pod 的调度行为(一次尝试里,污点已出现时新建的 BestEffort 和 Burstable Pod 都被调度并运行了,与文档说的 memory-pressure 污点语义不符,原因没有查清,所以这里没有下结论);evictionSoft 与 evictionSoftGracePeriod;磁盘类阈值(nodefs/imagefs,下一篇之后的 ephemeral-storage 一文);Pod 优先级对排序的影响;max-pod-grace-period 对驱逐的影响;内核 OOM 与 kubelet 驱逐谁先发生的竞争
    京ICP备2026067502号-1京公网安备11010502063487号