介绍
kubernetes 的原生调度器只能通过资源请求来调度 pod,这很容易造成一系列负载不均的问题:
- 对于某些节点,实际负载与资源请求相差不大,这会导致很大概率出现稳定性问题。
- 对于其他节点来说,实际负载远小于资源请求,这将导致资源的巨大浪费。
为了解决这些问题,动态调度器根据实际的节点利用率构建了一个简单但高效的模型,并过滤掉那些负载高的节点来平衡集群。
架构
如上图,动态调度器依赖于Prometheus和Node-exporter收集和汇总指标数据,它由两个组件组成:
Node-annotator 目前是 Crane-scheduler-controller的一个模块。
- Node-annotator定期从 Prometheus 拉取数据,并以注释的形式在节点上用时间戳标记它们。
- Dynamic plugin直接从节点的注释中读取负载数据,过滤并基于简单的算法对候选节点进行评分。
调度策略
动态调度器提供了一个默认值调度策略并支持用户自定义策略。默认策略依赖于以下指标:
- cpu_usage_avg_5m
- cpu_usage_max_avg_1h
- cpu_usage_max_avg_1d
- mem_usage_avg_5m
- mem_usage_max_avg_1h
- mem_usage_max_avg_1d
在调度的Filter阶段,如果该节点的实际使用率大于上述任一指标的阈值,则该节点将被过滤。而在Score阶段,最终得分是这些指标值的加权和。
Hot Value
在生产集群中,可能会频繁出现调度热点,因为创建 Pod 后节点的负载不能立即增加。因此,我们定义了一个额外的指标,名为Hot Value,表示节点最近几次的调度频率。并且节点的最终优先级是最终得分减去Hot Value。
安装 Prometheus
确保你的 Kubernetes 集群已安装 Prometheus。如果没有,请参考Install Prometheus。
配置 Prometheus 规则
配置 Prometheus 的规则以获取预期的聚合数据:
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: example-record
spec:
groups:
- name: cpu_mem_usage_active
interval: 30s
rules:
- record: cpu_usage_active
expr: 100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[30s])) * 100)
- record: mem_usage_active
expr: 100*(1-node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes)
- name: cpu-usage-5m
interval: 5m
rules:
- record: cpu_usage_max_avg_1h
expr: max_over_time(cpu_usage_avg_5m[1h])
- record: cpu_usage_max_avg_1d
expr: max_over_time(cpu_usage_avg_5m[1d])
- name: cpu-usage-1m
interval: 1m
rules:
- record: cpu_usage_avg_5m
expr: avg_over_time(cpu_usage_active[5m])
- name: mem-usage-5m
interval: 5m
rules:
- record: mem_usage_max_avg_1h
expr: max_over_time(mem_usage_avg_5m[1h])
- record: mem_usage_max_avg_1d
expr: max_over_time(mem_usage_avg_5m[1d])
- name: mem-usage-1m
interval: 1m
rules:
- record: mem_usage_avg_5m
expr: avg_over_time(mem_usage_active[5m])
Prometheus 的采样间隔必须小于30秒,不然可能会导致规则无法正常生效。如:cpu_usage_active
。
安装 Crane-scheduler
安装 Crane-scheduler 作为第二个调度器
kubectl apply -f https://finops.coding.net/p/gocrane/d/crane-scheduler/git/raw/main/deploy/controller/rbac.yaml?download=false
kubectl apply -f https://finops.coding.net/p/gocrane/d/crane-scheduler/git/raw/main/deploy/controller/deployment.yaml?download=false
使用Crane-scheduler 调度 Pod
使用以下示例测试 Crane-scheduler:
apiVersion: apps/v1
kind: Deployment
metadata:
name: cpu-stress
spec:
selector:
matchLabels:
app: cpu-stress
replicas: 1
template:
metadata:
labels:
app: cpu-stress
spec:
schedulerName: crane-scheduler
hostNetwork: true
tolerations:
- key: node.kubernetes.io/network-unavailable
operator: Exists
effect: NoSchedule
containers:
- name: stress
image: docker.io/gocrane/stress:latest
command: ["stress", "-c", "1"]
resources:
requests:
memory: "1Gi"
cpu: "1"
limits:
memory: "1Gi"
cpu: "1"
如果想将crane-scheduler
用作默认调度器,请将crane-scheduler
更改为default-scheduler
(即在yaml中更改默认default-scheduler这一字段)。
如果测试 pod 调度成功,将会有以下事件:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 28s crane-scheduler Successfully assigned
default/cpu-stress-7669499b57-zmrgb to vm-162-247-ubuntu
K8S版本1.18-1.22请修改configmap和镜像版本
KUBE_EDITOR="sed -i 's/v1beta2/v1beta1/g'"
kubectl edit cm scheduler-config -n crane-system && KUBE_EDITOR="sed -i 's/0.0.23/0.0.20/g'"
kubectl edit deploy crane-scheduler -n crane-system
案例分享
Crane-scheduler目前有众多公有云用户,包括斗鱼直播、酷狗、一汽大众、猎豹移动等公司均在使用,并给予了产品不错的反馈。
这里我们先分享一个某公有云用户的真实案例。该客户集群中的业务大多是内存消耗型的,因此极易出现内存利用率很高的节点,并且各个节点的内存利用率分布也很不平均,如下图所示:
了解到用户的情况后,我们推荐其使用 Crane-scheduler,组件运行一段时间后,该用户集群内各节点的内存利用率数据分布发生了显著变化,如下图 :
可见,用户集群的内存使用率更加趋于均衡。
另外, Crane-scheduler 也在公司内部各个 BG 的自研上云环境中,也得到了广泛的使用。下面是内部自研上云平台 TKEx-CSIG 的两个生产集群的 CPU 使用率分布情况,其中集群 A 未部署 Crane-scheduler:
集群 B 部署了组件并运行过一段时间:
很明显,在集群 B 中,节点 CPU 使用率分布在两端( < 10% 与 > 80%)所占的比例,要显著小于集群 A,并且整体分布也更加紧凑,相对而言更加均衡与健康。