↗️️ 点击 Readme 可视化右上角的 [bullet list icon],以查看由 github 生成的目录。
Kubernetes 的 Descheduler
Kubernetes 中的调度是将待处理 Pod 绑定到节点的过程,由 Kubernetes 的一个名为 kube-scheduler 的组件执行。调度器的决策,即 Pod 是否可以或在哪里被调度,由其可配置的策略指导,该策略由一组称为谓词(predicates)和优先级(priorities)的规则组成。调度器的决策受其在新的 Pod 出现需要调度时点对 Kubernetes 集群视图的影响。 由于 Kubernetes 集群非常动态且其状态随时间变化,出于各种原因,可能需要将已在运行的 Pod 迁移到其他节点:
- 某些节点利用率过低或过高。
- 由于节点上添加或移除了污点(taints)或标签(labels),Pod/节点亲和性要求不再满足,因此最初的调度决策不再成立。
- 某些节点发生故障,其 Pod 已迁移到其他节点。
- 集群中添加了新节点。
因此,集群中可能有多个 Pod 被调度到不太理想的节点上。 Descheduler 根据其策略,找到可以迁移的 Pod 并将其驱逐。请注意,在当前实现中,descheduler 不负责调度被驱逐 Pod 的替代者,而是依赖默认调度器来完成此任务。
⚠️ 按版本划分的文档版本
如果您使用的是 Descheduler 的已发布版本(例如
registry.k8s.io/descheduler/descheduler:v0.36.0),请遵循该版本发布分支中的文档,如下所列:
| Descheduler 版本 | 文档链接 |
|---|---|
| v0.36.x | release-1.36 |
| v0.35.x | release-1.35 |
| v0.34.x | release-1.34 |
| v0.33.x | release-1.33 |
| v0.32.x | release-1.32 |
| v0.31.x | release-1.31 |
| v0.30.x | release-1.30 |
The
master
分支被视为开发中,其中提供的信息可能不适用于之前的版本。
快速开始
Descheduler 可以作为 k8s 集群中的 Job、CronJob 或 Deployment 运行。它的优势在于可以多次运行而无需用户干预。
Descheduler pod 作为关键 pod 在 kube-system 命名空间中运行,以避免被自身或 kubelet 驱逐。
作为 Job 运行
kubectl create -f kubernetes/base/rbac.yaml
kubectl create -f kubernetes/base/configmap.yaml
kubectl create -f kubernetes/job/job.yaml
作为 CronJob 运行
kubectl create -f kubernetes/base/rbac.yaml
kubectl create -f kubernetes/base/configmap.yaml
kubectl create -f kubernetes/cronjob/cronjob.yaml
作为部署运行
kubectl create -f kubernetes/base/rbac.yaml
kubectl create -f kubernetes/base/configmap.yaml
kubectl create -f kubernetes/deployment/deployment.yaml
使用 Helm 安装
从 v0.18.0 版本开始,提供了一个官方的 helm chart,可用于安装 descheduler。有关详细说明,请参阅 helm chart README。
descheduler 的 helm chart 也列在 artifact hub 上。
使用 Kustomize 安装
你可以使用 kustomize 来安装 descheduler。 有关详细说明,请参阅 resources | Kustomize。
Run As A Job
kustomize build 'github.com/kubernetes-sigs/descheduler/kubernetes/job?ref=release-1.34' | kubectl apply -f -
Run As A CronJob
kustomize build 'github.com/kubernetes-sigs/descheduler/kubernetes/cronjob?ref=release-1.34' | kubectl apply -f -
Run As A Deployment
kustomize build 'github.com/kubernetes-sigs/descheduler/kubernetes/deployment?ref=release-1.34' | kubectl apply -f -
用户指南
请参阅 /docs 目录中的 用户指南。
策略、默认驱逐器和策略插件
Descheduler 策略是可配置的,包含可以启用或禁用的默认策略插件。它包含顶层的通用驱逐配置,以及来自 Evictor 插件的配置(如果未另行指定,则为 Default Evictor)。顶层配置和 Evictor 插件配置应用于所有驱逐操作。
顶层配置
这些是 Descheduler 策略中的顶层键,可用于配置所有驱逐操作。
| Name | type | Default Value | Description |
|---|---|---|---|
nodeSelector | string | nil | 限制被处理的节点。仅在 nodeFit=true 时由 PreEvictionFilter 扩展点使用。 |
maxNoOfPodsToEvictPerNode | int | nil | 从每个节点驱逐的 Pod 最大数量(所有策略的总和)。 |
maxNoOfPodsToEvictPerNamespace | int | nil | 从每个命名空间驱逐的 Pod 最大数量(所有策略的总和)。 |
maxNoOfPodsToEvictTotal | int | nil | 每个重新调度周期驱逐的 Pod 最大数量(所有策略的总和)。 |
metricsCollector (deprecated) | object | nil | 配置实际资源利用率指标的收集。 |
metricsCollector.enabled | bool | false | 启用 Kubernetes Metrics Server 收集。 |
metricsProviders | []object | nil | 启用各种指标提供程序,例如 Kubernetes Metrics Server |
evictionFailureEventNotification | bool | false | 启用驱逐失败事件通知。 |
gracePeriodSeconds | int | nil | 对象应被删除前的持续时间(以秒为单位)。值零表示立即删除。如果此值为 nil,则将使用指定类型的默认宽限期。 |
prometheus | object | nil | 配置收集 Prometheus 指标以监控实际资源使用情况 |
prometheus.url | string | nil | 指向 Prometheus 服务器 URL |
prometheus.authToken | object | nil | 设置 Prometheus 服务器身份验证令牌。如果未指定,则从容器的文件系统读取集群身份验证令牌。 |
prometheus.authToken.secretReference | object | nil | 从 kubernetes secret 读取身份验证令牌(预期该 secret 在 prometheusAuthToken 数据键下包含令牌) |
prometheus.authToken.secretReference.namespace | string | nil | 身份验证令牌 kubernetes secret 命名空间(目前,RBAC 配置允许从 kube-system 命名空间检索 secret。如果 secret 需要从其他命名空间访问,必须显式扩展现有的 RBAC 规则。 |
prometheus.authToken.secretReference.name | string | nil | 身份验证令牌 kubernetes secret 名称 |
Descheduler 目前允许通过 metricsProviders 字段配置 Kubernetes Metrics 的指标采集。
之前设置 metricsCollector 字段的方式已弃用。当前有两种配置来源:
KubernetesMetrics:启用从 Kubernetes Metrics 服务器采集指标Prometheus:启用从 Prometheus 服务器采集指标
通常,每个插件可以从不同的提供者消费指标,因此可以并行配置多个不同的提供者。
Evictor 插件配置(默认 Evictor)
默认 Evictor 插件默认用于在策略插件处理 Pod 之前对其进行过滤,或在驱逐前应用 Pod 的 PreEvictionFilter。您也可以创建自己的 Evictor 插件,或使用 Descheduler 提供的默认插件。Evictor 插件的其他用途可以包括根据不同的标准对 Pod 进行排序、过滤、验证或分组,这就是为什么这由插件处理而不是在顶层配置中配置的原因。
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
nodeSelector | string | nil | 限制被处理的节点。 |
evictLocalStoragePods | bool | false | [已弃用:请改用 podProtections 和 "PodsWithLocalStorage"]允许驱逐使用本地存储的 Pod。 |
evictDaemonSetPods | bool | false | [已弃用:请改用 podProtections 和 "DaemonSetPods"]允许驱逐由 DaemonSet 管理的 Pod。 |
evictSystemCriticalPods | bool | false | [已弃用:请改用 podProtections 配合 "SystemCriticalPods"][警告:将驱逐 Kubernetes 系统 Pod] 允许驱逐具有任何优先级的 Pod,包括 kube-dns 等关键系统 Pod。 |
ignorePvcPods | bool | false | [已弃用:请改用 podProtections 配合 "PodsWithPVC"]设置是否应驱逐或忽略 PVC Pod。 |
evictFailedBarePods | bool | false | [已弃用:请改用 podProtections 配合 "FailedBarePods"]允许驱逐没有属主引用且处于失败阶段的 Pod。 |
ignorePodsWithoutPDB | bool | false | [已弃用:请改用 podProtections 配合 "PodsWithoutPDB"]设置是否应驱逐或忽略没有 PodDisruptionBudget 的 Pod。 |
namespaceLabelSelector | metav1.LabelSelector | 限制按命名空间处理的 Pod(参见 标签过滤) | |
labelSelector | metav1.LabelSelector | (参见 标签过滤) | |
priorityThreshold | priorityThreshold | (参见 优先级过滤) | |
nodeFit | bool | false | (参见 节点适配过滤) |
minReplicas | uint | 0 | 忽略驱逐其所有者(例如,ReplicaSet)副本数低于此阈值的 Pod。 |
minPodAge | metav1.Duration | 0 | 忽略驱逐创建时间在此阈值内的 Pod。 |
noEvictionPolicy | enum | `` | sets whether a descheduler.alpha.kubernetes.io/prefer-no-eviction Pod 注解被视为首选或强制。接受的值:""、"Preferred"、"Mandatory"。默认为 "Preferred"。 |
podProtections | PodProtections | {} | 保存已启用和已禁用的保护 Pod 策略列表。 用户可以有选择地禁用某些默认保护规则或启用额外的规则。支持的取值见下文。 |
podProtections.DefaultDisabled 的受支持值
在
defaultDisabled中设置值会禁用对应的默认保护规则。这意味着指定类型的 Pod 将不再受到保护免于驱逐,如果满足其他条件,可能会被驱逐。
| 值 | 含义 |
|---|---|
"PodsWithLocalStorage" | 允许驱逐使用本地存储的 Pod。 |
"DaemonSetPods" | 允许驱逐由 DaemonSet 管理的 Pod。 |
"SystemCriticalPods" | 允许驱逐系统关键 Pod。 |
"FailedBarePods" | 允许驱逐失败的裸 Pod(无控制器)。 |
podProtections.ExtraEnabled 的受支持值
在
extraEnabled中设置值会启用额外的保护规则。这意味着指定类型的 Pod 将受到保护,免于被驱逐。
| 值 | 含义 |
|---|---|
"PodsWithPVC" | 防止使用持久卷声明(PVC)的 Pod 被驱逐。 |
"PodsWithoutPDB" | 防止没有 PodDisruptionBudget(PDB)的 Pod 被驱逐。 |
"PodsWithResourceClaims" | 防止使用 ResourceClaims 的 Pod 被驱逐。 |
保护使用特定 Storage Class 的 Pod
启用 PodsWithPVC 保护后,所有使用 PVC 的 Pod 默认都会受到驱逐保护,如有需要,您可以通过按 PVC 存储类进行过滤来限制保护范围。当按存储类过滤时,只有使用指定存储类的 PVC 的 Pod 才会受到驱逐保护。例如:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "DefaultEvictor"
args:
podProtections:
extraEnabled:
- PodsWithPVC
config:
PodsWithPVC:
protectedStorageClasses:
- name: storage-class-0
- name: storage-class-1
此示例将保护使用存储类 storage-class-0 和 storage-class-1 的 PVC 的 Pod,使其免于被驱逐。
策略示例
作为该策略的一部分,您将开始决定使用哪个顶层配置,然后决定使用哪个 Evictor 插件(如果您有自己的插件则使用自己的,否则使用 Default Evictor),接着决定传递给 Evictor 插件的配置。默认情况下,Default Evictor 在 filter 和 preEvictionFilter 扩展点处均已启用。之后,您将启用/禁用驱逐策略插件并对其进行正确配置。
有关可用参数的详细信息,请参阅各策略插件部分。
策略:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
nodeSelector: "node=node1" # you don't need to set this, if not set all will be processed
maxNoOfPodsToEvictPerNode: 5000 # you don't need to set this, unlimited if not set
maxNoOfPodsToEvictPerNamespace: 5000 # you don't need to set this, unlimited if not set
maxNoOfPodsToEvictTotal: 5000 # you don't need to set this, unlimited if not set
gracePeriodSeconds: 60 # you don't need to set this, 0 if not set
# you don't need to set this, metrics are not collected if not set
metricsProviders:
- source: Prometheus
prometheus:
url: http://prometheus-kube-prometheus-prometheus.prom.svc.cluster.local
authToken:
secretReference:
namespace: "kube-system"
name: "authtoken"
profiles:
- name: ProfileName
pluginConfig:
- name: "DefaultEvictor"
args:
podProtections:
defaultDisabled:
#- "PodsWithLocalStorage"
#- "SystemCriticalPods"
#- "DaemonSetPods"
#- "FailedBarePods"
extraEnabled:
#- "PodsWithPVC"
#- "PodsWithoutPDB"
#- "PodsWithResourceClaims"
config: {}
nodeFit: true
minReplicas: 2
plugins:
# DefaultEvictor is enabled for both `filter` and `preEvictionFilter`
# filter:
# enabled:
# - "DefaultEvictor"
# preEvictionFilter:
# enabled:
# - "DefaultEvictor"
deschedule:
enabled:
- ...
balance:
enabled:
- ...
[...]
下图提供了大多数策略的可视化,以帮助 对策略如何相互结合进行分类。

以下章节概述了可用的不同策略插件。这些插件根据其实现的扩展点进行分组:Deschedule 或 Balance。
Deschedule 插件:这些插件逐个处理 pod,并以顺序方式驱逐它们。
Balance 插件:这些插件处理所有 pod 或 pod 组,并根据组的预期分布情况确定要驱逐哪些 pod。
| 名称 | 实现的扩展点 | 描述 |
|---|---|---|
| RemoveDuplicates | Balance | 分散副本 |
| LowNodeUtilization | Balance | 根据 pod 的资源请求和节点可用资源分散 pod |
| HighNodeUtilization | Balance | 根据 pod 的资源请求和节点可用资源分散 pod |
| RemovePodsViolatingInterPodAntiAffinity | Deschedule | 驱逐违反 pod 反亲和性的 pod |
| RemovePodsViolatingNodeAffinity | Deschedule | 驱逐违反节点亲和性的 pod |
| RemovePodsViolatingNodeTaints | Deschedule | 驱逐违反节点污点的 pod |
| RemovePodsViolatingTopologySpreadConstraint | Balance | 驱逐违反 TopologySpreadConstraints 的 pod |
| RemovePodsHavingTooManyRestarts | Deschedule | 驱逐重启次数过多的 pod |
| PodLifeTime | Deschedule | 根据年龄、状态转换、条件、状态、退出代码和所有者类型驱逐 pod |
| RemoveFailedPods | Deschedule | 驱逐具有特定失败原因和退出代码的 pod |
RemoveDuplicates
此策略插件确保在同一节点上运行的 ReplicaSet (RS)、ReplicationController (RC)、StatefulSet 或 Job 仅关联一个 Pod。如果存在多个, 这些重复的 Pod 将被驱逐,以更好地在集群中分散 Pod。如果某些节点因各种原因宕机,且其上的 Pod 被迁移到其他节点,导致 例如在同一节点上运行多个关联同一 RS 或 RC 的 Pod,则可能出现此问题。一旦故障节点 恢复就绪,可以启用此策略来驱逐这些重复的 Pod。
它提供一个可选参数 excludeOwnerKinds,这是一个 OwnerRef Kind 列表。如果某个 Pod
的 Kind 中列出了这些 OwnerRef 中的任意一个,则该 Pod 不会被考虑驱逐。请注意,
由 Deployment 创建的 Pod 会被此策略考虑驱逐。excludeOwnerKinds 参数
应包含 ReplicaSet,以排除由 Deployment 创建的 Pod。
Parameters:
| Name | Type |
|---|---|
excludeOwnerKinds | list(string) |
namespaces | (see namespace filtering) |
Example:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemoveDuplicates"
args:
excludeOwnerKinds:
- "ReplicaSet"
plugins:
balance:
enabled:
- "RemoveDuplicates"
LowNodeUtilization
此策略查找利用率较低的节点,并尽可能从其他节点驱逐 Pod,
希望被驱逐 Pod 的重新创建会被调度到这些利用率较低的节点上。此策略的参数
在 nodeResourceUtilizationThresholds 下配置。
节点的利用率不足由可配置的阈值 thresholds 决定。阈值
thresholds 可以针对 cpu、memory、pods 数量以及以百分比表示的扩展资源进行配置(该百分比
计算为节点上当前请求的资源与 total allocatable 之比。
对于 pods,这意味着节点上的 pods 数量占为该节点设置的 pod 容量的比例)。
如果节点在所有(cpu、memory、pods 数量和扩展资源)方面的使用率均低于阈值,则该节点被视为利用率不足。 目前,计算节点资源利用率时考虑的是 pods 请求的资源需求。
还有另一个可配置的阈值 targetThresholds,用于计算可能驱逐 pods 的潜在节点。
如果节点在任何(cpu、memory、pods 数量或扩展资源)方面的使用率高于 targetThreshold,
则该节点被视为过度利用。位于阈值 thresholds 和 targetThresholds 之间的任何节点
都被视为适当利用,并且不会被考虑用于驱逐。阈值 targetThresholds
也可以针对 cpu、memory 和 pods 数量以百分比进行配置。
这些阈值 thresholds 和 targetThresholds 可以根据您的集群需求进行调整。请注意,此
策略会将 pods 从 overutilized nodes(使用率高于 targetThresholds 的节点)迁移到 underutilized nodes
(使用率低于 thresholds 的节点),如果 underutilized nodes 或 overutilized nodes 的数量为零,它将中止。
此外,该策略接受一个 useDeviationThresholds 参数。
如果该参数设置为 true,则阈值被视为相对于平均资源使用率的百分比偏差。
将从所有节点的平均值中扣除 thresholds,并将 targetThresholds 加到平均值上。
高于(或低于)此窗口的资源消耗被视为过度利用(或资源利用不足)。
注意: 默认情况下,节点资源消耗由 Pod 的请求和限制决定,而非实际使用情况。
选择此方法是为了与 kube-scheduler 保持一致,后者在将 Pod 调度到节点时遵循相同的设计。这意味着 Kubelet(或类似 kubectl top 的命令)报告的资源使用情况可能与计算得出的消耗量不同,因为这些组件报告的是
实际使用指标。可以通过设置 metricsUtilization.metricsServer 字段(已弃用)
或 metricsUtilization.source 字段为 KubernetesMetrics 来启用基于指标的驱逐。
为了使插件消费指标,还需要配置指标提供程序。
或者,可以创建一个 prometheus 客户端并配置 prometheus 查询,以在 kubernetes metrics server 之外消费
指标。该查询预期返回每个节点的值向量。
预期这些值是 <0; 1> 区间内的任意实数。在驱逐期间,每个过载节点最多只驱逐
一个 Pod。目前不支持驱逐更多 Pod。
请参阅 顶层配置 中的 metricsProviders 字段以了解可用选项。
参数:
| 名称 | 类型 |
|---|---|
useDeviationThresholds | bool |
thresholds | map(string:int) |
targetThresholds | map(string:int) |
numberOfNodes | int |
evictionLimits | object |
evictableNamespaces | (参见 命名空间过滤) |
metricsUtilization | object |
metricsUtilization.metricsServer (已弃用) | bool |
metricsUtilization.source | string |
metricsUtilization.prometheus.query | string |
示例:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "LowNodeUtilization"
args:
thresholds:
"cpu" : 20
"memory": 20
"pods": 20
targetThresholds:
"cpu" : 50
"memory": 50
"pods": 50
# metricsUtilization:
# source: Prometheus
# prometheus:
# query: instance:node_cpu:rate:sum
evictionLimits:
node: 5
plugins:
balance:
enabled:
- "LowNodeUtilization"
策略应通过以下验证检查:
- 支持三种基本原生资源类型:
cpu、memory和pods。 如果未指定其中任何一种资源类型,其所有阈值将默认为 100%,以避免节点从利用率不足变为利用率过高。 - 支持扩展资源。例如,资源类型
nvidia.com/gpu用于指定 GPU 节点利用率。扩展资源是可选的, 如果未在thresholds和targetThresholds中明确指定,则不会用于计算节点的使用情况。 thresholds或targetThresholds不能为 nil,且它们必须配置完全相同类型的资源。- 资源百分比值的有效范围是 [0, 100]
- 对于同一资源,
thresholds的百分比值不能大于targetThresholds。
与 LowNodeUtilization 策略相关的还有两个参数,称为 numberOfNodes 和 evictionLimits。
第一个参数可以配置为仅在利用率不足的节点数量超过配置值时激活该策略。这在大型集群中可能很有帮助,因为少数节点可能会频繁或短时间内出现利用率不足的情况。默认情况下,numberOfNodes 设置为零。
第二个参数在需要限制每个插件在每个调度周期内的驱逐数量时很有用。
该参数目前通过 node 字段来限制每个节点的驱逐数量。
HighNodeUtilization
该策略会查找利用率较低的节点,并从这些节点中驱逐 Pod,以期这些 Pod 能够紧凑地调度到更少的节点上。与节点自动扩缩容配合使用时,该策略旨在帮助触发对利用率较低节点的缩容。
该策略必须与调度器评分策略 MostAllocated 一起使用。该策略的参数在 nodeResourceUtilizationThresholds 下配置。
注意:在 GKE 上,无法自定义默认的调度器配置。相反,您可以使用
optimze-utilization自动扩缩容策略,其效果与启用MostAllocated调度器插件相同。或者,您可以部署第二个自定义调度器并自行编辑该调度器的配置。
节点的利用率较低是通过可配置的阈值 thresholds 来确定的。阈值
thresholds 可以针对 CPU、内存、Pod 数量以及以百分比表示的扩展资源进行配置。该百分比
计算为节点上当前请求的资源与 总可分配量 之比。
对于 Pod 而言,这意味着节点上的 Pod 数量占为该节点设置的 Pod 容量的比例。
如果节点在所有方面(CPU、内存、Pod 数量和扩展资源)的使用率均低于阈值,则该节点被视为利用率较低。
目前,在计算节点资源利用率时,会考虑 Pod 请求的资源需求。
任何高于 thresholds 的节点都被视为利用率适当,不会被考虑进行驱逐。
thresholds 参数可以根据您的集群需求进行调整。请注意,此策略会从 underutilized nodes(使用率低于 thresholds 的节点)中驱逐 Pod,以便它们可以在利用率适当的节点上重新创建。
如果 underutilized nodes 或 appropriately utilized nodes 中任何一个的数量为零,该策略将中止。
要控制从利用率不足的节点中驱逐 Pod,请使用 evictionModes
数组。默认策略是一种宽松策略,无论 Pod 的资源请求如何都会驱逐 Pod。要启用一种更严格的策略,仅驱逐为提供的阈值资源定义了资源请求的 Pod,请将
选项 OnlyThresholdingResources 添加到 evictionModes 配置中。
注意: 节点资源消耗由 Pod 的请求和限制决定,而非实际使用量。
选择这种方法是为了保持与 kube-scheduler 的一致性,kube-scheduler 在将 Pod 调度到节点时遵循相同的设计。这意味着 Kubelet(或 kubectl top 等命令)报告的资源使用量可能与计算出的消耗量不同,因为这些组件报告的是
实际使用指标。基于指标的重新调度目前是该项目的待办事项。
参数:
| 名称 | 类型 |
|---|---|
thresholds | map(string:int) |
numberOfNodes | int |
evictionModes | list(string) |
evictableNamespaces | (参见 命名空间过滤) |
支持的驱逐模式:
| 名称 | 描述 |
|---|---|
OnlyThresholdingResources | 仅驱逐为提供的阈值资源定义了资源请求的 Pod。 |
示例:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "HighNodeUtilization"
args:
thresholds:
"cpu" : 20
"memory": 20
"pods": 20
evictableNamespaces:
exclude:
- "kube-system"
- "namespace1"
evictionModes:
- "OnlyThresholdingResources"
plugins:
balance:
enabled:
- "HighNodeUtilization"
策略应通过以下验证检查:
- 支持三种基本原生资源类型:
cpu、memory和pods。如果未指定其中任何一种资源类型,其所有阈值默认为 100%。 - 支持扩展资源。例如,资源类型
nvidia.com/gpu用于指定 GPU 节点利用率。扩展资源是可选的,如果未在thresholds中明确指定,则不会用于计算节点的使用率。 thresholds不能为 nil。- 资源百分比值的有效范围是 [0, 100]
与 HighNodeUtilization 策略相关的另一个参数称为 numberOfNodes。
可以配置此参数,仅在低利用率节点数量超过配置值时激活该策略。这在大型集群中可能很有帮助,因为少数节点可能会频繁或短时间内处于低利用率状态。默认情况下,numberOfNodes 设置为零。
RemovePodsViolatingInterPodAntiAffinity
此策略确保违反 Pod 间反亲和性的 Pod 从节点上移除。例如, 如果节点上有 podA,而 podB 和 podC(运行在同一节点上)具有禁止它们运行在同一节点上的反亲和性规则, 那么 podA 将从该节点上驱逐,以便 podB 和 podC 可以运行。当 podB 和 podC 已经在节点上运行时, 如果为它们创建反亲和性规则,则可能会出现此问题。
参数:
| 名称 | 类型 |
|---|---|
namespaces | (参见 命名空间过滤) |
labelSelector | (参见 标签过滤) |
示例:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemovePodsViolatingInterPodAntiAffinity"
plugins:
deschedule:
enabled:
- "RemovePodsViolatingInterPodAntiAffinity"
RemovePodsViolatingNodeAffinity
此策略确保所有违反
node affinity
的 pod 最终从节点上移除。Node affinity 规则允许 pod 指定
requiredDuringSchedulingIgnoredDuringExecution 和/或
preferredDuringSchedulingIgnoredDuringExecution。
requiredDuringSchedulingIgnoredDuringExecution 类型告诉调度器
在调度 pod 时尊重 node affinity,但告诉 kubelet 在节点随时间变化且不再满足 affinity 时忽略它。
启用后,该策略作为 requiredDuringSchedulingRequiredDuringExecution 的临时实现,
并驱逐不再满足 node affinity 的 kubelet 上的 pod。
例如,podA 被调度到 nodeA 上,在调度时满足 node
affinity 规则 requiredDuringSchedulingIgnoredDuringExecution。随着时间推移,nodeA 不再满足该规则。当策略执行时,
如果存在另一个满足 node affinity 规则的可用节点,
podA 将从 nodeA 上被驱逐。
preferredDuringSchedulingIgnoredDuringExecution 类型告诉调度器
在可能的情况下调度时尊重 node affinity。如果不可能,pod
仍会被调度。可能会发生这种情况:随着时间推移,集群状态
发生变化,现在 pod 可以被调度到一个实际符合其
preferred node affinity 的节点上。启用后,该策略作为 preferredDuringSchedulingPreferredDuringExecution 的临时
实现,因此如果 pod 可以被调度到“更好”的节点上,它将被驱逐。
Parameters:
| Name | Type |
|---|---|
nodeAffinityType | list(string) |
namespaces | (see namespace filtering) |
labelSelector | (see label filtering) |
Example:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemovePodsViolatingNodeAffinity"
args:
nodeAffinityType:
- "requiredDuringSchedulingIgnoredDuringExecution"
plugins:
deschedule:
enabled:
- "RemovePodsViolatingNodeAffinity"
RemovePodsViolatingNodeTaints
此策略确保移除违反节点上 NoSchedule 污点的 Pod。例如,存在一个名为 "podA" 的 Pod,其容忍度允许容忍污点 key=value:NoSchedule,并且该 Pod 已调度并在带有该污点的节点上运行。如果随后更新或移除了该节点的污点,且该污点不再被其 Pod 的容忍度所满足,则该 Pod 将被驱逐。
可以通过指定 excludedTaints 列表来将节点污点排除在考虑范围之外。如果节点污点的键 或 key=value 与 excludedTaints 中的某个条目匹配,则该污点将被忽略。
例如,excludedTaints 条目 "dedicated" 将匹配所有键为 "dedicated" 的污点,无论其值为何。excludedTaints 条目 "dedicated=special-user" 将匹配键为 "dedicated" 且值为 "special-user" 的污点。
如果提供了 includedTaints 列表,则当且仅当污点匹配列表中的某个 included 键 或 key=value 时,该污点才会被考虑。否则将被忽略。如果不设置 includedTaints,则默认包含任何污点。
Parameters:
| Name | Type |
|---|---|
excludedTaints | list(string) |
includedTaints | list(string) |
includePreferNoSchedule | bool |
namespaces | (see namespace filtering) |
labelSelector | (see label filtering) |
Example:
Setting excludedTaints
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemovePodsViolatingNodeTaints"
args:
excludedTaints:
- dedicated=special-user # exclude taints with key "dedicated" and value "special-user"
- reserved # exclude all taints with key "reserved"
plugins:
deschedule:
enabled:
- "RemovePodsViolatingNodeTaints"
Setting includedTaints
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemovePodsViolatingNodeTaints"
args:
includedTaints:
- decommissioned=end-of-life # include only taints with key "decommissioned" and value "end-of-life"
- reserved # include all taints with key "reserved"
plugins:
deschedule:
enabled:
- "RemovePodsViolatingNodeTaints"
RemovePodsViolatingTopologySpreadConstraint
该策略确保违反 topology spread constraints
的 pods 从节点上被驱逐。具体来说,它尝试驱逐最少数量的 pods,以使拓扑域平衡到每个约束的 maxSkew 范围内。
该策略至少需要 k8s 版本 1.18。
默认情况下,该策略仅包含硬约束,您可以显式设置 constraints 以同时包含两者,如下所示:
constraints:
- DoNotSchedule
- ScheduleAnyway
topologyBalanceNodeFit 参数用于平衡拓扑域时,而 Default Evictor 的 nodeFit 用于预驱逐阶段,以确定 pod 是否可以被驱逐。
topologyBalanceNodeFit: false
策略参数 labelSelector 在平衡拓扑域时不会被使用,仅在驱逐阶段应用,以确定 pod 是否可以被驱逐。
| 名称 | 是否支持? |
|---|---|
maxSkew | 是 |
minDomains | 否 |
topologyKey | 是 |
whenUnsatisfiable | 是 |
labelSelector | 是 |
matchLabelKeys | 是 |
nodeAffinityPolicy | 是 |
nodeTaintsPolicy | 是 |
参数:
| 名称 | 类型 |
|---|---|
namespaces | (参见 namespace filtering) |
labelSelector | (参见 label filtering) |
constraints | (参见 whenUnsatisfiable) |
topologyBalanceNodeFit | bool |
示例:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemovePodsViolatingTopologySpreadConstraint"
args:
constraints:
- DoNotSchedule
plugins:
balance:
enabled:
- "RemovePodsViolatingTopologySpreadConstraint"
RemovePodsHavingTooManyRestarts
此策略确保重启次数过多的 pod 从节点上移除。例如,一个挂载了 EBS/PD 的 pod 如果无法将卷/磁盘附加到实例,则该 pod 应被重新调度到其他节点。其参数包括 podRestartThreshold,即 pod 应被驱逐时的重启次数(所有符合条件的容器之和),以及 includingInitContainers,用于确定是否将 init 容器的重启计入该计算。
您还可以指定 states 参数,以仅驱逐符合以下条件的 pod:
- Pod Phase 状态为:
Running - Container State Waiting 为:
CrashLoopBackOff
如果未指定 states 或 podStatusPhases 的值,
则任何状态(即使是 Running)的 Pod 都会被考虑进行驱逐。
Parameters:
| Name | Type |
|---|---|
podRestartThreshold | int |
includingInitContainers | bool |
namespaces | (see namespace filtering) |
labelSelector | (see label filtering) |
states | list(string) |
Example:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemovePodsHavingTooManyRestarts"
args:
podRestartThreshold: 100
includingInitContainers: true
plugins:
deschedule:
enabled:
- "RemovePodsHavingTooManyRestarts"
PodLifeTime
该策略根据 Pod 的年龄、状态转换、条件、状态、退出码和所有者类型来驱逐 Pod。它既支持基于简单年龄的驱逐,也支持针对符合特定转换条件的 Pod 进行细粒度清理。
所有非空的过滤器类别之间采用 AND 逻辑(Pod 必须满足所有指定的过滤器)。在每个类别内部,各项之间采用 OR 逻辑(匹配任意一项即满足该过滤器)。对于 conditions,如果任意一个列出的条件过滤器匹配,则该 Pod 符合驱逐条件——每个过滤器都会独立地与 Pod 的 status.conditions[] 条目进行比对。Pod 将根据其创建时间从最旧到最新进行处理。
有关详细文档和高级用例,请参阅 plugin README。
参数:
| 名称 | 类型 | 备注 |
|---|---|---|
conditions | list(object) | 每个对象包含可选的 type、status、reason、minTimeSinceLastTransitionSeconds 字段 |
exitCodes | list(int32) | 容器终止退出码 |
includingEphemeralContainers | bool | 将状态过滤扩展到临时容器 |
includingInitContainers | bool | 将状态/退出码过滤扩展到初始化容器 |
labelSelector | (参见 label filtering) | |
maxPodLifeTimeSeconds | uint | 驱逐年龄超过此秒数的 Pod |
namespaces | (参见 namespace filtering) | |
ownerKinds | object | include 或 exclude 所有者引用类型列表 |
states | list(string) | Pod 阶段、Pod 状态原因、容器等待/终止原因 |
示例(基于转换的驱逐):
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "PodLifeTime"
args:
states:
- "Succeeded"
conditions:
- reason: "PodCompleted"
status: "True"
minTimeSinceLastTransitionSeconds: 14400
ownerKinds:
exclude:
- "Job"
plugins:
deschedule:
enabled:
- "PodLifeTime"
示例(基于年龄的驱逐):
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "PodLifeTime"
args:
maxPodLifeTimeSeconds: 86400
states:
- "Pending"
- "PodInitializing"
plugins:
deschedule:
enabled:
- "PodLifeTime"
RemoveFailedPods
此策略会驱逐处于失败状态阶段的 Pod。
您可以提供可选参数,以根据失败 Pod 和容器的 reasons 以及 exitCodes 进行过滤。exitCodes 仅适用于处于 terminated 状态的失败 Pod 容器。通过将可选参数 includingInitContainers 设置为 true,reasons 和 exitCodes 可以扩展以包含 InitContainers 的相关项。
您可以指定可选参数 minPodLifetimeSeconds,以驱逐存在时间超过指定秒数的 Pod。
最后,您可以指定可选参数 excludeOwnerKinds,如果某个 Pod 将这些 Kind 中的任何一个列为 OwnerRef,则该 Pod 将不会被考虑进行驱逐。
Parameters:
| Name | Type |
|---|---|
minPodLifetimeSeconds | uint |
excludeOwnerKinds | list(string) |
reasons | list(string) |
exitCodes | list(int32) |
includingInitContainers | bool |
namespaces | (see namespace filtering) |
labelSelector | (see label filtering) |
Example:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "RemoveFailedPods"
args:
reasons:
- "NodeAffinity"
exitCodes:
- 1
includingInitContainers: true
excludeOwnerKinds:
- "Job"
minPodLifetimeSeconds: 3600
plugins:
deschedule:
enabled:
- "RemoveFailedPods"
过滤 Pod
命名空间过滤
以下策略接受一个 namespaces 参数,用于分别指定包含和排除的命名空间列表:
PodLifeTimeRemovePodsHavingTooManyRestartsRemovePodsViolatingNodeTaintsRemovePodsViolatingNodeAffinityRemovePodsViolatingInterPodAntiAffinityRemoveDuplicatesRemovePodsViolatingTopologySpreadConstraintRemoveFailedPods
以下策略接受一个 evictableNamespaces 参数,用于指定排除的命名空间列表:
LowNodeUtilization和HighNodeUtilization(仅在驱逐前进行过滤)
在以下使用 PodLifeTime 的示例中,PodLifeTime 仅在 namespace1 和 namespace2 上执行。
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "PodLifeTime"
args:
maxPodLifeTimeSeconds: 86400
namespaces:
include:
- "namespace1"
- "namespace2"
plugins:
deschedule:
enabled:
- "PodLifeTime"
类似的情况也适用于 exclude 字段。在以下示例中,该策略将在除 namespace1 和 namespace2 之外的所有命名空间上执行。
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "PodLifeTime"
args:
maxPodLifeTimeSeconds: 86400
namespaces:
exclude:
- "namespace1"
- "namespace2"
plugins:
deschedule:
enabled:
- "PodLifeTime"
不允许将 include 与 exclude 字段组合使用。
优先级过滤
优先级阈值可以通过 Default Evictor Filter 进行配置,并且只有低于该阈值的 pod 才能被驱逐。你可以通过设置 priorityThreshold.name(将阈值设置为给定
优先级类的值)或 priorityThreshold.value(直接设置阈值)参数来指定此阈值。默认情况下,此阈值
设置为 system-cluster-critical 优先级类的值。
注意:将 evictSystemCriticalPods 设置为 true 将完全禁用优先级过滤。
E.g.
设置 priorityThreshold value
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "DefaultEvictor"
args:
priorityThreshold:
value: 10000
- name: "PodLifeTime"
args:
maxPodLifeTimeSeconds: 86400
plugins:
deschedule:
enabled:
- "PodLifeTime"
设置 Priority Threshold Class Name (priorityThreshold.name)
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "DefaultEvictor"
args:
priorityThreshold:
name: "priorityClassName1"
- name: "PodLifeTime"
args:
maxPodLifeTimeSeconds: 86400
plugins:
deschedule:
enabled:
- "PodLifeTime"
请注意,您不能同时配置 priorityThreshold.name 和 priorityThreshold.value,如果给定的优先级类
不存在,descheduler 不会创建它,而是会抛出错误。
标签过滤
以下策略可以配置 标准 kubernetes labelSelector 以根据标签过滤 Pod:
PodLifeTimeRemovePodsHavingTooManyRestartsRemovePodsViolatingNodeTaintsRemovePodsViolatingNodeAffinityRemovePodsViolatingInterPodAntiAffinityRemovePodsViolatingTopologySpreadConstraintRemoveFailedPods
这允许在调度器感兴趣的 Pod 之间运行策略。
例如:
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "PodLifeTime"
args:
maxPodLifeTimeSeconds: 86400
labelSelector:
matchLabels:
component: redis
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}
plugins:
deschedule:
enabled:
- "PodLifeTime"
Node Fit 过滤
NodeFit 可通过 Default Evictor Filter 进行配置。如果设置为 true,调度器在驱逐 Pod 之前会考虑满足驱逐条件的 Pod 是否能适配到其他节点。如果 Pod 无法重新调度到其他节点,则不会被驱逐。当前,在将 nodeFit 设置为 true 时,会考虑以下标准:
- Pod 上的
nodeSelector - Pod 上的任何
tolerations以及其他节点上的任何taints - Pod 上的
nodeAffinity - Pod 产生的资源
requests以及其他节点上可用的资源 - 其他节点是否被标记为
unschedulable - Pod 与其他节点上的 Pod 之间的任何
podAntiAffinity
E.g.
apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
- name: ProfileName
pluginConfig:
- name: "DefaultEvictor"
args:
nodeFit: true
- name: "PodLifeTime"
args:
maxPodLifeTimeSeconds: 86400
plugins:
deschedule:
enabled:
- "PodLifeTime"
请注意,节点适配过滤引用的是当前 pod 的 spec,而不是其属主的 spec。 因此,如果该 pod 由 ReplicationController 拥有(且该 ReplicationController 最近被修改过), 该 pod 可能正在运行一个过时的 spec,而 descheduler 在确定节点适配时会引用该 spec。 这是预期行为,因为 descheduler 是一种“尽力而为”的机制。
使用 Deployments 代替 ReplicationControllers 可以提供 pod spec 变更的自动化滚动更新,从而确保 descheduler 拥有集群状态的最新视图。
Pod 驱逐
当 descheduler 决定从节点驱逐 pod 时,它采用以下通用机制:
- 关键 Pod(priorityClassName 设置为 system-cluster-critical 或 system-node-critical)永远不会被驱逐(除非设置了
evictSystemCriticalPods: true)。 - 不属于 ReplicationController、ReplicaSet(Deployment)、StatefulSet 或 Job 的 Pod(静态 Pod 或镜像 Pod 或独立 Pod)
永远不会被驱逐,因为这些 Pod 不会被重新创建。(通过设置
evictFailedBarePods: true可以驱逐处于失败状态阶段的独立 Pod) - 与 DaemonSet 关联的 Pod 永远不会被驱逐(除非设置了
evictDaemonSetPods: true)。 - 具有本地存储的 Pod 永远不会被驱逐(除非设置了
evictLocalStoragePods: true)。 - 具有 PVC 的 Pod 会被驱逐(除非设置了
ignorePvcPods: true)。 - 在
LowNodeUtilization和RemovePodsViolatingInterPodAntiAffinity中,Pod 会按照优先级从低到高进行驱逐,如果优先级相同, best effort Pod 会在 burstable 和 guaranteed Pod 之前被驱逐。 - 所有带有
descheduler.alpha.kubernetes.io/evict注解的 Pod 类型都有资格被驱逐。此 注解用于覆盖防止驱逐的检查,用户可以指定驱逐哪个 Pod。 用户应了解 Pod 是否以及如何被重新创建。 该注解仅影响内部 descheduler 检查。 /eviction 子资源提供的反干扰保护仍然会被遵守。 - 带有
descheduler.alpha.kubernetes.io/prefer-no-eviction注解的 Pod 表达了不被驱逐的偏好。 每个插件决定该注解是否被遵守。当DefaultEvictor插件将noEvictionPolicy设置为Mandatory时,所有此类 Pod 都将被排除在驱逐之外。需要谨慎使用,因为某些插件可能会强制执行 各种预期始终满足的策略。 - 具有非 nil DeletionTimestamp 的 Pod 默认不会被驱逐。
在 Descheduler 上设置 --v=4 或更高的值将记录任何 Pod 不可驱逐的所有原因。
Pod 中断预算 (PDB)
受 Pod 中断预算 (PDB) 约束的 Pod,如果调度器取消调度会违反其 PDB,则不会被驱逐。这些 Pod 通过使用驱逐子资源来处理 PDB 而被驱逐。
高可用性
在高可用性模式下,Descheduler 会在 Kubernetes 中启动 领导者选举 进程。如果你选择将应用程序部署为 Deployment,则可以启用 HA 模式。
Deployment 默认以 1 个副本启动。如果你想使用超过 1 个副本,你必须考虑启用高可用性模式,因为我们不希望同时运行多个 descheduler Pod。
配置 HA 模式
可以通过在 CLI 中设置 --leader-elect 来启用领导者选举进程。如果你使用 Helm,还可以设置
--set=leaderElection.enabled=true 标志。
要从 HA 模式中获得最佳效果,可能需要一些额外的配置:
- 如果你想仅在节点与至少一个正在运行的 descheduler 位于同一可用区时才将其调度到该节点,请配置 podAntiAffinity 规则
- 将副本数设置为大于 1
指标
| name | type | description |
|---|---|---|
| build_info | gauge | 常量 1 |
| pods_evicted | CounterVec | 被驱逐的 Pod 总数,在版本 v0.34.0 中已弃用 |
| pods_evicted_total | CounterVec | 被驱逐的 Pod 总数 |
| descheduler_loop_duration_seconds | HistogramVec | 完成整个调度周期所花费的时间(支持 _bucket、_sum、_count),在版本 v0.34.0 中已弃用 |
| loop_duration_seconds | HistogramVec | 完成整个调度周期所花费的时间(支持 _bucket、_sum、_count) |
| descheduler_strategy_duration_seconds | HistogramVec | 完成调度操作的每个策略所花费的时间(支持 _bucket、_sum、_count),在版本 v0.34.0 中已弃用 |
| strategy_duration_seconds | HistogramVec | 完成调度操作的每个策略所花费的时间(支持 _bucket、_sum、_count) |
指标默认通过 https://localhost:10258/metrics 提供服务。
可以通过设置 --binding-address 和 --secure-port 标志来更改地址和端口。
兼容性矩阵
以下兼容性矩阵显示了 descheduler 编译时使用的 k8s 客户端包(client-go、apimachinery 等)的版本。目前,descheduler 并不硬性依赖于特定的 k8s 版本。但是, 特定的 descheduler 版本仅针对最近三个 k8s 次要版本进行测试。例如,descheduler v0.18 应与 k8s v1.18、v1.17 和 v1.16 配合使用。
从 descheduler v0.18 版本开始,descheduler 的次要版本与其编译时使用的 k8s 客户端 包的次要版本相匹配。
| Descheduler | 支持的 Kubernetes 版本 |
|---|---|
| v0.36 | v1.36 |
| v0.35 | v1.35 |
| v0.34 | v1.34 |
| v0.33 | v1.33 |
| v0.32 | v1.32 |
| v0.31 | v1.31 |
| v0.30 | v1.30 |
| v0.29 | v1.29 |
| v0.28 | v1.28 |
| v0.27 | v1.27 |
| v0.26 | v1.26 |
| v0.25 | v1.25 |
| v0.24 | v1.24 |
| v0.23 | v1.23 |
| v0.22 | v1.22 |
| v0.21 | v1.21 |
| v0.20 | v1.20 |
| v0.19 | v1.19 |
| v0.18 | v1.18 |
| v0.10 | v1.17 |
| v0.4-v0.9 | v1.9+ |
| v0.1-v0.3 | v1.7-v1.8 |
参与和贡献
您对为 descheduler 做出贡献感兴趣吗?我们, 维护者和社区,非常欢迎您的建议、贡献和帮助! 此外,维护者随时可以联系,以了解如何参与。
要开始编写代码,请参阅 /docs 目录中的 贡献者指南。
为了让更多新人参与进来,我们会给 issue 打上
[good first issue][good_first_issue] 标签。
这些通常是范围较小但适合入门以熟悉代码库的 issue。
我们还鼓励所有活跃的社区参与者像维护者一样行事,即使你没有“官方”的写权限。这是一项 社区努力,我们在这里是为了服务 Kubernetes 社区。如果你有 活跃的兴趣并希望参与进来,你就拥有真正的力量!不要假设 这里唯一能成事的人是“维护者”。
我们也希望增加更多“官方”维护者,所以向我们展示你能 做什么!
此仓库使用 Kubernetes 机器人。完整的命令列表见 此处。
与贡献者沟通
你可以通过以下方式联系本项目的贡献者:
了解如何在 社区页面 上与 Kubernetes 社区互动。
路线图
此路线图没有特定的顺序。
- 考虑 pod 亲和性
- 考虑待处理 pod 数量的策略
- 与集群自动扩缩容器集成
- 与指标提供程序集成以获取真实负载指标
- 考虑 Kubernetes 调度器的谓词
行为准则
参与 Kubernetes 社区受 Kubernetes 行为准则 的约束。