背景
在目前的环境下,公司的业务缩减。公司开启了一波降本增效, 我们IT部门也进行了积极的响应。
首先先对我们的服务器进行大幅缩减,然后数据库和带宽配置进行了腰斩。
由于我们的业务系统运行在阿里云,涉及到的资源基本包括:EIP, CLB, ECS, RDS-Redis,RDS-MySQL等等。此次降本增效大部分都是阿里云给我们提供了无缝切换,但是唯一一个就是ECS。我们业务系统运行在自建的k8s集群中,并没有使用阿里云提供的AKS。那么减少ECS数量需要我们自己来干, 减少ECS在我们的场景中就是移除k8s Node。
需求
优雅移除k8s Node而不影响业务的可用性,对用户无感知。
k8s对增减Node支持
- 添加Node到集群:
kubeadmin join
- 查询集群中Node列表:
kubectl get nodes
- 从集群移除Node:
kubectl drain node
,kubectl cordon node
,kubectl delete node
特别注意
这个特别注意就是不要在你驱逐node的时候服务还有其他Pod可以支持继续为用户提供服务。
这个可以有很多方案来实现啦,我这儿提供2个:
- 确保Pod副本是分布在不同的Node中,从而避免一个服务的所有Pod副本都在一个Node导致驱逐Node时导致系统宕机
- 保证服务Pod最小可用副本数
第一个解决方案可以使用Node的反亲和性来解决:
第二个解决方案可以使用PDB(PodDisruptionBudget )来保证Pod的最小副本数。
实施步骤
- 获取Node
- 驱逐节点上的 Pod
- 确认 Pod 已迁移
- 从集群中删除节点
- (可选)停止并重置kubelet
- (可选)重新加入集群
第一步和第二步可以使用
kubectl drain
命令来完成。
详细步骤
1. 获取Node
首先我们使用kubectl get nodes | grep <node-name>
获取想要驱逐的Node,
kubectl get nodes
2. 驱逐节点上的 Pod
接下来,我们需要将节点上的现有 Pod 驱逐到其他节点。使用 kubectl drain
命令可以完成这个操作(可能你的node中有daemonset和local data, 可以使用--ignore-daemonsets
和--delete-local-data
来忽略和删除):
kubectl drain <node-name> --ignore-daemonsets --delete-local-data
示例:
kubectl drain node-1 --ignore-daemonsets --delete-local-data
参数解释:
--ignore-daemonsets
:忽略 DaemonSet 管理的 Pod。--delete-local-data
:删除使用emptyDir
卷的 Pod。
这个命令会驱逐节点上的所有 Pod,并将它们重新调度到其他节点。注意,这一步可能需要一些时间,具体取决于节点上的 Pod 数量和资源情况。
3. 确认 Pod 已迁移
在驱逐操作完成后,使用以下命令确认所有 Pod 已经从目标节点迁移:
kubectl get pods --all-namespaces -o wide | grep <node-name>
示例:
kubectl get pods --all-namespaces -o wide | grep node-1
如果命令没有返回任何结果,说明 Pod 已经成功迁移。
4. 从集群中删除节点
确认 Pod 已迁移后,我们可以安全地从集群中删除节点:
kubectl delete node <node-name>
示例:
kubectl delete node node-1
这个命令会将节点从 Kubernetes 集群中移除。
5. (可选)停止并重置kubelet
如果Node后面不再使用了,那么可以停止kubelet服务:
sudo systemctl stop kubelet
另外,还可以使用kubeadm 重置Node
sudo kubeadm reset
sudo rm -rf ~/.kube
6. (可选)重新加入集群
如果你的Node只是想做一些系统维护的工作,维护完成后重新加入集群并接受调度,那么就可以使用kubeadm重新加入集群:
# 生成加入集群的Token
kubeadm token create --print-join-command
# 加入集群
kubeadm join <master-node>:<api-port> --token <your-token> --discovery-token-ca-cert-hash sha256:<hash>
# 验证Node是否加入集群
kubectl get nodes
# 此时可以看到Node并且状态是Ready
注意事项
- 在执行这些操作之前,请确保集群有足够的资源来承载被驱逐的 Pod(根据情况给当前Node加点CPU和内存不过分吧~)。
- 驱逐操作可能会影响业务,建议在业务低峰期执行(在之前先通知用户,系统升级可能会不可用,先说断后不乱~)。