bigywater.tech
Kubernetes · 83

cordon 与 drain:被驱逐的 Pod 去了哪

kubectl drain 到底做了什么?为什么总要加一堆 flag?PodDisruptionBudget 怎么让它卡住?uncordon 之后 Pod 会回来吗?这篇在真集群里一步步加 flag、再制造 PDB 阻塞,把输出原样记下来。

3 类拒绝
直接 drain 被拒的三类 Pod:没有控制器的、DaemonSet 管的、带 emptyDir 的
3.1 秒
加全 flag 后 drain 完成的用时
retry after 5s
PDB 阻塞时 drain 的重试间隔,25 秒超时后退出码 1

cordon:只拦新 Pod

实测 · 本机执行输出
  kubectl cordon worker:node/kx-main-worker cordoned
  节点 spec.unschedulable=True;taints=[('node.kubernetes.io/unschedulable', 'NoSchedule')]
  kubectl get nodes:kx-main-control-plane Ready control-plane 9h v1.37 | kx-main-worker Ready,SchedulingDisabled <none> 9h  | kx-main-worker2 Ready <none> 9h v1.37.0
  已有的 Pod 不受影响:{'worker': ['bare', 'dep', 'dep', 'dep', 'ds-dfndg', 'scratch'], 'worker2': ['ds-9dnbz']}
  扩到 5 个副本:新增的 2 个去了哪:{'worker': ['bare', 'dep', 'dep', 'dep', 'ds-dfndg', 'scratch'], 'worker2': ['dep', 'dep', 'ds-9dnbz']}(只能去 worker2)

kubectl cordon 把节点的 spec.unschedulable 设为 true,同时带上污点 node.kubernetes.io/unschedulable:NoSchedule,kubectl get nodes 显示 Ready,SchedulingDisabled。节点上已有的 Pod 不动;把 Deployment 扩到 5 个副本,新增的 2 个只能去 worker2。

drain:一道道拦

实测 · 本机执行输出
  直接 kubectl drain worker:退出码 1;error: unable to drain node "kx-main-worker" due to error: [cannot delete Pods that declare no controller (use --force to override): k77/bare, cannot delete DaemonSet-managed Pods (use --ignore-daemonsets to ignore): k77/ds-dfndg, kube-system/kindnet-bhd99, kube-system/kube-proxy-btrjt, cannot delete Pods with local storage (use --delete-emptydir-data to override): k77/scratch, kube-system/metrics-server-59b55d8c77-b6q9g], continuing command...
  加 --ignore-daemonsets:退出码 1;error: unable to drain node "kx-main-worker" due to error: [cannot delete Pods that declare no controller (use --force to override): k77/bare, cannot delete Pods with local storage (use --delete-emptydir-data to override): k77/scratch, kube-system/metrics-server-59b55d8c77-b6q9g], continuing command...
  再加 --delete-emptydir-data:退出码 1;error: unable to drain node "kx-main-worker" due to error: cannot delete Pods that declare no controller (use --force to override): k77/bare, k77/scratch, continuing command...
  再加 --force:退出码 0,用时 3.1 秒;输出:
    node/kx-main-worker already cordoned
    evicting pod kube-system/metrics-server-59b55d8c77-b6q9g
    evicting pod k77/scratch
    evicting pod k77/bare
    evicting pod k77/dep-5b88b8485b-lqfds
    pod/metrics-server-59b55d8c77-b6q9g evicted
    pod/bare evicted
    pod/scratch evicted
    pod/dep-5b88b8485b-lqfds evicted
    node/kx-main-worker drained
    Warning: deleting Pods that declare no controller: k77/bare, k77/scratch; ignoring DaemonSet-managed Pods: k77/ds-dfndg, kube-system/kindnet-bhd99, ku
  drain 之后各节点上的 Pod:{'worker2': ['dep', 'dep', 'dep', 'ds-9dnbz'], 'worker': ['ds-dfndg']}
  bare(裸 Pod,--force 之后被直接删掉)还在吗:False;scratch(带 emptyDir 的裸 Pod)还在吗:False;dep 的 3 个副本都在 worker2:3 个;DaemonSet 在 worker 上的 Pod 还在:True

