跳转到文档内容
版本:v1.5

基于集群资源模型的调度

概览

在将应用程序调度到特定集群时,目标集群的资源状态是一个不容忽视的因素。 例如,当集群资源不足以运行给定的实例时,我们希望调度器尽可能避免这种调度行为。 本文将重点介绍 Karmada 如何基于集群资源模型进行实例的调度。

集群资源模型

在调度过程中,karmada-scheduler 现在根据一系列因素做出决策,其中一个因素是集群的资源状态。 现在 Karmada 有两种不同的基于集群资源的调度方式,其中一种是通用的集群模型,另一种是自定义的集群模型。

通用集群资源模型

使用通用集群资源模型

出于上述目的,Karmada在Cluster API 引入了ResourceSummary的概念。

以下给出了一个ResourceSummary的例子:

resourceSummary:
allocatable:
cpu: "4"
ephemeral-storage: 206291924Ki
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 16265856Ki
pods: "110"
allocated:
cpu: 950m
memory: 290Mi
pods: "11"

从上面的例子中,我们可以知道集群的可分配资源和已分配资源。

基于通用集群资源模型的调度

假设在Karmada控制面上注册了三个成员集群,这时过来一个Pod的调度请求。

Member1:

resourceSummary:
allocatable:
cpu: "4"
ephemeral-storage: 206291924Ki
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 16265856Ki
pods: "110"
allocated:
cpu: 950m
memory: 290Mi
pods: "11"

Member2:

resourceSummary:
allocatable:
cpu: "4"
ephemeral-storage: 206291924Ki
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 16265856Ki
pods: "110"
allocated:
cpu: "2"
memory: 290Mi
pods: "11"

Member3:

resourceSummary:
allocatable:
cpu: "4"
ephemeral-storage: 206291924Ki
hugepages-1Gi: "0"
hugepages-2Mi: "0"
memory: 16265856Ki
pods: "110"
allocated:
cpu: "2"
memory: 290Mi
pods: "110"

假设这个Pod的资源请求是500m CPU。 显然,Member1和Member2有足够的资源来运行这个副本,但Member3没有Pod的配额。 考虑到可用资源的数量,调度器更倾向于将Pod调度到member1。

Clustermember1member2member3
AvailableReplicas(4 - 0.95) / 0.5 = 6.1(4 - 2) / 0.5 = 40

自定义集群资源模型

背景

ResourceSummary 描述了集群的整体可用资源。 但是,ResourceSummary不够精确,它机械地统计所有节点上的资源,而忽略了节点上的碎片资源。例如,一个有 2000 个节点的集群,每个节点上只剩下1核CPU。 从 ResourceSummary 中我们获知集群还有 2000核CPU,但事实上,这个集群甚至无法运行任何需要1核CPU以上的Pod实例。

因此,我们为每个集群引入了“自定义资源模型”的概念,来记录每个节点的资源画像。 Karmada将收集每个集群的节点和pod信息,并经过计算将这个节点被划分为对应等级的合适的资源模型。

启用自定义资源模型

自定义集群资源模型特性开关从Karmada v1.4后处于Beta阶段,并且默认开启。如果你使用Karmada v1.3,你需要在 karmada-schedulerkarmada-aggregated-serverkarmada-controller-manager 中开启 CustomizedClusterResourceModeling 特性开关。

例如,你可以使用以下命令打开 karmada-controller-manager 中的特性开关。

kubectl --kubeconfig ~/.kube/karmada.config --context karmada-host edit deploy/karmada-controller-manager -nkarmada-system
- command:
- /bin/karmada-controller-manager
- --kubeconfig=/etc/kubeconfig
- --bind-address=0.0.0.0
- --cluster-status-update-frequency=10s
- --secure-port=10357
- --feature-gates=CustomizedClusterResourceModeling=true
- --v=4

在开启特性开关后,当集群注册到 Karmada 控制面时,Karmada会自动为集群设置一个通用的资源模型。你可以在 cluster.spec 中看到它。

默认的资源模型如下:

resourceModels:
- grade: 0
ranges:
- max: "1"
min: "0"
name: cpu
- max: 4Gi
min: "0"
name: memory
- grade: 1
ranges:
- max: "2"
min: "1"
name: cpu
- max: 16Gi
min: 4Gi
name: memory
- grade: 2
ranges:
- max: "4"
min: "2"
name: cpu
- max: 32Gi
min: 16Gi
name: memory
- grade: 3
ranges:
- max: "8"
min: "4"
name: cpu
- max: 64Gi
min: 32Gi
name: memory
- grade: 4
ranges:
- max: "16"
min: "8"
name: cpu
- max: 128Gi
min: 64Gi
name: memory
- grade: 5
ranges:
- max: "32"
min: "16"
name: cpu
- max: 256Gi
min: 128Gi
name: memory
- grade: 6
ranges:
- max: "64"
min: "32"
name: cpu
- max: 512Gi
min: 256Gi
name: memory
- grade: 7
ranges:
- max: "128"
min: "64"
name: cpu
- max: 1Ti
min: 512Gi
name: memory
- grade: 8
ranges:
- max: "9223372036854775807"
min: "128"
name: cpu
- max: "9223372036854775807"
min: 1Ti
name: memory

