问题及原因

k8s是通过sceduler来调度pod的,在调度过程中,由于一些原因,会出现调度不均衡的问题,例如:

节点故障
新节点被加到集群中
节点资源利用不足

这些都会导致pod在调度过程中分配不均,例如会造成节点负载过高,引发pod触发OOM等操作造成服务不可用
其中,节点资源利用不足时是最容易出现问题的,例如,设置的requests和limits不合理,或者没有设置requests/limits都会造成调度不均衡。

  • 由于我部署使用的是statefulset 而非deployment,因此使用了这个工具无效,看了官方文档应该不支持statefulset。打算后期再调整一下部署方式 换成deployment 并解决相关优雅部署问题之后再尝试。

安装 重平衡工具Descheduler

工具简介

Descheduler 的出现就是为了解决 Kubernetes 自身调度(一次性调度)不足的问题。它以定时任务方式运行,根据已实现的策略,重新去平衡 pod 在集群中的分布。

截止目前,Descheduler 已实现的策略和计划中的功能点如下:

  • 已实现的调度策略
    • RemoveDuplicates 移除重复 pod
    • LowNodeUtilization 节点低度使用
    • RemovePodsViolatingInterPodAntiAffinity 移除违反pod反亲和性的 pod
    • RemovePodsViolatingNodeAffinity
  • 路线图中计划实现的功能点
    • Strategy to consider taints and tolerations 考虑污点和容忍
    • Consideration of pod affinity 考虑 pod 亲和性
    • Strategy to consider pod life time 考虑 pod 生命周期
    • Strategy to consider number of pending pods 考虑待定中的 pod 数量
    • Integration with cluster autoscaler 与集群自动伸缩集成
    • Integration with metrics providers for obtaining real load metrics 与监控工具集成来获取真正的负载指标
    • Consideration of Kubernetes’s scheduler’s predicates 考虑 k8s 调度器的预判机制
策略介绍
  • RemoveDuplicates 此策略确保每个副本集(RS)、副本控制器(RC)、部署(Deployment)或任务(Job)只有一个 pod 被分配到同一台 node 节点上。如果有多个则会被驱逐到其它节点以便更好的在集群内分散 pod。
  • LowNodeUtilization a. 此策略会找到未充分使用的 node 节点并在可能的情况下将那些被驱逐后希望重建的 pod 调度到该节点上。 b. 节点是否利用不足由一组可配置的 阈值(thresholds) 决定。这组阈值是以百分比方式指定了 CPU、内存以及 pod数量 的。只有当所有被评估资源都低于它们的阈值时,该 node 节点才会被认为处于利用不足状态。 c. 同时还存在一个 目标阈值(targetThresholds),用于评估那些节点是否因为超出了阈值而应该从其上驱逐 pod。任何阈值介于 thresholds 和 targetThresholds 之间的节点都被认为资源被合理利用了,因此不会发生 pod 驱逐行为(无论是被驱逐走还是被驱逐来)。 d. 与之相关的还有另一个参数numberOfNodes,这个参数用来激活指定数量的节点是否处于资源利用不足状态而发生 pod 驱逐行为。
  • RemovePodsViolatingInterPodAntiAffinity 此策略会确保 node 节点上违反 pod 间亲和性的 pod 被驱逐。比如节点上有 podA 并且 podB 和 podC(也在同一节点上运行)具有禁止和 podA 在同一节点上运行的反亲和性规则,则 podA 将被从节点上驱逐,以便让 podB 和 podC 可以运行。
  • RemovePodsViolatingNodeAffinity 此策略会确保那些违反 node 亲和性的 pod 被驱逐。比如 podA 运行在 nodeA 上,后来该节点不再满足 podA 的 node 亲和性要求,如果此时存在 nodeB 满足这一要求,则 podA 会被驱逐到 nodeB 节点上。
部署方式

Descheduler 会以 Job 形式在 pod 内运行,因为 Job 具有多次运行而无需人为介入的优势。为了避免被自己驱逐 Descheduler 将会以 关键型 pod 运行,因此它只能被创建建到 kube-system namespace 内。

