首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >节点失联后副本不会马上补上:300 秒容忍与驱逐限速

节点失联后副本不会马上补上:300 秒容忍与驱逐限速

原创
作者头像
一只特立独行的兔先生
发布于 2026-11-13 09:17:58
发布于 2026-11-13 09:17:58
500
举报

一台工作节点失联后,Deployment 不会立刻在其他节点补副本。控制面要先认定节点无响应,再打上 NoExecute 污点;Pod 默认还能再留 300 秒。一批节点一起失联时,污点有速率限制,小集群甚至会停掉驱逐。这几分钟里少掉的是可用容量,不是监控刷新慢。

宽限到了才把节点判失联

kubelet 默认每 10 秒更新一次 kube-node-lease 里、与节点同名的 Lease 的 spec.renewTime。节点 .status 没有变化时默认 5 分钟才写一次,不能拿它判断节点还活着。

--node-monitor-grace-period 当前上游默认 50 秒,--node-monitor-period 默认 5 秒。宽限内没有新续约,Ready 写成 Unknown,污点是 node.kubernetes.io/unreachable:NoExecute,reason 为 NodeStatusUnknown。kubelet 自己报不健康时,Ready 是 False,污点是 node.kubernetes.io/not-ready:NoExecute。两种都要配容忍。控制器改写失联状态时不更新 lastHeartbeatTime,它仍是 kubelet 上次写 status 的时间。

节点状态文档的条件表写 50 秒,同一页心跳一节还留着 40 秒;更早发行版默认也是 40 秒。以该集群 kube-controller-manager 的实际参数为准。

污点打上之后,Pod 默认还能再留 300 秒

NoSchedule 只挡新 Pod。失联污点是 NoExecute,才会删已经绑定的 Pod。

没显式写对应容忍时,准入控制补上这两条,tolerationSeconds 都是 300。参数是 kube-apiserver 的 --default-not-ready-toleration-seconds 和 --default-unreachable-toleration-seconds。计时从匹配污点出现开始,污点先被清掉就不会删。

单节点、污点没排队时,从最后一次成功续约到开始删 Pod,大约是 50 秒加 300 秒,再加最多一个 5 秒检查周期,接近 6 分钟。调度、拉镜像和就绪探针还不在这 6 分钟里。

DaemonSet 也带这两条 key,但没有 tolerationSeconds,表示一直容忍,失联也不驱逐。抄进 Deployment,故障时副本补不上。1.29 起这条路径在 taint-eviction-controller 里,--controllers=-taint-eviction-controller 会把它关掉。300 秒的语义不变。

一批节点一起失联时,后面的要排队

加污点有速率限制,避免分区时把大量 Pod 一起删掉。300 秒从污点打上才开始,排队的节点更晚被删。多可用区时按每个 zone 算;不跨区时 zone 就是整个集群。

参数

默认

含义

--node-eviction-rate

0.1

zone 正常时,大约每 10 秒一个节点

--unhealthy-zone-threshold

0.55

不健康比例

--large-cluster-size-threshold

50

小集群分界;多 zone 时按 zone 内节点数

--secondary-node-eviction-rate

0.01

大集群部分中断时约 100 秒一个节点

部分中断要同时满足:NotReady 多于 2 个,且比例达到 0.55。

  • zone 里还有 Ready 节点,且不满足上面两条:正常,速率 0.1。
  • 部分中断,且该 zone 节点数不超过 50:速率为 0,不驱逐。超过 50:降到 0.01。
  • 该 zone 没有 Ready 节点,但别的 zone 还正常:按 0.1 迁走整个 zone。
  • 所有 zone 都没有 Ready 节点:认为是控制面到节点的连通性问题,停止驱逐。当前上游控制器进入这个状态时,还会尝试清掉这两类污点。

4 个节点的单 zone、3 个 NotReady:超过 2 个,比例 0.75,节点数不超过 50,速率是 0。剩下的健康节点不会收到迁来的副本。3 个节点里只有 2 个 NotReady,还没越过「多于 2 个」,仍按 0.1。单 zone 的 3 个节点全不健康,属于所有 zone 都中断,同样不驱逐;若这 3 个只是多 zone 集群里的一个 zone,而别处还有 Ready 节点,则按 0.1 迁走。

入口摘了后端,不等于副本已经补上

