apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: koord-mid
value: 7000
description: "This priority class should be used for mid service pods only.(中层)"
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: koord-batch
value: 5000
description: "This priority class should be used for batch service pods only.(批处理)"
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: koord-free
value: 3000
description: "This priority class should be used for free service pods only.(空闲)"

## QoS
QoS 用于表达节点上 Pod 的运行质量,如获取资源的方式、获取资源的比例、QoS 保障策略等。Koordinator 调度系统支持的 QoS 有五种类型:
| QoS | 特点 | 说明 |
| -------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| SYSTEM | 系统进程,资源受限 | 对于 DaemonSets 等系统服务,虽然需要保证系统服务的延迟,但也需要限制节点上这些系统服务容器的资源使用,以确保其不占用过多的资源 |
| LSE(Latency Sensitive Exclusive) | 保留资源并组织同 QoS 的 pod 共享资源 | 很少使用,常见于中间件类应用,一般在独立的资源池中使用 |
| LSR(Latency Sensitive Reserved) | 预留资源以获得更好的确定性 | 类似于社区的 Guaranteed,CPU 核被绑定 |
| LS(Latency Sensitive) | 共享资源,对突发流量有更好的弹性 | 微服务工作负载的典型QoS级别,实现更好的资源弹性和更灵活的资源调整能力 |
| BE(Best Effort) | 共享不包括 LSE 的资源,资源运行质量有限,甚至在极端情况下被杀死 | 批量作业的典型 QoS 水平,在一定时期内稳定的计算吞吐量,低成本资源 |
Koordlet 根据 Pod 的优先级和 QoS 定义,触发相应的资源隔离和 QoS 保障,Koordinator 和 Kubernetes QoS 之间是有对应关系,如下所示:
| Koordinator QoS | Kubernetes QoS |
| --------------- | -------------------- |
| SYSTEM | --- |
| LSE | Guaranteed |
| LSR | Guaranteed |
| LS | Guaranteed/Burstable |
| BE | BestEffort |
# kubernetes服务质量等级:
Kubernetes(简称k8s)的QoS(Quality of Service,服务质量)等级有三种,分别是BestEffort、Burstable和Guaranteed。
Guaranteed级别:
- 含义:这是最高级别的QoS级别。在此级别下,Pod里的每个容器都必须有内存/CPU的限制和请求,而且值必须相等。如果一个容器只指明了limit而未设定request,则request的值等于limit值。此外,Pod被分配了足够的CPU和内存资源,能够保证容器始终有足够的资源来运行。
- 作用:Kubernetes会严格限制资源的使用,并且能够保证容器不会被内存和CPU锁死。当一个Pod被划分到这种QoS级别时,它会在可用资源范围内得到最大比例的资源分配。
Burstable级别:
- 含义:这是一种中级的QoS级别,Pod在此级别下会被分配一定的CPU和内存资源,但这些资源并不总是可用的。当系统中其他Pod消耗了更多的资源时,容器的资源可用性可能会受到影响。
- 作用:容器能够使用超过所分配的资源量(称为“突发资源”),但实际可用资源量取决于其他Pod和系统资源的占用情况。Kubernetes调度器会为这类Pod分配足够的资源,以满足它们的需求。
BestEffort级别:
- 含义:这是一种最低优先级的服务质量级别,主要用于无法保证服务的资源请求。在此级别下,Pod通常不会被分配任何CPU或内存资源。
- 作用:适用于一切不可用的情况,例如备份任务、流量转向等。Kubernetes会尽力让容器运行,但不保证容器的可用性。
## 如何区分Qos服务质量:
Guaranteed
- 如果满足以下条件,Pod 将分配有保证的 QoS 等级:
- Pod 中的所有容器都为 CPU 和内存设置了限制和请求。
- Pod 中的所有容器都具有相同的 CPU Limit 和 CPU Request 值。
- Pod 中所有容器都具有相同的 memory Limit 和 memory Request 值
Guaranteed Pod 在正常情况下不会被驱逐。
Burstable
- 如果满足以下条件,Pod 将分配有可突发的 QoS 等级:
- 它没有 Guaranteed QoS 等级。
- 已为 Pod 中的容器设置了 Limits 或 Requests 。
- Burstable Pod 可以被驱逐,但比下一个类别更不可能。
BestEffort
如果出现以下情况,Pod 将分配有 BestEffort 的 QoS 等级:
- Pod 中的任何容器都没有设置限制和请求。
- 在发生节点压力过程的情况下,BestEffort Pod 被驱逐的可能性最大。
重要提示:Limits 和 Requests 中可能还有其他资源,如 ephemeral-storage,但它们不用于 QoS Class 计算。
# koordinator负载感知调度
调度架构:

