
1. 生产环境K8s节点下线的重要性与挑战在Kubernetes生产集群运维中节点下线是最常见但风险最高的操作之一。我经历过多次因节点下线不当导致的服务中断事故——某次直接下线Worker节点导致30%的Pod被强制终止另一次因未清理本地存储造成数据丢失。这些教训让我意识到节点下线不是简单的kubectl drain命令执行而是需要系统化的流程设计。生产环境节点下线主要面临三大挑战业务连续性保障必须确保Pod优雅终止并重新调度避免服务中断数据完整性风险处理有状态服务时需确保存储卷正确迁移资源回收验证防止残留配置导致资源泄漏或后续节点加入冲突2. 标准下线流程全景图2.1 前置检查清单在下线操作前必须完成以下检查以节点node-01为例# 检查节点状态 kubectl get node node-01 -o wide # 查看节点运行Pod列表注意--ignore-daemonsets参数 kubectl get pods -A -o wide --field-selector spec.nodeNamenode-01 | grep -v kube-system # 检查本地存储使用情况 ssh node-01 df -h | grep -E local-volume|data关键检查项确认节点无运行关键业务Pod如数据库主实例检查本地存储使用量是否超过其他节点剩余容量验证集群剩余资源是否满足Pod重新调度需求2.2 核心操作流程2.2.1 驱逐PodDrain操作标准drain命令应包含以下参数kubectl drain node-01 \ --ignore-daemonsets \ --delete-emptydir-data \ --force \ --timeout300s \ --pod-selectorapp notin (redis-master,postgresql-primary)参数解析--ignore-daemonsets跳过DaemonSet管理的Pod如日志收集器--delete-emptydir-data清理emptyDir临时数据--pod-selector保护关键Pod不被驱逐需提前打标签重要提示对于StatefulSet Pod必须确认已配置适当的PodDisruptionBudget(PDB)否则可能违反SLA2.2.2 存储卷处理针对不同存储类型需特殊处理存储类型处理方案检查命令PV/PVC自动随Pod迁移kubectl get pvc -ALocal PV需人工确认数据备份kubectl get pv -o jsonHostPath必须手动迁移数据find /mnt/data -type f对于Local PV建议先执行数据备份# 创建临时备份目录 ssh node-01 mkdir -p /backup/$(date %Y%m%d) # 同步数据到NFS rsync -avz /mnt/data/ nfs-server:/backups/node-01/2.3 节点下线后验证执行kubectl delete node node-01后必须验证资源释放情况kubectl get leases -A | grep node-01 kubectl get volumeattachments | grep node-01服务恢复验证# 检查原Pod是否在新节点正常运行 for pod in $(kubectl get pods -A -o jsonpath{range .items[?(.spec.nodeNamenode-01)]}{.metadata.name}{\n}{end}); do kubectl -n ${pod%%_*} get pod ${pod##*_} -o wide done3. 特殊场景处理方案3.1 控制平面节点下线控制节点下线需要额外步骤先迁移kube-apiserver等关键组件# 查看当前leader kubectl -n kube-system get endpoints kube-scheduler -o jsonpath{.metadata.annotations.control-plane\.alpha\.kubernetes\.io/leader} # 手动移除待下线节点 kubectl -n kube-system patch leases kube-scheduler --typejson -p[{op:remove, path:/spec/holderIdentity}]从kubeadm配置移除节点kubeadm init phase upload-config kubeadm --config /etc/kubernetes/kubeadm-config.yaml3.2 批量下线操作当需要下线多个节点时建议使用并行处理脚本#!/bin/bash for node in node-{01..03}; do kubectl drain $node --ignore-daemonsets --delete-emptydir-data done wait # 验证所有Pod已迁移 kubectl get pods -A -o wide | grep -E Pending|Evicted遵循滚动下线原则每次最多下线集群节点的20%间隔至少5分钟观察集群状态优先下线非关键业务节点4. 自动化方案实现4.1 基于Cluster API的下线流程现代集群推荐使用声明式API管理节点生命周期apiVersion: cluster.x-k8s.io/v1beta1 kind: Machine metadata: name: worker-node-01 spec: nodeDeletionTimeout: 30m nodeDrainTimeout: 15m remediationStrategy: maxRetry: 3 retryPeriod: 5m4.2 自定义控制器实现通过编写控制器实现智能下线func (r *NodeReconciler) handleDrain(node *corev1.Node) error { // 检查PodDisruptionBudget if err : r.checkPDB(node); err ! nil { return fmt.Errorf(PDB check failed: %v, err) } // 分批次驱逐Pod pods : r.getPodsOnNode(node) batchSize : len(pods)/5 1 for i : 0; i len(pods); i batchSize { end : i batchSize if end len(pods) { end len(pods) } if err : r.evictPods(pods[i:end]); err ! nil { return err } time.Sleep(30 * time.Second) } return nil }5. 故障排查手册5.1 常见错误与解决方案错误现象根本原因解决方案Pod卡在Terminating状态Finalizer未清理kubectl patch pod name -p {metadata:{finalizers:null}}存储卷无法卸载仍有进程占用设备ssh node-01 lsof D /mnt/data终止相关进程新节点加入后IP冲突旧节点kubelet未完全清理在旧节点执行kubeadm reset --force服务中断超过SLAPDB配置不合理调整minAvailable值kubectl patch pdb my-pdb -p {spec:{minAvailable:60%}}5.2 监控指标检查清单下线操作期间必须监控以下Prometheus指标# 待下线节点资源使用率 sum(rate(container_cpu_usage_seconds_total{nodenode-01}[5m])) by (pod) sum(container_memory_working_set_bytes{nodenode-01}) by (pod) # 集群整体资源余量 sum(kube_node_status_allocatable{resourcecpu}) - sum(kube_pod_container_resource_requests{resourcecpu})6. 最佳实践与经验总结优雅终止超时设置 所有Pod模板必须配置preStop钩子并设置合理的terminationGracePeriodSecondslifecycle: preStop: exec: command: [/bin/sh, -c, sleep 30; nginx -s quit] terminationGracePeriodSeconds: 60节点下线时间窗口选择避免业务高峰时段通过分析历史监控数据考虑依赖服务的维护周期如数据库备份期间不下线自动化验证脚本示例#!/bin/bash function verify_drain() { local node$1 local retries3 while ((retries-- 0)); do if kubectl get pods -A --field-selector spec.nodeName$node | grep -v NAME; then echo 仍有Pod运行在节点$node上 sleep 10 else return 0 fi done return 1 }文档记录要点记录下线原因硬件更换/维护/缩容保存操作时间点和影响评估更新集群拓扑图和容量规划表