ITADN
kubernetes-sigs/descheduler
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

Go Report Card Release Charts

↗️️ 点击 Readme 可视化右上角的 [bullet list icon],以查看由 github 生成的目录。

descheduler

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.xrelease-1.36
v0.35.xrelease-1.35
v0.34.xrelease-1.34
v0.33.xrelease-1.33
v0.32.xrelease-1.32
v0.31.xrelease-1.31
v0.30.xrelease-1.30

The master 分支被视为开发中,其中提供的信息可能不适用于之前的版本。

快速开始

Descheduler 可以作为 k8s 集群中的 JobCronJobDeployment 运行。它的优势在于可以多次运行而无需用户干预。 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 策略中的顶层键,可用于配置所有驱逐操作。

NametypeDefault ValueDescription
nodeSelectorstringnil限制被处理的节点。仅在 nodeFit=true 时由 PreEvictionFilter 扩展点使用。
maxNoOfPodsToEvictPerNodeintnil从每个节点驱逐的 Pod 最大数量(所有策略的总和)。
maxNoOfPodsToEvictPerNamespaceintnil从每个命名空间驱逐的 Pod 最大数量(所有策略的总和)。
maxNoOfPodsToEvictTotalintnil每个重新调度周期驱逐的 Pod 最大数量(所有策略的总和)。
metricsCollector (deprecated)objectnil配置实际资源利用率指标的收集。
metricsCollector.enabledboolfalse启用 Kubernetes Metrics Server 收集。
metricsProviders[]objectnil启用各种指标提供程序,例如 Kubernetes Metrics Server
evictionFailureEventNotificationboolfalse启用驱逐失败事件通知。
gracePeriodSecondsintnil对象应被删除前的持续时间(以秒为单位)。值零表示立即删除。如果此值为 nil,则将使用指定类型的默认宽限期。
prometheusobjectnil配置收集 Prometheus 指标以监控实际资源使用情况
prometheus.urlstringnil指向 Prometheus 服务器 URL
prometheus.authTokenobjectnil设置 Prometheus 服务器身份验证令牌。如果未指定,则从容器的文件系统读取集群身份验证令牌。
prometheus.authToken.secretReferenceobjectnil从 kubernetes secret 读取身份验证令牌(预期该 secret 在 prometheusAuthToken 数据键下包含令牌)
prometheus.authToken.secretReference.namespacestringnil身份验证令牌 kubernetes secret 命名空间(目前,RBAC 配置允许从 kube-system 命名空间检索 secret。如果 secret 需要从其他命名空间访问,必须显式扩展现有的 RBAC 规则。
prometheus.authToken.secretReference.namestringnil身份验证令牌 kubernetes secret 名称

Descheduler 目前允许通过 metricsProviders 字段配置 Kubernetes Metrics 的指标采集。 之前设置 metricsCollector 字段的方式已弃用。当前有两种配置来源:

  • KubernetesMetrics:启用从 Kubernetes Metrics 服务器采集指标
  • Prometheus:启用从 Prometheus 服务器采集指标

通常,每个插件可以从不同的提供者消费指标,因此可以并行配置多个不同的提供者。

Evictor 插件配置(默认 Evictor)

默认 Evictor 插件默认用于在策略插件处理 Pod 之前对其进行过滤,或在驱逐前应用 Pod 的 PreEvictionFilter。您也可以创建自己的 Evictor 插件,或使用 Descheduler 提供的默认插件。Evictor 插件的其他用途可以包括根据不同的标准对 Pod 进行排序、过滤、验证或分组,这就是为什么这由插件处理而不是在顶层配置中配置的原因。

名称类型默认值描述
nodeSelectorstringnil限制被处理的节点。
evictLocalStoragePodsboolfalse[已弃用:请改用 podProtections"PodsWithLocalStorage"]
允许驱逐使用本地存储的 Pod。
evictDaemonSetPodsboolfalse[已弃用:请改用 podProtections"DaemonSetPods"]
允许驱逐由 DaemonSet 管理的 Pod。
evictSystemCriticalPodsboolfalse[已弃用:请改用 podProtections 配合 "SystemCriticalPods"]
[警告:将驱逐 Kubernetes 系统 Pod] 允许驱逐具有任何优先级的 Pod,包括 kube-dns 等关键系统 Pod。
ignorePvcPodsboolfalse[已弃用:请改用 podProtections 配合 "PodsWithPVC"]
设置是否应驱逐或忽略 PVC Pod。
evictFailedBarePodsboolfalse[已弃用:请改用 podProtections 配合 "FailedBarePods"]
允许驱逐没有属主引用且处于失败阶段的 Pod。
ignorePodsWithoutPDBboolfalse[已弃用:请改用 podProtections 配合 "PodsWithoutPDB"]
设置是否应驱逐或忽略没有 PodDisruptionBudget 的 Pod。
namespaceLabelSelectormetav1.LabelSelector限制按命名空间处理的 Pod(参见 标签过滤)
labelSelectormetav1.LabelSelector(参见 标签过滤)
priorityThresholdpriorityThreshold(参见 优先级过滤)
nodeFitboolfalse(参见 节点适配过滤)
minReplicasuint0忽略驱逐其所有者(例如,ReplicaSet)副本数低于此阈值的 Pod。
minPodAgemetav1.Duration0忽略驱逐创建时间在此阈值内的 Pod。
noEvictionPolicyenum``sets whether a descheduler.alpha.kubernetes.io/prefer-no-eviction Pod 注解被视为首选或强制。接受的值:""、"Preferred"、"Mandatory"。默认为 "Preferred"。
podProtectionsPodProtections{}保存已启用和已禁用的保护 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-0storage-class-1 的 PVC 的 Pod,使其免于被驱逐。

策略示例

作为该策略的一部分,您将开始决定使用哪个顶层配置,然后决定使用哪个 Evictor 插件(如果您有自己的插件则使用自己的,否则使用 Default Evictor),接着决定传递给 Evictor 插件的配置。默认情况下,Default Evictor 在 filterpreEvictionFilter 扩展点处均已启用。之后,您将启用/禁用驱逐策略插件并对其进行正确配置。

有关可用参数的详细信息,请参阅各策略插件部分。

策略:

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:
          - ...
      [...]

下图提供了大多数策略的可视化,以帮助 对策略如何相互结合进行分类。

Strategies diagram

以下章节概述了可用的不同策略插件。这些插件根据其实现的扩展点进行分组:Deschedule 或 Balance。

Deschedule 插件:这些插件逐个处理 pod,并以顺序方式驱逐它们。

Balance 插件:这些插件处理所有 pod 或 pod 组,并根据组的预期分布情况确定要驱逐哪些 pod。

名称实现的扩展点描述
RemoveDuplicatesBalance分散副本
LowNodeUtilizationBalance根据 pod 的资源请求和节点可用资源分散 pod
HighNodeUtilizationBalance根据 pod 的资源请求和节点可用资源分散 pod
RemovePodsViolatingInterPodAntiAffinityDeschedule驱逐违反 pod 反亲和性的 pod
RemovePodsViolatingNodeAffinityDeschedule驱逐违反节点亲和性的 pod
RemovePodsViolatingNodeTaintsDeschedule驱逐违反节点污点的 pod
RemovePodsViolatingTopologySpreadConstraintBalance驱逐违反 TopologySpreadConstraints 的 pod
RemovePodsHavingTooManyRestartsDeschedule驱逐重启次数过多的 pod
PodLifeTimeDeschedule根据年龄、状态转换、条件、状态、退出代码和所有者类型驱逐 pod
RemoveFailedPodsDeschedule驱逐具有特定失败原因和退出代码的 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:

NameType
excludeOwnerKindslist(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, 则该节点被视为过度利用。位于阈值 thresholdstargetThresholds 之间的任何节点 都被视为适当利用,并且不会被考虑用于驱逐。阈值 targetThresholds 也可以针对 cpu、memory 和 pods 数量以百分比进行配置。

这些阈值 thresholdstargetThresholds 可以根据您的集群需求进行调整。请注意,此 策略会将 pods 从 overutilized nodes(使用率高于 targetThresholds 的节点)迁移到 underutilized nodes (使用率低于 thresholds 的节点),如果 underutilized nodesoverutilized 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 字段以了解可用选项。

参数:

名称类型
useDeviationThresholdsbool
thresholdsmap(string:int)
targetThresholdsmap(string:int)
numberOfNodesint
evictionLimitsobject
evictableNamespaces(参见 命名空间过滤)
metricsUtilizationobject
metricsUtilization.metricsServer (已弃用)bool
metricsUtilization.sourcestring
metricsUtilization.prometheus.querystring

示例:

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"

策略应通过以下验证检查:

  • 支持三种基本原生资源类型:cpumemorypods。 如果未指定其中任何一种资源类型,其所有阈值将默认为 100%,以避免节点从利用率不足变为利用率过高。
  • 支持扩展资源。例如,资源类型 nvidia.com/gpu 用于指定 GPU 节点利用率。扩展资源是可选的, 如果未在 thresholdstargetThresholds 中明确指定,则不会用于计算节点的使用情况。
  • thresholdstargetThresholds 不能为 nil,且它们必须配置完全相同类型的资源。
  • 资源百分比值的有效范围是 [0, 100]
  • 对于同一资源,thresholds 的百分比值不能大于 targetThresholds

LowNodeUtilization 策略相关的还有两个参数,称为 numberOfNodesevictionLimits。 第一个参数可以配置为仅在利用率不足的节点数量超过配置值时激活该策略。这在大型集群中可能很有帮助,因为少数节点可能会频繁或短时间内出现利用率不足的情况。默认情况下,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 nodesappropriately utilized nodes 中任何一个的数量为零,该策略将中止。

要控制从利用率不足的节点中驱逐 Pod,请使用 evictionModes 数组。默认策略是一种宽松策略,无论 Pod 的资源请求如何都会驱逐 Pod。要启用一种更严格的策略,仅驱逐为提供的阈值资源定义了资源请求的 Pod,请将 选项 OnlyThresholdingResources 添加到 evictionModes 配置中。

注意: 节点资源消耗由 Pod 的请求和限制决定,而非实际使用量。 选择这种方法是为了保持与 kube-scheduler 的一致性,kube-scheduler 在将 Pod 调度到节点时遵循相同的设计。这意味着 Kubelet(或 kubectl top 等命令)报告的资源使用量可能与计算出的消耗量不同,因为这些组件报告的是 实际使用指标。基于指标的重新调度目前是该项目的待办事项。

参数:

名称类型
thresholdsmap(string:int)
numberOfNodesint
evictionModeslist(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"

策略应通过以下验证检查:

  • 支持三种基本原生资源类型:cpumemorypods。如果未指定其中任何一种资源类型,其所有阈值默认为 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:

NameType
nodeAffinityTypelist(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:

NameType
excludedTaintslist(string)
includedTaintslist(string)
includePreferNoSchedulebool
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 是否可以被驱逐。

Supported Constraints 字段:

名称是否支持?
maxSkew
minDomains
topologyKey
whenUnsatisfiable
labelSelector
matchLabelKeys
nodeAffinityPolicy
nodeTaintsPolicy

参数:

名称类型
namespaces(参见 namespace filtering)
labelSelector(参见 label filtering)
constraints(参见 whenUnsatisfiable)
topologyBalanceNodeFitbool

示例:

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:

如果未指定 statespodStatusPhases 的值, 则任何状态(即使是 Running)的 Pod 都会被考虑进行驱逐。

Parameters:

NameType
podRestartThresholdint
includingInitContainersbool
namespaces(see namespace filtering)
labelSelector(see label filtering)
stateslist(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

参数:

名称类型备注
conditionslist(object)每个对象包含可选的 typestatusreasonminTimeSinceLastTransitionSeconds 字段
exitCodeslist(int32)容器终止退出码
includingEphemeralContainersbool将状态过滤扩展到临时容器
includingInitContainersbool将状态/退出码过滤扩展到初始化容器
labelSelector(参见 label filtering)
maxPodLifeTimeSecondsuint驱逐年龄超过此秒数的 Pod
namespaces(参见 namespace filtering)
ownerKindsobjectincludeexclude 所有者引用类型列表
stateslist(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 设置为 truereasonsexitCodes 可以扩展以包含 InitContainers 的相关项。 您可以指定可选参数 minPodLifetimeSeconds,以驱逐存在时间超过指定秒数的 Pod。 最后,您可以指定可选参数 excludeOwnerKinds,如果某个 Pod 将这些 Kind 中的任何一个列为 OwnerRef,则该 Pod 将不会被考虑进行驱逐。

Parameters:

NameType
minPodLifetimeSecondsuint
excludeOwnerKindslist(string)
reasonslist(string)
exitCodeslist(int32)
includingInitContainersbool
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 参数,用于分别指定包含和排除的命名空间列表:

  • PodLifeTime
  • RemovePodsHavingTooManyRestarts
  • RemovePodsViolatingNodeTaints
  • RemovePodsViolatingNodeAffinity
  • RemovePodsViolatingInterPodAntiAffinity
  • RemoveDuplicates
  • RemovePodsViolatingTopologySpreadConstraint
  • RemoveFailedPods

以下策略接受一个 evictableNamespaces 参数,用于指定排除的命名空间列表:

  • LowNodeUtilizationHighNodeUtilization(仅在驱逐前进行过滤)

在以下使用 PodLifeTime 的示例中,PodLifeTime 仅在 namespace1namespace2 上执行。

apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
  - name: ProfileName
    pluginConfig:
    - name: "PodLifeTime"
      args:
        maxPodLifeTimeSeconds: 86400
        namespaces:
          include:
          - "namespace1"
          - "namespace2"
    plugins:
      deschedule:
        enabled:
          - "PodLifeTime"

类似的情况也适用于 exclude 字段。在以下示例中,该策略将在除 namespace1namespace2 之外的所有命名空间上执行。

apiVersion: "descheduler/v1alpha2"
kind: "DeschedulerPolicy"
profiles:
  - name: ProfileName
    pluginConfig:
    - name: "PodLifeTime"
      args:
        maxPodLifeTimeSeconds: 86400
        namespaces:
          exclude:
          - "namespace1"
          - "namespace2"
    plugins:
      deschedule:
        enabled:
          - "PodLifeTime"

不允许将 includeexclude 字段组合使用。

优先级过滤

优先级阈值可以通过 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.namepriorityThreshold.value,如果给定的优先级类 不存在,descheduler 不会创建它,而是会抛出错误。

标签过滤

以下策略可以配置 标准 kubernetes labelSelector 以根据标签过滤 Pod:

  • PodLifeTime
  • RemovePodsHavingTooManyRestarts
  • RemovePodsViolatingNodeTaints
  • RemovePodsViolatingNodeAffinity
  • RemovePodsViolatingInterPodAntiAffinity
  • RemovePodsViolatingTopologySpreadConstraint
  • RemoveFailedPods

这允许在调度器感兴趣的 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)。
  • LowNodeUtilizationRemovePodsViolatingInterPodAntiAffinity 中,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

指标

nametypedescription
build_infogauge常量 1
pods_evictedCounterVec被驱逐的 Pod 总数,在版本 v0.34.0 中已弃用
pods_evicted_totalCounterVec被驱逐的 Pod 总数
descheduler_loop_duration_secondsHistogramVec完成整个调度周期所花费的时间(支持 _bucket、_sum、_count),在版本 v0.34.0 中已弃用
loop_duration_secondsHistogramVec完成整个调度周期所花费的时间(支持 _bucket、_sum、_count)
descheduler_strategy_duration_secondsHistogramVec完成调度操作的每个策略所花费的时间(支持 _bucket、_sum、_count),在版本 v0.34.0 中已弃用
strategy_duration_secondsHistogramVec完成调度操作的每个策略所花费的时间(支持 _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.36v1.36
v0.35v1.35
v0.34v1.34
v0.33v1.33
v0.32v1.32
v0.31v1.31
v0.30v1.30
v0.29v1.29
v0.28v1.28
v0.27v1.27
v0.26v1.26
v0.25v1.25
v0.24v1.24
v0.23v1.23
v0.22v1.22
v0.21v1.21
v0.20v1.20
v0.19v1.19
v0.18v1.18
v0.10v1.17
v0.4-v0.9v1.9+
v0.1-v0.3v1.7-v1.8

参与和贡献

您对为 descheduler 做出贡献感兴趣吗?我们, 维护者和社区,非常欢迎您的建议、贡献和帮助! 此外,维护者随时可以联系,以了解如何参与。

要开始编写代码,请参阅 /docs 目录中的 贡献者指南

为了让更多新人参与进来,我们会给 issue 打上 [good first issue][good_first_issue] 标签。 这些通常是范围较小但适合入门以熟悉代码库的 issue。

我们还鼓励所有活跃的社区参与者像维护者一样行事,即使你没有“官方”的写权限。这是一项 社区努力,我们在这里是为了服务 Kubernetes 社区。如果你有 活跃的兴趣并希望参与进来,你就拥有真正的力量!不要假设 这里唯一能成事的人是“维护者”。

我们也希望增加更多“官方”维护者,所以向我们展示你能 做什么!

此仓库使用 Kubernetes 机器人。完整的命令列表见 此处

与贡献者沟通

你可以通过以下方式联系本项目的贡献者:

了解如何在 社区页面 上与 Kubernetes 社区互动。

路线图

此路线图没有特定的顺序。

  • 考虑 pod 亲和性
  • 考虑待处理 pod 数量的策略
  • 与集群自动扩缩容器集成
  • 与指标提供程序集成以获取真实负载指标
  • 考虑 Kubernetes 调度器的谓词

行为准则

参与 Kubernetes 社区受 Kubernetes 行为准则 的约束。