调度流程:
- 控制器把将要创建的pod同步到api server中。
- kubelet从koordlet拉取pod信息,并上报给APIserver中。
- koordlet将Node和Pods的资源使用情况报告NodeMetric。
- 调度新的Pod通过watch/list的机制监听到pod中字段nodename为空的进行调度。
- APIserver推送NodeMetric给调度器。
- 调度器通过扩展插件进行过滤,打分,保留等操作后,调度pod后进行绑定。
调度细节:

## 调度器参数配置
```shell
apiVersion: v1
kind: ConfigMap
metadata:
name: koord-scheduler-config
...
data:
koord-scheduler-config: |
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: koord-scheduler
plugins:
# 启用LoadAwareScheduling插件
filter:
enabled:
- name: LoadAwareScheduling
...
score:
enabled:
- name: LoadAwareScheduling
weight: 1
...
reserve:
enabled:
- name: LoadAwareScheduling
...
pluginConfig:
# 配置插件的阈值和权重
- name: LoadAwareScheduling
args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: LoadAwareSchedulingArgs
# 是否过滤koordlet无法更新NodeMetric的节点
filterExpiredNodeMetrics: true
# 使用NodeMetric时的到期阈值单位秒
nodeMetricExpirationSeconds: 300
# 资源权重
resourceWeights:
cpu: 1
memory: 1
# 资源利用率的阈值(%)
usageThresholds:
cpu: 75
memory: 85
# Prod Pods资源利用率阈值(%)
prodUsageThresholds:
cpu: 55
memory: 65
# 根据Prod的使用情况启用分数
scoreAccordingProdUsage: true
# 估计资源使用情况的因素(%)
estimatedScalingFactors:
cpu: 80
memory: 70
# 根据百分位数统计实现资源利用率过滤和评分
aggregated:
usageThresholds:
cpu: 65
memory: 75
usageAggregationType: "p99"
scoreAggregationType: "p99"
| 字段 | 说明 |
|---|---|
| filterExpiredNodeMetrics | filterExpiredNodeMetrics 表示是否过滤koordlet更新NodeMetric失败的节点。 默认情况下启用,但在 Helm chart 中,它被禁用。 |
| nodeMetricExpirationSeconds | nodeMetricExpirationSeconds 指示 NodeMetric 过期时间,当 NodeMetrics 过期时,节点被认为是异常的。 默认为 180 秒。 |
| resourceWeights | resourceWeights 表示资源的权重。 CPU 和 Memory 的权重默认都是 1。 |
| usageThresholds | usageThresholds 表示整机的资源利用率阈值。 CPU 的默认值为 65%,内存的默认值为 95%。 |
| estimatedScalingFactors | estimatedScalingFactors 表示估计资源使用时的因子。 CPU 默认值为 85%,Memory 默认值为 70%。 |
| prodUsageThresholds | prodUsageThresholds 表示 Prod Pod 相对于整机的资源利用率阈值。 默认情况下不启用。 |
| scoreAccordingProdUsage | scoreAccordingProdUsage 控制是否根据 Prod Pod 的利用率进行评分。 |
| aggregated | aggregated 支持基于百分位数统计的资源利用率过滤和评分。 |
Aggregated 支持的字段:
| 字段 | 说明 |
|---|---|
| usageThresholds | usageThresholds 表示机器基于百分位统计的资源利用率阈值。 |
| usageAggregationType | usageAggregationType 表示过滤时机器利用率的百分位类型。 目前支持avg、p50、p90、p95和p99。 |
| usageAggregatedDuration | usageAggregatedDuration 表示过滤时机器利用率百分位数的统计周期。不设置该字段时,调度器默认使用 NodeMetrics 中最大周期的数据。 |
| scoreAggregationType | scoreAggregationType 表示评分时机器利用率的百分位类型。 目前支持avg、p50、p90、p95和p99。 |
| scoreAggregatedDuration | scoreAggregatedDuration 表示打分时 Prod Pod 利用率百分位的统计周期。 不设置该字段时,调度器默认使用 NodeMetrics 中最大周期的数据。 |
按照节点配置过滤阈值
通过插件的配置可以作为集群默认的全局配置,用户也可以通过在节点上附加 annotation 来设置节点维度的负载阈值。 当节点上存在 annotation 时,会根据注解指定的参数进行过滤。
Annotation 定义如下:
const (
AnnotationCustomUsageThresholds = "scheduling.koordinator.sh/usage-thresholds"
)
//CustomUsageThresholds支持用户定义的节点资源利用阈值。
type CustomUsageThresholds struct {
// 使用阈值表示整个机器的资源利用率阈值。
UsageThresholds map[corev1.ResourceName]int64 `json:"usageThresholds,omitempty"`
// ProdUsageThresholds表示与整台机器相比,Prod Pods的资源利用率阈值
ProdUsageThresholds map[corev1.ResourceName]int64 `json:"prodUsageThresholds,omitempty"`
// AggregatedUsage支持基于百分位数统计的资源利用率过滤和评分
AggregatedUsage *CustomAggregatedUsage `json:"aggregatedUsage,omitempty"`
}
type CustomAggregatedUsage struct {
// 使用阈值表示基于百分位数统计的机器资源利用阈值
UsageThresholds map[corev1.ResourceName]int64 `json:"usageThresholds,omitempty"`
// UsageAggregationType表示过滤时机器利用率的百分位数类型
UsageAggregationType slov1alpha1.AggregationType `json:"usageAggregationType,omitempty"`
// UsageAggregatedDuration表示过滤时机器利用率的百分位数的统计周期
UsageAggregatedDuration *metav1.Duration `json:"usageAggregatedDuration,omitempty"`
}
koordinator负载感知重调度
目标
- 负载感知调度
- 调度器支持负载感知调度。
- 选择负载较低的节点运行新Pod。
- 集群环境变化的影响
- 时间、集群环境和工作负载流量会变化。
- 节点利用率随环境动态变化。
- 可能出现负载均衡被打破的情况。
- koord-descheduler的功能
- 感知集群内节点负载的变化。
- 自动优化超过负载水位安全阈值的节点。
- 防止极端负载不均衡的情况出现。
简介
koord-descheduler 组件中LowNodeLoad插件负责感知负载水位完成热点打散重调度工作。LowNodeLoad插件 与 Kubernetes 原生的 descheduler 的插件 LowNodeUtilization 不同的是,LowNodeLoad是根据节点真实利用率的情况决策重调度,而 LowNodeUtilization 是根据资源分配率决策重调度。
LowNodeLoad插件有两个最重要的参数:
- highThresholds 表示负载水位的目标安全阈值,超过该阈值的节点上的 Pod 将参与重调度;
- lowThresholds 表示负载水位的空闲安全水位。低于该阈值的节点上的 Pod 不会被重调度。
以下图为例,lowThresholds 为45%,highThresholds 为 70%,我们可以把节点归为三类:
- 空闲节点(Idle Node)。资源利用率低于 45% 的节点;
- 正常节点(Normal Node)。资源利用率高于 45% 但低于 70% 的节点,这个负载水位区间是我们期望的合理的区间范围
- 热点节点(Hotspot Node)。如果节点资源利用率高于70%,这个节点就会被判定为不安全了,属于热点节点,应该驱逐一部分 Pod,降低负载水位,使其不超过 70%。
在识别出哪些节点是热点后,koord-descheduler 将会执行迁移驱逐操作,驱逐热点节点中的部分 Pod 到空闲节点上。如果 Idle Node 数量是 0 或者 Hotspot Node 数量是 0,则 descheduler 不会执行任何操作。
如果一个集群中空闲节点的总数并不是很多时会终止重调度。这在大型集群中可能会有所帮助,在大型集群中,一些节点可能会经常或短时间使用不足。默认情况下,numberOfNodes 设置为零。可以通过设置参数 numberOfNodes 来开启该能力。
在迁移前,koord-descheduler 会计算出实际空闲容量,确保要迁移的 Pod 的实际利用率之和不超过集群内空闲总量。这些实际空闲容量来自于空闲节点,一个空闲节点实际空闲容量 = (highThresholds - 节点当前负载) * 节点总容量。假设节点 A 的负载水位是20%,highThresholdss是 70%,节点 A 的 CPU 总量为96C,那么 (70%-20%) * 96 = 48C,这 48C 就是可以承载的空闲容量了。
调度细节
在迁移热点节点时,会过滤筛选节点上的Pod,目前 koord-descheduler 支持多种筛选参数,可以避免迁移驱逐非常重要的 Pod:
- 按 namespace 过滤。可以配置成只筛选某些 namespace 或者过滤掉某些 namespace
- 按 pod selector 过滤。可以通过 label selector 筛选出 Pod,或者排除掉具备某些 Label 的 Pod
- 配置 nodeFit 检查调度规则是否有备选节点。当开启后,koord-descheduler 根据备选 Pod 对应的 Node Affinity/Node Selector/Toleration ,检查集群内是否有与之匹配的 Node,如果没有的话,该 Pod 将不会去驱逐迁移。如果设置 nodeFit 为 false,此时完全由 koord-descheduler 底层的迁移控制器完成容量预留,确保有资源后开始迁移。
当筛选出 Pod 后,从 QoSClass、Priority、实际用量和创建时间等多个维度对这些 Pod 排序。
筛选 Pod 并完成排序后,开始执行迁移操作。迁移前会检查剩余空闲容量是否满足和当前节点的负载水位是否高于目标安全阈值,如果这两个条件中的一个不能满足,将停止重调度。每迁移一个 Pod 时,会预扣剩余空闲容量,同时也会调整当前节点的负载水位,直到剩余容量不足或者水位达到安全阈值。
配置参数
负载感知重调度默认是禁用的。可以通过修改配置 ConfigMap koord-descheduler-config 启用该能力。
对于需要深入定制的用户,可以按照需要更改 Helm Chart 中的 ConfigMap koord-descheduler-config 设置参数。修改配置后需要重启 koord-descheduler 才能应用最新的配置。
apiVersion: v1
kind: ConfigMap
metadata:
name: koord-descheduler-config
...
data:
koord-descheduler-config: |
apiVersion: descheduler/v1alpha2
kind: DeschedulerConfiguration
...
# 每60秒执行一次LowNodeLoad插件
deschedulingInterval: 60s
profiles:
- name: koord-descheduler
plugins:
deschedule:
disabled:
- name: "*"
balance:
enabled:
- name: LowNodeLoad # 配置以启用LowNodeLoad插件
....
pluginConfig:
- name: LowNodeLoad
args:
apiVersion: descheduler/v1alpha2
kind: LowNodeLoadArgs
evictableNamespaces:
# 包含和排除是相互排斥的,只能配置其中一个。
# 包含表示仅处理下面配置的命名空间
# include:
# - test-namespace
# 排除意味着只处理下面配置的命名空间以外的命名空间
exclude:
- "kube-system"
- "koordinator-system"
# lowThresholds定义了资源的低使用阈值
lowThresholds:
cpu: 20
memory: 30
# highThresholds定义了资源的目标使用阈值
highThresholds:
cpu: 50
memory: 60
....apiVersion: v1
kind: ConfigMap
metadata:
name: koord-descheduler-config
...
data:
koord-descheduler-config: |
apiVersion: descheduler/v1alpha2
kind: DeschedulerConfiguration
...
# 每60秒执行一次LowNodeLoad插件
deschedulingInterval: 60s
profiles:
- name: koord-descheduler
plugins:
deschedule:
disabled:
- name: "*"
balance:
enabled:
- name: LowNodeLoad # 配置以启用LowNodeLoad插件
....
pluginConfig:
- name: LowNodeLoad
args:
apiVersion: descheduler/v1alpha2
kind: LowNodeLoadArgs
evictableNamespaces:
# 包含和排除是相互排斥的,只能配置其中一个。
# 包含表示仅处理下面配置的命名空间
# include:
# - test-namespace
# 排除意味着只处理下面配置的命名空间以外的命名空间
exclude:
- "kube-system"
- "koordinator-system"
# lowThresholds定义了资源的低使用阈值
lowThresholds:
cpu: 20
memory: 30
# highThresholds定义了资源的目标使用阈值
highThresholds:
cpu: 50
memory: 60
....
| 字段 | 说明 |
|---|---|
| paused | Paused 控制 LowNodeLoad 插件是否工作. |
| dryRun | DryRun 表示只执行重调度逻辑,但不重复啊迁移/驱逐 Pod |
| numberOfNodes | NumberOfNodes 可以配置为仅当未充分利用的节点数高于配置值时才激活该策略。 这在大型集群中可能会有所帮助,在大型集群中,一些节点可能会经常或短时间使用不足。 默认情况下,NumberOfNodes 设置为零。 |
| evictableNamespaces | 可以参与重调度的Namespace。可以配置 include和exclude两种,但两种策略只能二选一。include 表示只处理指定的 namespace;exclude 表示只处理指定之外的namespace。 |
| nodeSelector | 通过 label selector 机制选择目标节点。 |
| podSelectors | 通过 label selector 选择要处理的Pod。 |
| nodeFit | 表示是否按照备选要迁移的Pod中指定的 Node Affinity/Node Selector/Resource Requests/TaintToleration 判断是否有空闲节点。没有则不参与调度。默认开启。可以设置为 false 禁用该能力。 |
| useDeviationThresholds | 如果 useDeviationThresholds 设置为 true,则阈值被视为与平均资源使用率的百分比偏差。lowThresholds 将从所有节点的平均值中减去,highThresholds 将添加到平均值中。高于此窗口的资源消耗被视为过度利用的,即热点节点。 |
| highThresholds | 表示负载水位的目标安全阈值,超过该阈值的节点上的Pod将参与重调度。 |
| lowThresholds | 表示负载水位的空闲安全水位。低于该阈值的节点上的Pod不会被重调度。 |
评论区