4. Kubelet 心跳上报原理:NodeLease 机制、NodeStatus 更新与节点状态转换

Kubelet 通过两种并行的机制向 API Server 报告节点健康状态:NodeLease(轻量心跳) 和 NodeStatus(全量更新)。理解这两者的区别、协作方式以及超时阈值,是诊断“证书轮换导致心跳上报失败”这类故障的理论基础。

4.1 双轨心跳机制概览

Kubernetes 自 v1.13 起引入了 NodeLease API(coordination.k8s.io/v1),将心跳与节点状态更新解耦,大幅降低了大规模集群中频繁更新 NodeStatus 带来的 etcd 压力。

对比维度 NodeLease(轻量心跳) NodeStatus(全量更新)
API 资源 Lease(coordination.k8s.io/v1) Node(v1)
更新频率 默认每 10 秒(node-status-update-frequency 的 1/5) 默认每 1 分钟(node-status-update-frequency)
数据量 极小(仅含 Lease 对象、续约时间戳) 大(包含节点条件、容量、镜像、IP 等全部状态)
主要用途 快速检测节点存活(心跳) 同步节点完整状态(调度决策依据)
证书依赖 需要有效的 kubelet 客户端证书 需要有效的 kubelet 客户端证书
关键认知: 证书轮换失败时,NodeLease 续约会最先中断,因为它的更新频率更高、对 API Server 的请求更密集。NodeStatus 更新虽然频率低,但一旦失败,节点状态会从 Ready 逐步转换为 NotReady。

4.2 NodeLease 机制详解

每个节点在 kube-node-lease 命名空间中拥有一个同名的 Lease 对象。Kubelet 定期(默认 10s)通过 PATCH 请求更新该 Lease 的 spec.renewTime 字段,作为“我还活着”的信号。

# 查看节点 lease 对象示例
kubectl get lease -n kube-node-lease node-1 -o yaml

apiVersion: coordination.k8s.io/v1
kind: Lease
metadata:
  name: node-1
  namespace: kube-node-lease
spec:
  holderIdentity: node-1
  leaseDurationSeconds: 40          # 租约有效期,默认 40s
  renewTime: "2025-03-20T08:15:30Z" # 最近一次续约时间
  acquireTime: "2025-03-20T08:00:00Z"
  leaseTransitions: 0
  • leaseDurationSeconds:默认 40 秒。如果超过该时间未收到续约,控制器认为节点心跳丢失。
  • renewTime:Kubelet 每次续约时更新此时间戳。
  • 更新方式:Kubelet 使用 PATCH /apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/node-1,仅更新 renewTime 字段,负载极小。
故障排查提示: 证书轮换失败后,检查 kube-node-lease 命名空间中对应节点的 Lease 对象的 renewTime 是否停滞。如果停滞时间超过 leaseDurationSeconds(默认 40s),说明心跳已中断。

4.3 NodeStatus 更新机制

NodeStatus 更新是 Kubelet 向 API Server 发送完整节点状态(包括 Ready、MemoryPressure、DiskPressure、PIDPressure 等条件)的 PUT 请求。默认每 60 秒执行一次。

# NodeStatus 中的核心条件字段
status:
  conditions:
  - type: Ready
    status: "True"          # True / False / Unknown
    lastHeartbeatTime: "2025-03-20T08:15:30Z"
    lastTransitionTime: "2025-03-20T08:00:00Z"
    reason: KubeletReady
    message: "kubelet is posting ready status"
  - type: MemoryPressure
    status: "False"
    ...
  • 更新频率:由 --node-status-update-frequency 控制,默认 60s。
  • 更新方式:Kubelet 使用 PUT 请求替换整个 status 子资源,数据量远大于 Lease。
  • 证书要求:需要 kubelet 客户端证书对 API Server 进行身份认证。证书轮换失败时,PUT 请求会被 401/403 拒绝。

4.4 心跳超时阈值与节点状态转换

节点状态转换由 Node Controller(运行在 kube-controller-manager 中)驱动,它同时监控 Lease 和 NodeStatus 的更新情况。

节点状态转换流程(基于心跳超时) Ready (True) Lease 超时 40s Unknown NodeStatus 超时 60s NotReady 超时参数说明 • node-monitor-period: 5s (控制器检查间隔) • node-monitor-grace-period: 40s (Lease 超时宽限期) • pod-eviction-timeout: 5m (NotReady 后驱逐 Pod 等待时间) • 证书轮换失败 → 401/403 → 心跳请求被拒绝 → 节点状态转换

节点状态转换的完整时间线如下:

  1. Lease 续约中断(证书失效后 10s 内):Kubelet 无法 PATCH Lease,renewTime 停滞。
  2. Lease 超时(约 40s 后):Node Controller 检测到 Lease 过期,将节点条件 Ready 置为 Unknown。
  3. NodeStatus 更新失败(约 60s 后):Kubelet 无法 PUT NodeStatus,控制器确认节点失联。
  4. 节点状态转为 NotReady(约 60s + 5s 控制器周期):Node Controller 将 Ready 条件置为 False,状态变为 NotReady。
  5. Pod 驱逐开始(默认 5 分钟后):如果节点持续 NotReady,kube-controller-manager 开始驱逐该节点上的 Pod。
证书轮换故障的典型表现: 在集群事件中会看到 NodeHasSufficientMemory、NodeHasNoDiskPressure 等条件正常,但 Ready 条件变为 Unknown 或 False。同时 kubelet 日志中出现 Unauthorized 或 certificate has expired 错误。此时 Lease 对象的 renewTime 会停留在证书过期前的最后成功续约时间。

4.5 证书轮换对心跳路径的影响

Kubelet 使用 TLS 客户端证书 向 API Server 发起所有请求,包括 Lease 续约和 NodeStatus 更新。证书轮换流程如下:

  • 正常轮换:Kubelet 在证书到期前向 API Server 发起 CSR,获取新证书,自动加载并继续使用新证书发送心跳。
  • 轮换失败场景:
    • CSR 被拒绝(RBAC 权限不足)
    • 证书签名服务不可用(kube-controller-manager 故障)
    • 新证书未及时下发(网络延迟或 etcd 性能问题)
    • Kubelet 未正确加载新证书(文件权限或路径错误)

一旦证书失效,Kubelet 对 API Server 的所有请求都会返回 401 Unauthorized 或 403 Forbidden,导致 Lease 和 NodeStatus 更新同时失败。

排查命令速查:
kubectl get lease -n kube-node-lease <node-name> -o jsonpath='{.spec.renewTime}' — 检查最后续约时间
kubectl get node <node-name> -o jsonpath='{.status.conditions[?(@.type=="Ready")]}' — 查看节点 Ready 条件
journalctl -u kubelet -n 50 --no-pager | grep -i "certificate\|unauthorized\|renew" — 查看 kubelet 日志中的证书相关错误