部署命令

  1. git clone https://github.com/kubernetes-sigs/descheduler.git
  2. cd kubernetes
  3. kubectl apply -f rbac.yaml
  4. kubectl apply -f configmap.yaml
  5. # Run As A Job
  6. # kubectl apply -f job.yaml
  7. # Run As A CronJob
  8. kubectl apply -f cronjob.yaml

descheduler 策略。目前只支持四种策略:

  • RemoveDuplicates
    RS、deployment 中的 pod 不能同时出现在一台机器上
  • LowNodeUtilization
    找到资源使用率比较低的 node,然后驱逐其他资源使用率比较高节点上的 pod,期望调度器能够重新调度让资源更均衡
  • RemovePodsViolatingInterPodAntiAffinity
    找到已经违反 Pod Anti Affinity 规则的 pods 进行驱逐,可能是因为反亲和是后面加上去的
  • RemovePodsViolatingNodeAffinity
    找到违反 Node Affinity 规则的 pods 进行驱逐,可能是因为 node 后面修改了 label

configmap.yaml LowNodeUtilization的主要配置如下

  1. nodeResourceUtilizationThresholds:
  2. thresholds:
  3. # "cpu" : 20 # 百分比
  4. "memory": 40 # 百分比
  5. # "pods": 20 # 个数
  6. targetThresholds:
  7. # "cpu" : 50 # 百分比
  8. "memory": 75 # 百分比
  9. # "pods": 50 # 个数

我的configmap.yaml 如下

  1. ---
  2. apiVersion: v1
  3. kind: ConfigMap
  4. metadata:
  5. name: descheduler-policy-configmap
  6. namespace: kube-system
  7. data:
  8. policy.yaml: |
  9. apiVersion: "descheduler/v1alpha1"
  10. kind: "DeschedulerPolicy"
  11. evictLocalStoragePods: true
  12. strategies:
  13. "LowNodeUtilization":
  14. enabled: true
  15. params:
  16. nodeResourceUtilizationThresholds:
  17. thresholds:
  18. "memory": 50
  19. targetThresholds:
  20. "memory": 70

如果pod只在乎内存 可以参考

内存使用率超过70%的节点将被视为overutilized,反之亦然。

  1. # 查看调度日志
  2. kubectl logs -n kube-system descheduler-cronjob

对crontab也进行了调整 希望在中午12点和凌晨1点进行重调度

  • 最好避免和定时任务冲突。也没有用户使用的时候
遵循机制

当 Descheduler 调度器决定于驱逐 pod 时,它将遵循下面的机制:

  • Critical pods (with annotations scheduler.alpha.kubernetes.io/critical-pod) are never evicted
    关键 pod(带注释 scheduler.alpha.kubernetes.io/critical-pod)永远不会被驱逐。
  • Pods (static or mirrored pods or stand alone pods) not part of an RC, RS, Deployment or Jobs are never evicted because these pods won’t be recreated
    不属于RC,RS,部署或作业的Pod(静态或镜像pod或独立pod)永远不会被驱逐,因为这些pod不会被重新创建。
  • Pods associated with DaemonSets are never evicted
    与 DaemonSets 关联的 Pod 永远不会被驱逐。
  • Pods with local storage are never evicted(配置 evictLocalStoragePods: true 可以驱逐具有本地存储的pod)
    具有本地存储的 Pod 永远不会被驱逐。
  • BestEffort pods are evicted before Burstable and Guaranteed pods QoS
    等级为 BestEffort 的 pod 将会在等级为 Burstable 和 Guaranteed 的 pod 之前被驱逐。

所以根据第二条的话 statefulset 应该不会被驱逐吧。

我的服务都是statefulset 所以出现了有意思的情况,日志显示 allPods:10, nonRemovablePods:10, removablePods:0 虽然超标 但是可移动的pod为0

Crontab的基本格式

<分钟> <小时> <日> <月份> <星期> <命令>

分钟 值从 0 到 59.
小时 值从 0 到 23.
日 值从 1 到 31.
月 值从 1 到 12.
星期 值从 0 到 6, 0 代表星期日

多个时间可以用逗号隔开,范围可以用连字符给出,*可以作为通配符。空格用来分开字段。

参考

https://cloud.tencent.com/developer/article/1671811

https://github.com/kubernetes-sigs/descheduler/issues/212

文档更新时间: 2021-01-29 11:23   作者:张尚