直接 kubectl drain 报错,列出三类不能删的:没有控制器的 bare、DaemonSet 管理的(ds、kindnet、kube-proxy)、带本地存储的(scratch、metrics-server)。加 --ignore-daemonsets 后剩两类;再加 --delete-emptydir-data 后只剩没有控制器的 bare 和 scratch;加 --force 才成功,3.1 秒内驱逐了 metrics-server、scratch、bare 和一个 dep Pod。结果是 dep 的 3 个副本都在 worker2,DaemonSet 的 Pod 仍留在 worker 上,bare 和 scratch 被直接删掉,不会重建。

PDB 让 drain 卡住

实测 · 本机执行输出
  PDB dep-pdb:minAvailable=3;当前 healthy=3;disruptionsAllowed=0
  drain worker2(上面有 dep 的 3 个副本):25 秒后退出码 1;输出(去重):
    node/kx-main-worker2 cordoned
    evicting pod kube-system/metrics-server-59b55d8c77-g5mj7
    evicting pod k77/dep-…
    pod/metrics-server-59b55d8c77-g5mj7 evicted
    Warning: ignoring DaemonSet-managed Pods: k77/ds-9dnbz, kube-system/kindnet-bnhqq, kube-system/kube-proxy-bc8wj
    error when evicting pods/"dep-… -n "k77" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
  这时 Pod 仍然在 worker2 上的有:['dep-5b88'],节点已被 cordon:True(drain 失败也不会撤销 cordon)
  删掉 PDB 后重新 drain:退出码 0,用时 4.1 秒;之后 {'worker': ['dep', 'dep', 'dep', 'ds-dfndg'], 'worker2': ['ds-9dnbz']}

PDB dep-pdb(minAvailable: 3,当前 healthy=3)的 disruptionsAllowed 是 0。drain worker2:metrics-server 被驱逐,dep 的 Pod 报 Cannot evict pod as it would violate the pod's disruption budget,drain 每 5 秒重试一次,25 秒超时退出码 1;Pod 仍在 worker2 上,节点却已经被 cordon——drain 失败也不会撤销 cordon。删掉 PDB 后重新 drain,4.1 秒完成。

uncordon

实测 · 本机执行输出
  uncordon 两个节点后:{'worker': ['dep', 'dep', 'dep', 'ds-dfndg'], 'worker2': ['ds-9dnbz']}(Pod 不会自己迁回;需要重建/rollout 才会重新分布)
  worker2 的 spec.unschedulable=None;taints=None

kubectl uncordon 只清除 spec.unschedulable 和污点,Pod 位置不变:worker 上还是 dep ×3 和 ds,worker2 上只有 ds,不会自己迁回。需要均衡就 rollout restart 或使用 descheduler。

分步演示

cordon 与 drain
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,2 个 worker),被 drain 的节点上同时有 Deployment、DaemonSet、裸 Pod、带 emptyDir 的 Pod 和 metrics-server;PDB 的阻塞用 --timeout=25s 截断;各 Pod 的 terminationGracePeriodSeconds 设为 2 秒;每种情形各一次(各次运行里被驱逐的 dep Pod 个数取决于它们先前落在哪个节点)
    • 没有验证:drain 的并发与 --grace-period 覆盖;PDB 的 maxUnavailable 与 unhealthyPodEvictionPolicy;StatefulSet 的 drain 顺序;kubectl drain 的 --pod-selector 与 --disable-eviction;Eviction API 与直接删除的差别;节点上带 PV 的 Pod 迁移;cordon 与控制面污点的关系
    京ICP备2026067502号-1京公网安备11010502063487号