TKE 默认把 Service 后端配到节点 NodePort。Service Controller 不把 NotReady 节点挂上去;Unschedulable 的节点仍可以挂,封锁不会自动摘掉。CLB 上这个后端消失,只说明新流量不再从这条 NodePort 路径进该节点,不表示 Pod 已在其他节点重建。直连 Pod 的后端是 Pod 地址,不要套用这句。

节点宕机时,缺口持续到驱逐发生且新 Pod 就绪。网络分区时,API 里已经删除的 Pod,kubelet 在通信恢复前收不到,进程可能还在旧节点上跑。没有选主或 fencing 的写入,会出现旧进程还在写、新 Pod 也起来了的窗口。全集群被看成不可达时则不驱逐,新副本也不会建。

Deployment 在旧 Pod 进入删除后就按期望副本数补新的,不用等进程退出。StatefulSet 同一序号要等旧 Pod 从 API 消失才重建。kubelet 不在时优雅期限跑不完,对象可能停在 Terminating,这会卡住 StatefulSet。

缩短容忍要两条一起写

无状态且副本已跨节点的服务,可以把容忍写短。两条都要显式写。只写 not-ready 时,unreachable 仍会被补成 300 秒,心跳丢失走的正是这一条。

代码语言:yaml
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: checkout
  namespace: prod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: checkout
  template:
    metadata:
      labels:
        app: checkout
    spec:
      tolerations:
      - key: node.kubernetes.io/not-ready
        operator: Exists
        effect: NoExecute
        tolerationSeconds: 60
      - key: node.kubernetes.io/unreachable
        operator: Exists
        effect: NoExecute
        tolerationSeconds: 60
      containers:
      - name: checkout
        image: example.com/checkout:1.8.0

tolerationSeconds: 0 表示污点一出现就删。宽限只有几十秒,控制面短暂卡住也可能让 Lease 续不上,再叠 0 秒就会全量重建。有本地数据或靠选主的服务不要改成 0。

PDB 挡不住节点失联这类非自愿中断,但被删的 Pod 仍计入预算,同时进行的 kubectl drain 可能被拒绝。这和排水卡在 PDB 不是同一条路径。

用对象状态验收

节点名换成实际值。tolerationSeconds 打印成空是无限容忍,不是 0。控制器改写失联时,Ready 的 reason 应为 NodeStatusUnknown。

代码语言:bash
复制
kubectl get node 10.0.0.12 -o jsonpath='{.status.conditions[?(@.type=="Ready")].reason} {.status.conditions[?(@.type=="Ready")].lastHeartbeatTime}'
echo
kubectl get lease -n kube-node-lease 10.0.0.12 -o jsonpath='{.spec.renewTime}'
echo
kubectl get pod -n prod -l app=checkout -o jsonpath='{range .items[*]}{.metadata.name} {range .spec.tolerations[*]}{.key}={.tolerationSeconds};{end}{end}'
echo

驱逐开始后才有 deletionTimestamp,DisruptionTarget 的 reason 为 DeletionByTaintManager。在这之前 readyReplicas 偏低是正常窗口;该字段为 0 时经常被省略,打出来是空的,不是命令失败。

代码语言:bash
复制
kubectl get pod -n prod -l app=checkout -o jsonpath='{range .items[*]}{.metadata.name} {.metadata.deletionTimestamp} {.status.conditions[?(@.type=="DisruptionTarget")].reason} {end}'
echo
kubectl get deploy -n prod checkout -o jsonpath='{.spec.replicas} {.status.readyReplicas}'
echo

大面积 NotReady 却长时间没有 unreachable 污点,先对照停驱逐条件,不要先改业务重启策略。

上线前对一下

  • 两条 NoExecute 要么写了秒数,要么接受默认 300 秒的容量缺口。
  • 业务 Deployment 没有抄 DaemonSet 那种不带 tolerationSeconds 的写法。
  • 副本跨了节点。小集群里 NotReady 达到 3 个且比例不低于 0.55 时,可能停驱逐。
  • 有写入的服务有选主或 fencing,不依赖「API 删了进程就停」。
  • 告警看 Lease 的 renewTime 和 readyReplicas,不要要求节点一红就在 10 秒内补齐。

参考文档:Taints and Tolerations、Nodes、Node Status、Disruptions、TKE Service 后端选择。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 宽限到了才把节点判失联
  • 污点打上之后,Pod 默认还能再留 300 秒
  • 一批节点一起失联时,后面的要排队
  • 入口摘了后端,不等于副本已经补上
  • 缩短容忍要两条一起写
  • 用对象状态验收
  • 上线前对一下
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档