1. 为什么我们需要主动缩容?
在Kubernetes集群运维中,节点扩容和缩容就像呼吸一样自然。想象一下这样的场景:
- 业务低谷期:电商平台在双十一结束后,服务器负载骤降
- 硬件更换:老旧的物理机需要退役更换为云服务器
- 资源优化:发现某些节点长期处于低利用率状态
此时若任由闲置节点空转,每小时可能浪费数百元云成本。但直接删除节点就像突然拔掉正在输液的针头——可能引发服务中断、数据丢失等问题。
2. 关键前置检查清单(必做!)
掏出你的终端,在开始手术前先做好五项检查:
# 查看所有节点状态(技术栈:kubectl)
kubectl get nodes -o wide
# 检查目标节点上的Pod分布(替换<node-name>为实际节点名)
kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=<node-name>
# 验证节点是否可调度(重点看SchedulingDisabled状态)
kubectl describe node <node-name> | grep -i taints
# 检查本地存储卷(特别是使用hostPath的应用)
kubectl get pv --all-namespaces | grep <node-name>
# 确认Kubelet状态(在目标节点执行)
systemctl status kubelet
3. 核心操作六部曲详解
3.1 给节点打上免打扰标签
就像给即将搬走的邻居门上贴封条:
kubectl cordon <node-name>
此时新Pod不会再被调度到此节点,但现有Pod继续运行。
3.2 优雅驱逐现有Pod
用专业的排水(drain)操作替代粗暴删除:
kubectl drain <node-name> \
--ignore-daemonsets \ # 忽略守护进程集(如监控Agent)
--delete-emptydir-data \ # 清理临时数据卷
--timeout=5m # 避免卡死
注意! 如果看到报错:"error: unable to drain node... due to pod with local storage",需要手动处理有状态服务。
3.3 处理顽固Pod的特殊案例
当遇到有本地存储的有状态服务时,推荐分步处理:
# 临时缩容StatefulSet(技术栈:Kubernetes原生API)
kubectl scale statefulset my-redis --replicas=0
# 手动删除残余Pod(谨慎操作!)
kubectl delete pod redis-node-0 --grace-period=60
# 等待所有PVC确认解除绑定(必须步骤)
watch kubectl get pvc -n <namespace>
3.4 正式删除节点
确认节点无残留Pod后执行:
kubectl delete node <node-name>
3.5 清理残留资源三要素
很多工程师会漏掉这些隐藏角落:
# 孤儿endpoint清理
kubectl get endpoints | grep <node-ip>
kubectl delete endpoints <orphan-endpoint-name>
# 残留网络接口检查(在集群网络插件所在节点执行)
ip link show | grep cali # Calico插件示例
calicoctl delete node <node-name> # 网络配置清理
# Kubelet残留配置清理(在目标节点执行)
sudo kubeadm reset
sudo rm -rf /etc/cni/net.d/
3.6 反向验证操作
必须通过四项验证才算真正成功:
# 查看节点列表是否已消失
kubectl get nodes
# 检查CoreDNS端点更新情况
kubectl -n kube-system get endpoints kube-dns
# 验证集群自动缩放器状态(如果启用了Cluster Autoscaler)
kubectl -n kube-system logs deployment/cluster-autoscaler | grep "Removed node"
# 残留资源最后通牒检查
kubectl get all --all-namespaces -o wide | grep <node-name>
4. 必知的五个隐藏技巧
4.1 负载均衡器的秘密握手
在AWS环境删除节点时,记得检查目标组:
aws elbv2 describe-target-health \
--target-group-arn <your-tg-arn> \
--query 'TargetHealthDescriptions[?Target.Id==`<instance-id>`]'
4.2 节点优雅退出的时间玄学
通过调整控制器管理器的参数实现平滑过渡:
# 修改kube-controller-manager启动参数
- --terminated-pod-gc-threshold=50
- --pod-eviction-timeout=2m0s
4.3 节点临终关怀服务
创建PreStop钩子确保服务优雅终止:
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- "curl -X POST http://127.0.0.1:8080/drain || true"
4.4 节点标签的精确制导
通过标签选择器批量操作:
kubectl drain -l node-type=spot-instance
4.5 云供应商特殊处理
AWS节点需要额外清理ENI:
aws ec2 describe-network-interfaces \
--filters Name=attachment.instance-id,Values=<instance-id>
5. 典型故障的黄金救援方案
5.1 僵尸节点复活事件
当节点状态显示NotReady但API Server仍保留记录时:
kubectl get node <node-name> -o json | jq '.spec.taints'
kubectl patch node <node-name> -p '{"spec":{"taints":[]}}'
5.2 永远驱逐不走的Pod
强制删除的终极手段:
kubectl delete pod <pod-name> --grace-period=0 --force
5.3 存储卷的生死缠绵
当PV持续处于Terminating状态:
kubectl patch pv <pv-name> -p '{"metadata":{"finalizers":null}}'
6. 关联技术深度解析
6.1 PodDisruptionBudget的守护结界
为关键服务设置驱逐保护:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
minAvailable: 2
selector:
matchLabels:
app: zookeeper
6.2 节点亲和性的双刃剑
错误配置的亲和性可能导致Pod无法迁移:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: ssd
operator: In
values:
- "true"
7. 实践中的坑与黄金法则
7.1 三大经典翻车现场
- 未检查DaemonSet导致Pod无限重建
- 漏删本地存储引发的数据泄漏
- LoadBalancer未及时更新导致的流量黑洞
7.2 操作黄金时间窗
建议选择业务低峰期的维护窗口:
- 周二凌晨2-4点(避开周一服务重启高峰)
- 季度结算周期结束后
- 重大促销活动前2周
8. 完整实战案例演示
假设我们有一个3节点的集群要移除其中1个worker节点:
# 先标记节点不可调度
kubectl cordon worker-node03
# 驱逐所有Pod(带详细参数解释)
kubectl drain worker-node03 \
--ignore-daemonsets \ # 绕过监控Agent等DaemonSet
--delete-emptydir-data \ # 清除临时数据卷
--grace-period=120 \ # 给Pod额外2分钟准备时间
--timeout=10m # 设置超时阈值
# 确认驱逐完成
watch kubectl get pods -o wide
# 执行节点删除
kubectl delete node worker-node03
# 云平台资源清理(以AWS为例)
aws ec2 terminate-instances --instance-ids i-0abcdef1234567890
# 验证负载均衡器健康检查(以ALB为例)
aws elbv2 describe-target-health --target-group-arn arn:aws:elasticloadbalancing...
# 最终状态确认
kubectl get nodes
kubectl get pods --all-namespaces -o wide
9. 技术方案选型对比
当面对不同规模集群时,采用不同策略:
场景 | 小规模集群(<20节点) | 中大型集群 | 超大规模集群 |
---|---|---|---|
操作方式 | 手动逐台操作 | 脚本批量处理 | 自动化调度系统 |
风险控制 | 人工二次确认 | 金丝雀发布模式 | 细胞级隔离策略 |
清理周期 | 立即清理 | 定时垃圾回收 | 智能预测回收 |
典型工具链 | kubectl | Ansible+Shell | 自研运维平台 |
耗时预估 | 10分钟/节点 | 5分钟/节点 | <1分钟/节点 |