深色模式
节点维护:cordon、drain 与下线
摘要:本文给出节点维护的标准流程:先 cordon 停止调度、再 drain 驱逐 Pod、维护完成后 uncordon 恢复。覆盖 DaemonSet 与本地存储的强制选项、PodDisruptionBudget 的保护作用,以及驱逐卡住的处理。
适用环境
- 可用 K8s 集群,节点数 ≥ 2(单节点 drain 会驱逐系统组件,勿在生产用)
- 有
kubectl与节点登录权限 - 目标节点上的服务已有多副本(否则 drain 会造成业务中断)
操作步骤
一、维护前检查
bash
kubectl get nodes
kubectl get pod -A -o wide --field-selector spec.nodeName=<节点名>
kubectl describe node <节点名> | grep -A10 "Allocated resources"1
2
3
2
3
确认:该节点上的 Pod 在其他节点有副本、目标节点有足够余量承接迁移。
注意
单副本服务、使用 emptyDir 或本地盘的 Pod 被驱逐后数据会丢失。drain 前务必逐个确认。
二、cordon:停止调度新 Pod
bash
kubectl cordon <节点名>
kubectl get nodes # STATUS 显示 Ready,SchedulingDisabled1
2
2
已有 Pod 不受影响,只是不会有新 Pod 被调度上来。
三、drain:驱逐已有 Pod
bash
kubectl drain <节点名> \
--ignore-daemonsets \
--delete-emptydir-data \
--grace-period=60 \
--timeout=10m1
2
3
4
5
2
3
4
5
参数说明:
| 参数 | 作用 |
|---|---|
--ignore-daemonsets | 忽略 DaemonSet(默认会因它们而报错中断) |
--delete-emptydir-data | 允许删除使用 emptyDir 的 Pod,其数据会丢 |
--grace-period | 优雅退出等待秒数 |
--force | 允许驱逐不受控制器管理的裸 Pod(会造成服务消失) |
bash
kubectl get pod -A -o wide | grep <节点名> # 应只剩 DaemonSet1
四、PodDisruptionBudget 的保护
PDB 限制「自愿驱逐」时同时不可用的副本数,防止 drain 把服务一次全赶走:
yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web-pdb
spec:
minAvailable: 2 # 或 maxUnavailable: 1
selector:
matchLabels:
app: web1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
bash
kubectl get pdb -A1
建议
PDB 只约束自愿中断(drain、节点缩容),不约束节点宕机这类非自愿中断。所有多副本生产服务都应配 PDB。
五、drain 卡住怎么办
常见报错:error when evicting pods: Cannot evict pod as it would violate the pod's disruption budget。
bash
kubectl describe pdb -n <命名空间> # 看允许的中断数
kubectl scale deploy <name> --replicas=+1 # 临时加副本再 drain1
2
2
或等 PDB 允许后自动继续(drain 会重试)。确需强制时用 --force --disable-eviction(绕过 PDB,会破坏可用性承诺)。
六、执行节点维护
bash
ssh <节点>
sudo systemctl stop kubelet
# 做内核升级、换盘、硬件检修等
sudo reboot
sudo systemctl status kubelet containerd1
2
3
4
5
2
3
4
5
七、恢复调度
bash
kubectl uncordon <节点名>
kubectl get nodes # STATUS 回到 Ready
kubectl get pod -A -o wide | grep <节点名>1
2
3
2
3
危险
uncordon 不会自动把 Pod 调度回来。若希望负载重新均衡,需要手动触发重调度(如 kubectl rollout restart),或依赖 descheduler 组件。长期看节点负载会自然逐步均衡。
八、彻底移除节点
bash
kubectl drain <节点名> --ignore-daemonsets --delete-emptydir-data
kubectl delete node <节点名>
# 在节点上清理 kubeadm 残留
sudo kubeadm reset
sudo rm -rf /etc/cni/net.d ~/.kube/config1
2
3
4
5
2
3
4
5
验证
- [ ]
kubectl get nodes显示Ready,SchedulingDisabled - [ ] drain 后该节点只剩 DaemonSet Pod
- [ ] 业务 Pod 在其他节点 Running 且服务可用
- [ ] uncordon 后 STATUS 恢复 Ready,新 Pod 能被调度上来
常见坑
- drain 报错中断:忘了
--ignore-daemonsets,几乎必现。 - 驱逐后服务不可用:副本数为 1,或 PDB 设置与实际副本冲突。
emptyDir数据丢失:被--delete-emptydir-data删掉,重要数据必须放 PVC。- 维护完负载不均:uncordon 不触发回迁,属预期行为。
- 节点删了又自动注册回来:kubelet 仍在运行且 kubeconfig 未清理,需先
kubeadm reset。