bigywater.tech
Kubernetes · 81

节点心跳:Lease 与 NodeStatus

节点是怎么告诉控制面“我还活着”的?Lease 和 Node status 有什么分工?kubelet 停了多久才会被标成 NotReady?这篇在真集群里观察 Lease 的续约节奏、对比 Node 对象的更新频率,再停掉 kubelet 看超时判定。

10 次 vs 1 次
100 秒内 Lease 与 Node 对象各自被更新的次数
~10 秒
Lease 的 renewTime 续约间隔
48 秒
停掉 kubelet 后 Ready 变成 NodeStatusUnknown 的用时

Lease:专用心跳

实测 · 本机执行输出
  Lease kx-main-worker2(命名空间 kube-node-lease):holderIdentity=kx-main-worker2;leaseDurationSeconds=40;ownerReferences=[('Node', 'kx-main-worker2')]
  所有节点的 Lease:['kx-main-control-plane', 'kx-main-worker', 'kx-main-worker2']
  观察 65 秒:renewTime 变了 6 次,相邻两次间隔(秒)[10.0, 10.1, 10.3, 10.1, 10.3, 10.2](≈ 10 秒一次)
  同一节点 Ready 条件:lastHeartbeatTime=2026-10-10T17:04:43Z,距现在 258 秒;lastTransitionTime 距现在 32717 秒

kube-node-lease 命名空间里每个节点一个 Lease,名字就是节点名。worker2 的 Lease:holderIdentity=kx-main-worker2,leaseDurationSeconds=40,ownerReferences 指向 Node。观察 65 秒,renewTime 变了 6 次,间隔 10.0、10.1、10.3、10.1、10.3、10.2 秒——约 10 秒一次。

Node status 慢得多

实测 · 本机执行输出
  100 秒内:Node 对象的 resourceVersion 变了 1 次;Lease 的 resourceVersion 变了 10 次(≈ 每 10 秒)
  Ready 条件的 lastHeartbeatTime 在这 100 秒里出现过 2 个不同值(从 17:04:43 开始)——Node status 在没变化时每 5 分钟才更新一次

同样 100 秒,Lease 的 resourceVersion 变了 10 次,而 Node 对象本身只变了 1 次:Ready 条件的 lastHeartbeatTime 出现了 2 个不同值(从 17:04:43 开始,到约 300 秒时才刷新)。没有状态变化时,Node status 每 5 分钟才更新一次。把“我还活着”的高频信号放进只有几十字节的 Lease,避免了频繁改写大体积的 Node 对象,节点多时对 etcd 压力差别很大。

心跳停了

实测 · 本机执行输出
  最后一次 renewTime=17:10:33;停掉 kubelet 之后:Ready 变成 NodeStatusUnknown 用了 48 秒(message:Kubelet stopped posting node status.);出现污点 [('node.kubernetes.io/unreachable', 'NoSchedule')] 用了 47 秒
  此时 Lease 的 renewTime 仍停在 17:10:33(没有再更新)
  重新启动 kubelet:5 秒后 Ready=True 且污点被清除;Lease renewTime=17:11:29

停掉 worker2 的 kubelet:最后一次 renewTime 是 17:10:33,此后 Lease 不再更新。47 秒时出现污点 node.kubernetes.io/unreachable:NoSchedule,48 秒时 Ready 条件变成 NodeStatusUnknown,message 是 Kubelet stopped posting node status.——这是约 40 秒的节点监控宽限期加检查周期。重新启动 kubelet,5 秒后 Ready=True,污点被清除。(驱逐 Pod 的时间线见下一篇。)

Lease 归 kubelet 管

实测 · 本机执行输出
  kubectl delete lease kx-main-worker2:5.7 秒后 kubelet 又把它建回来(新 uid,holderIdentity=kx-main-worker2);节点 Ready=True

kubectl delete lease kx-main-worker2:5.7 秒后 kubelet 又把它建回来,新 uid,holderIdentity 不变,节点 Ready 没受影响。Lease 是 kubelet 持有的对象,手动删除/修改会和控制器的假设冲突。

分步演示

心跳
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0),观察对象是 worker2;renewTime 与 resourceVersion 每 0.5~1 秒轮询一次;“48 秒”是 systemctl stop kubelet 起到 Ready 条件不再是 True 的用时,单次测量;每种情形各一次(第二节中的 5 分钟周期是由 lastHeartbeatTime 的两次取值推出的,不是等了完整 5 分钟)
    • 没有验证:node-monitor-grace-period、nodeStatusUpdateFrequency、nodeStatusReportFrequency 的参数调整;NoExecute 污点与 Pod 驱逐(下一篇);控制面节点的心跳;大规模集群的 etcd 写入量对比;Lease 为什么在 Node 上有 ownerReference 的 GC 行为
    京ICP备2026067502号-1京公网安备11010502063487号