前言
最近发现Rancher集群的主机负载不均衡,有的主机只有十几个容器,有的主机有三十几个容器。容器部署采用默认主机调度规则,主机没有污点,容器有设置cpu和内存资源预留,但是发现容器调度不均衡,经常往资源占用高的主机部署。如截图红框中的主机明明资源相对富余,但新容器却不往该主机部署。导致个别主机实际负载高、个别主机空闲的情况。
一、环境信息
Rancher 版本:v2.5.11
Kubernetes 版本: v1.20.12
二、问题分析
起初怀疑是因为没有合理设置工作负载的资源预留(requests)导致调度器无视主机负载情况,所以为每个工作负载结合实际资源用量都设置了CPU和内存的资源预留,但是重新部署了之后情况没有改善,部署仍然不均衡。
查阅了k8s的调度策略之后,发现影响调度的因素很多,k8s调度分为断言(Predicates) 和优先级(Priorities) 两个阶段。首先根据污点、资源申请、是否指定节点、节点亲和性等设置排除不符合条件的节点;其次根据节点的pod数量、资源占用情况、是否存在所需镜像、节点亲和性等因素对节点进行评分,从而得出节点优先级。
三、解决方案
经过一番调试后仍然无法确定具体导致不均衡的因素,最终通过Descheduler组件二次调度达到均衡的效果。
四、Descheduler部署配置
1、获取yaml配置
git clone https://github.com/kubernetes-sigs/descheduler.git
或
git clone https://gitee.com/chest-hair/descheduler.git
从官方代码仓库拉取文件,在kubernetes目录下找到rbac.yaml、configmap.yaml和cronjob.yaml三个文件。
2、调整configmap.yaml配置
我期望它根据容器数量来平衡调度,所以把cpu和memory参数去除,pods上限调为27。当节点非系统pods数量超过27个时,会将多余的pods转移到其他节点。
thresholds:
#"cpu" : 20
#"memory": 20
"pods": 20
targetThresholds:
#"cpu" : 50
#"memory": 50
"pods": 27
3、部署组件
- 通过Rancher导入yaml进行部署
- 通过kubectl工具部署
kubectl create -f kubernetes/rbac.yaml kubectl create -f kubernetes/configmap.yaml kubectl create -f kubernetes/job.yaml
4、查看调度日志
descheduler-cronjob定时任务每两分钟会执行一次调度。位于system项目》kube-system命名空间》descheduler-cronjob工作负载。
节点出现Node is overutilized说明该节点超过阈值,会进行重新调度。
总结
1、为每个工作负载(Pods)添加资源预留(Reques),需要预留多少资源,可进入主机通过docker status命令查看容器资源使用情况来判断。
2、利用Descheduler组件进行Pods二次调度,按Pods数量进行调度,常规应用可设置Pods上限为:比两倍主机内存(G)少5个,例如16G主机则配置为27。视实际情况而定。
后续优化
通过容器数量去平衡仍然存在一定不合理性,最合理的还是根据节点实际负载来调度。后续的优化思路是通过Prometheus监控主机的实际CPU和内存使用率,将监控结果写入到节点label,再利用调度规则实现平衡。
已实现根据监控指标进行调度,详见《Rancher&k8s根据监控指标进行容器调度》