Descheduler for Kubernetes(K8s 重调度器)
Descheduler for Kubernetes(K8s 重调度器)是一款官方维护的工具,核心作用是优化已运行 Pod 的调度位置——它会识别并迁移那些因集群状态变化(如节点资源不足、节点亲和性失效等)而“调度不合理”的 Pod,解决原生调度器(kube-scheduler)仅在 Pod 创建时调度、无法动态调整的问题。
一、核心定位与解决的问题
原生 kube-scheduler 仅在 Pod 首次创建时进行调度,当集群后续出现以下情况时,已运行的 Pod 会处于“不合理”状态,此时需要 Descheduler 介入:
- 节点资源失衡:部分节点 CPU/内存使用率过高(负载不均),部分节点资源闲置。
- 节点亲和性/反亲和性失效:例如 Pod 要求“运行在带
gpu=true
标签的节点”,但节点标签被删除后,Pod 仍留在原节点。 - 节点污点/容忍变化:节点新增污点(如
node-role.kubernetes.io/unschedulable=true
),而 Pod 无对应容忍,导致后续无法重启。 - 新节点加入集群:集群扩容后,原有 Pod 未迁移到新节点,新节点资源闲置。
- PVC 绑定优化:Pod 挂载的 PVC 对应的 PV 所在节点与 Pod 当前节点不同,导致跨节点存储访问,性能损耗。
二、工作原理:“识别不合理 Pod → 驱逐 → 原生调度器重新调度”
Descheduler 以 Deployment 形式运行在集群中(通常部署在 kube-system
命名空间),通过定时任务(默认 5 分钟一次,可配置)执行“重调度循环”,核心步骤分为 3 步:
1. 第一步:筛选“可重调度的 Pod”(排除不可迁移的 Pod)
Descheduler 首先会过滤掉无法迁移的 Pod,避免影响核心业务,主要排除规则包括:
- 标记了
descheduler.alpha.kubernetes.io/evict=false
注解的 Pod(明确禁止重调度)。 - 本地存储依赖的 Pod(如使用
emptyDir
、hostPath
且数据不可丢失的 Pod)。 - 未就绪(Not Ready)的 Pod(可能处于启动中,迁移风险高)。
- 静态 Pod(由
kubelet
直接管理,无法通过 API 驱逐)。 - 有本地亲和性的 Pod(如
nodeSelector
绑定特定节点,且无其他节点满足条件)。 - 核心组件 Pod(如
kube-apiserver
、etcd
等,通常配置了禁止驱逐注解)。
2. 第二步:通过“策略”识别“不合理 Pod”
Descheduler 内置多种“重调度策略”(可按需启用/禁用),通过策略筛选出需要驱逐的“不合理 Pod”,常用策略如下:
策略名称 | 作用(识别的不合理场景) |
---|---|
RemoveDuplicates | 同一 Deployment/DaemonSet 的多个 Pod 运行在同一节点,导致节点负载集中,需驱逐部分 Pod 到其他节点。 |
LowNodeUtilization | 节点资源利用率过低(如 CPU 使用率 < 20%),或过高(如 CPU 使用率 > 80%),通过驱逐平衡负载。 |
HighNodeUtilization | 针对节点资源使用率过高的场景(单独优化过载节点),驱逐部分 Pod 到低负载节点。 |
RemovePodsViolatingNodeAffinity | Pod 违反“节点亲和性规则”(如 requiredDuringSchedulingIgnoredDuringExecution ),需驱逐到符合条件的节点。 |
RemovePodsViolatingNodeTaints | Pod 无法容忍节点当前的污点(如节点新增 node-role.kubernetes.io/unschedulable ),需驱逐。 |
RemovePodsViolatingTopologySpreadConstraints | Pod 违反“拓扑分布约束”(如 topologySpreadConstraints 要求跨节点/跨可用区均匀分布)。 |
3. 第三步:驱逐 Pod 并由原生调度器重新调度
- 驱逐逻辑:Descheduler 对筛选出的“不合理 Pod”发送 Eviction API 请求(类似
kubectl drain
),触发 Pod 驱逐。 - 重新调度:Pod 被驱逐后,会进入“Pending”状态,此时原生 kube-scheduler 会按照正常调度流程,将 Pod 重新调度到“合理的节点”(满足资源、亲和性、污点容忍等条件)。
- 驱逐保护:为避免频繁驱逐,Descheduler 支持配置“驱逐阈值”(如单次最多驱逐节点上 10% 的 Pod)、“冷却时间”(同一 Pod 被驱逐后,多久内不再重新驱逐)。
三、核心配置:通过 ConfigMap 定义重调度策略
Descheduler 的行为由 ConfigMap
配置(默认名称 descheduler-config
,挂载到 Descheduler Deployment 中),核心配置包括“调度周期”“启用的策略”“策略参数”,示例如下:
# descheduler-config.yaml(ConfigMap 内容)
apiVersion: v1
kind: ConfigMap
metadata:name: descheduler-confignamespace: kube-system
data:policy.yaml: |apiVersion: "descheduler/v1alpha2"kind: "DeschedulerPolicy"schedule: "0 */5 * * *" # 重调度周期:每 5 分钟一次(Cron 表达式)strategies:LowNodeUtilization: # 启用“节点负载均衡”策略enabled: trueparams:nodeResourceUtilizationThresholds:thresholds: # 节点资源使用率阈值(超过/低于则触发重调度)cpu: 80memory: 80pods: 80targetThresholds: # 目标使用率(重调度后希望达到的水平)cpu: 50memory: 50pods: 50RemoveDuplicates: # 启用“移除重复 Pod”策略enabled: trueRemovePodsViolatingNodeAffinity: # 启用“移除违反节点亲和性的 Pod”策略enabled: true
四、部署与使用注意事项
- 部署方式:Descheduler 可通过 Helm Chart(官方维护的
descheduler
Chart)或 YAML 清单直接部署,需为其配置 ClusterRole 权限(需访问pods
、nodes
、evictions
等 API 资源)。 - 业务影响:驱逐 Pod 会导致业务短暂中断(除非 Pod 属于多副本 Deployment,且配置了
PodDisruptionBudget
控制中断数量),建议:- 对核心业务 Pod 配置
descheduler.alpha.kubernetes.io/evict=false
注解,禁止驱逐。 - 配置
PodDisruptionBudget
(PDB),限制同一时间被驱逐的 Pod 数量(如minAvailable: 1
)。
- 对核心业务 Pod 配置
- 性能开销:Descheduler 运行时会扫描集群所有 Pod 和节点,对超大规模集群(如 1000+ 节点),建议调大重调度周期(如 15 分钟一次),避免占用过多 API Server 资源。
总结
Descheduler 是原生调度器的“补充工具”——它不替代原生调度器,而是通过“事后优化”解决集群动态变化带来的调度不合理问题,核心价值是提升集群资源利用率、保证 Pod 运行合规性。在中大规模集群(尤其是节点动态变化、业务负载波动大的场景)中,Descheduler 是保障集群稳定性和资源效率的关键组件。