在K8S中,如何进行优雅的节点关机维护?
在 Kubernetes 中进行优雅的节点关机维护是确保服务高可用性和数据完整性的关键操作。核心目标是:安全驱逐(Evict)所有 Pod,避免服务中断,并确保有状态应用(如数据库)能正确处理终止请求。 以下是详细步骤和最佳实践:
核心步骤:优雅节点关机流程
-
标记节点为不可调度 (Cordon):
kubectl cordon <node-name>
- 作用: 阻止新创建的 Pod 被调度到该节点上。
- 原理: 设置
node.Spec.Unschedulable=true
。
-
安全驱逐所有 Pod (Drain):
kubectl drain <node-name> \ --ignore-daemonsets \ # 忽略 DaemonSet 管理的 Pod(如 CNI、日志采集器) --delete-emptydir-data \ # 删除使用 emptyDir 卷的 Pod 的数据(谨慎评估!) --force \ # 强制驱逐未受控制器管理(如裸 Pod)或自定义控制器管理的 Pod --timeout=300s # 设置超时时间(根据 Pod 终止时间调整)
- 作用: 安全地将节点上所有 Pod 驱逐(Evict) 到其他可用节点。
- 关键过程:
- 驱逐顺序: Kubernetes 控制平面会尝试在其他节点上重新调度被驱逐的 Pod。
- 优雅终止:
- Kubelet 向 Pod 中的每个容器发送
SIGTERM
信号。 - 等待
terminationGracePeriodSeconds
(默认为 30 秒)让容器执行清理逻辑(如保存状态、关闭连接)。 - 如果超时后容器仍在运行,则发送
SIGKILL
强制终止。
- Kubelet 向 Pod 中的每个容器发送
- 存储卷处理: 对于有持久卷(PV)的 Pod,Kubernetes 确保卷能安全卸载(需要 CSI 驱动支持
VOLUME_MODE_FILESYSTEM
的分离操作)。
-
等待驱逐完成:
- 监控
kubectl drain
命令的输出,直到所有 Pod 被成功驱逐或超时。 - 检查节点状态确认无用户 Pod 运行:
kubectl get pods --all-namespaces --field-selector spec.nodeName=<node-name>
- 仅应剩下
DaemonSet
管理的 Pod(如网络插件、监控代理)。
- 仅应剩下
- 监控
-
关机维护:
- 确认节点无用户 Pod 后,执行关机或重启操作:
sudo shutdown -h now # Linux 关机
- 确认节点无用户 Pod 后,执行关机或重启操作:
-
维护完成后恢复节点 (Uncordon):
kubectl uncordon <node-name>
- 作用: 重新允许 Pod 调度到该节点。
- 检查: 节点状态恢复
Ready
,并可接受新 Pod。
关键注意事项与进阶策略
-
处理阻塞 Drain 的场景:
- DaemonSet: 使用
--ignore-daemonsets
忽略(通常需在维护期间保留)。 - 静态 Pod(Static Pod): 由 kubelet 直接管理,需手动删除其 manifest 文件(默认
/etc/kubernetes/manifests/
)。 - PodDisruptionBudget (PDB):
- 检查 PDB 是否阻止驱逐(如要求最小可用副本数):
kubectl get pdb --all-namespaces
- 若 PDB 阻止,需临时调整副本数或 PDB 配置(确保服务可用性)。
- 检查 PDB 是否阻止驱逐(如要求最小可用副本数):
- DaemonSet: 使用
-
优化有状态应用的优雅终止:
- 延长宽限期: 为关键 Pod 设置更长的
terminationGracePeriodSeconds
(如 120 秒),确保完成清理:apiVersion: v1 kind: Pod spec: terminationGracePeriodSeconds: 120 # 延长优雅终止时间
- PreStop Hook: 在容器终止前执行自定义脚本(如通知下游、刷新缓存):
lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 30; /app/graceful-shutdown.sh"]
- 延长宽限期: 为关键 Pod 设置更长的
-
存储卷的安全卸载:
- CSI 支持: 确保 CSI 驱动实现
ControllerUnpublishVolume
和NodeUnpublishVolume
接口。 - StatefulSet: 优先使用
StatefulSet
管理有状态应用,其 Pod 名称和卷绑定关系稳定,易于重新调度。
- CSI 支持: 确保 CSI 驱动实现
-
使用节点关机特性(Kubelet Graceful Node Shutdown):
- 功能: Kubelet 在检测到系统关机信号时自动执行 Pod 驱逐(需 Kubernetes v1.20+)。
- 配置: 在 kubelet 配置文件中启用:
{ "shutdownGracePeriod": "60s", # 总关机宽限期 "shutdownGracePeriodCriticalPods": "20s" # 关键 Pod 的宽限期 }
- 原理: kubelet 在收到关机信号后,在宽限期内驱逐非关键 Pod,最后处理关键 Pod。
-
自动化与集成:
- Cluster API: 在管理大规模集群时,使用 Cluster API 自动化节点维护流程。
- GitOps: 结合 Argo CD/Flux,通过声明式配置管理节点状态。
总结操作流程
graph TD
A[标记节点不可调度<br>kubectl cordon] --> B[安全驱逐所有 Pod<br>kubectl drain]
B --> C{等待驱逐完成?}
C -->|是| D[关机维护]
C -->|否| B
D --> E[维护完成]
E --> F[恢复节点调度<br>kubectl uncordon]
最佳实践
- 预检: 维护前检查集群容量,确保其他节点有足够资源接纳被驱逐的 Pod。
- 窗口期: 在业务低峰期执行维护。
- 监控: 维护过程中监控应用指标(如请求错误率、Pod 启动状态)。
- 回滚计划: 准备遇到故障时快速恢复节点的预案(如取消 Drain 并 Uncordon)。
- 文档化: 将维护流程纳入运维手册,避免遗漏关键步骤。
通过遵循上述流程,Kubernetes 节点维护可以做到对业务近乎无感知,确保分布式系统的高可用性和数据一致性。