当你管理一个Kubernetes集群时,节点维护是绕不开的日常工作。想象一下,这就像管理一支足球队——有时候你需要让某个球员暂时休息(节点升级),有时候球员受伤需要治疗(硬件故障),还有些时候球队需要精简人员(集群缩容)。这时候,你就需要三把"瑞士军刀":cordon、drain和delete。
我刚开始接触K8s时,经常搞混这三个命令。直到有一次线上事故,因为用错了命令导致服务中断,才真正明白它们的区别。简单来说:
选择哪个命令,取决于你的维护目标:
上周我们集群有个节点需要安装安全补丁,我就用了cordon。这个命令特别适合:
实际操作很简单:
bash复制# 查看当前节点状态
kubectl get nodes
# 隔离节点
kubectl cordon node-01
# 验证状态
kubectl describe node node-01 | grep -i schedul
你会看到SchedulingDisabled: true的标记。这时候新创建的Pod会自动避开这个节点,但原有的Pod纹丝不动。
新手容易犯两个错误:
bash复制kubectl uncordon node-01
我有个同事曾经cordon了一个节点后忘记uncordon,三天后那个节点还处于隔离状态,导致集群资源利用率不均。
drain是我用得最多的命令,特别是在这些场景:
完整流程应该是:
bash复制# 1. 先cordon(安全起见)
kubectl cordon node-02
# 2. 驱逐Pod(带保护参数)
kubectl drain node-02 \
--ignore-daemonsets \
--delete-local-data \
--force \
--timeout=300s
# 3. 执行维护操作
# ...你的维护脚本...
# 4. 恢复节点
kubectl uncordon node-02
这几个参数必须掌握:
--ignore-daemonsets:忽略DaemonSet管理的Pod(如kube-proxy)--delete-local-data:删除使用emptyDir的Pod--force:强制驱逐不由控制器管理的Pod--timeout:设置等待时间(单位秒)去年我们升级内核时就遇到个坑:没加--timeout参数,结果有些Pod终止超时,导致drain卡住。后来发现是某个Java应用关闭时需要30秒完成事务处理。
drain的实际工作流程是这样的:
delete是三个命令中最"暴力"的,适用于:
它的操作流程:
bash复制# 1. 驱逐Pod(建议先drain)
kubectl drain node-03 --force --ignore-daemonsets
# 2. 从集群删除节点
kubectl delete node node-03
# 3. 在节点机器上清理(如果需要重新加入)
kubeadm reset
上个月我们有个物理服务器硬盘故障,被迫使用delete。结果发现那个节点上运行的MySQL Pod使用了本地PV,导致数据无法恢复。后来我们改用了网络存储。
根据我的经验,可以按这个流程选择:
code复制是否需要永久移除节点?
├─ 是 → 使用delete
└─ 否 → 是否需要迁移现有Pod?
├─ 是 → 使用drain
└─ 否 → 使用cordon
问题1:drain卡住不动
kubectl describe pod <pod-name>--timeout值问题2:delete后节点自动重新加入
systemctl stop kubeletrm -rf /etc/kubernetes/问题3:cordon后仍有Pod被调度
kubectl logs -n kube-system <scheduler-pod>上周我们给集群的20个节点升级Docker版本,完整流程是:
bash复制kubectl drain <node> --ignore-daemonsets
apt-get upgrade docker-ce
reboot
kubectl uncordon <node>
整个过程零停机,关键是要控制好滚动升级的批次间隔。
当遇到硬件故障时:
在云环境下自动缩容时:
这样能确保服务不中断。