自定义你的集群资源模型

在某些情况下,默认的集群资源模型可能与你的集群不相匹配。你可以调整集群资源模型的细粒度,以便更好地向集群下发资源。 例如,你可以使用以下命令编辑 member1 的集群资源模型。

kubectl --kubeconfig ~/.kube/karmada.config --context karmada-apiserver edit cluster/member1

自定义资源模型应满足以下要求:

  • 每个模型的等级不应该是相同的。
  • 每个模型中资源类型的数量应该相同。
  • 目前只支持 cpu, memory, storage, ephemeral-storage四种资源类型。
  • 每个资源的最大值必须大于最小值。
  • 第一个模型中每个资源的最小值应为 0。
  • 最后一个模型中每个资源的最大值应为 MaxInt64。
  • 每个模型的资源类型应该相同。
  • 从低等级到高等级的模型,资源的范围必须连续且不重叠。

例如:以下给出了一个自定义的集群资源模型:

resourceModels:
- grade: 0
ranges:
- max: "1"
min: "0"
name: cpu
- max: 4Gi
min: "0"
name: memory
- grade: 1
ranges:
- max: "2"
min: "1"
name: cpu
- max: 16Gi
min: 4Gi
name: memory
- grade: 2
ranges:
- max: "9223372036854775807"
min: "2"
name: cpu
- max: "9223372036854775807"
min: 16Gi
name: memory

上述是一个有三个等级的集群资源模型,每个等级分别定义了CPU和内存这两种资源的资源范围。这时如果一个节点的剩余可用资源为0.5核CPU和2Gi内存,则会被划分为0级的资源模型。如果这个节点的剩余可用资源为1.5核CPU和10Gi内存,则会被划分为1级。

基于自定义集群资源模型的调度

自定义集群资源模型将节点划分为不同区间的等级,并且当一个Pod实例需要调度到特定集群时,karmada-scheduler根据将要调度的实例资源请求比较不同集群中满足要求的节点数,并将实例调度到满足要求的节点数更多的集群。 假设有三个注册在Karmada控制面的成员集群,采用默认设置的集群资源模型,这些集群的剩余可用资源情况如下。

成员集群1:

spec:
...
- grade: 2
ranges:
- max: "4"
min: "2"
name: cpu
- max: 32Gi
min: 16Gi
name: memory
- grade: 3
ranges:
- max: "8"
min: "4"
name: cpu
- max: 64Gi
min: 32Gi
name: memory
...
...
status:
- count: 1
grade: 2
- count: 6
grade: 3

成员集群2:

spec:
...
- grade: 2
ranges:
- max: "4"
min: "2"
name: cpu
- max: 32Gi
min: 16Gi
name: memory
- grade: 3
ranges:
- max: "8"
min: "4"
name: cpu
- max: 64Gi
min: 32Gi
name: memory
...
...
status:
- count: 4
grade: 2
- count: 4
grade: 3

成员集群3:

spec:
...
- grade: 6
ranges:
- max: "64"
min: "32"
name: cpu
- max: 512Gi
min: 256Gi
name: memory
...
...
status:
- count: 1
grade: 6

假设这时过来一个Pod的调度请求,Pod的资源请求是3核CPU和20Gi内存。那么,Karmada认为所有满足等级2及以上的节点满足此要求。考虑到不同集群可用节点的数量,调度器更倾向于Pod调度到成员集群3。

Clustermember1member2member3
AvailableReplicas1 + 6 = 74 + 4 = 81 * min(32/3, 256/20) = 10

假设这时过来一个Pod的调度请求,Pod的资源请求是3核CPU和60Gi内存。那么,这时等级2的节点已经无法满足Pod所需所有资源的要求。考虑到不同集群可用节点的数量,调度器更倾向于Pod调度到成员集群1。

Clustermember1member2member3
AvailableReplicas6 * 1 = 64 * 1 = 41 * min(32/3, 256/60) = 4

禁用集群资源模型

在基于集群可用资源的动态副本分配场景中,调度器总是会参考资源模型来做出调度决策。 在资源建模的过程中,不论是通用集群资源建模还是自定义集群资源建模,Karmada都会从管理的所有集群中收集节点和Pod信息。 这在大规模场景中带来了不小的性能负担。

你可以通过在 karmada-controller-managerkarmada-agent 中将 --enable-cluster-resource-modeling 设置为 false 来禁用集群资源模型。