Kubernetes Descheduler:把 GPU Pod 从碎片化节点上挪走,比加卡更省钱

发布时间:2026/7/13 12:38:20

Kubernetes Descheduler:把 GPU Pod 从碎片化节点上挪走,比加卡更省钱 Kubernetes Descheduler把 GPU Pod 从碎片化节点上挪走比加卡更省钱一、GPU 资源的隐形空置集群利用率 60% 却无法调度新 Pod管理者查看 GPU 集群面板时总利用率显示 60%——看起来还有 40% 的空间。但新提交的 Pod申请 2 张 GPU却持续 Pending。打开节点详情8 个 GPU 节点中6 个各有 1 张空闲 GPU1 个有 2 张空闲1 个满载。Pod 申请 2 张没有单节点能满足——碎片化代价。GPU 推理任务的特性加剧了碎片化。推理 Pod 的生命周期不均匀短则 5 分钟弹性缩容、长则 48 小时长连接对话服务。扩缩容过程会在集群中留下大量单 GPU 洞。Kubernetes 默认调度器只做初始调度Scheduling不做二次重整Rescheduling——它把 Pod 放到当初最合适的节点上然后永远不动哪怕那个节点后来被碎片填满。某 200 张 A100 集群的周报数据实际 GPU 利用率 72%但可调度利用率仅 58%。差值 14% 约等于 28 张 A100——按云厂商按需价格计算每月浪费超过 6 万美元。基础设施不需要漂亮话——不能把 GPU 碎片归咎于正常损耗。二、Descheduler 的工作原理与 GPU 专用策略flowchart TD A[Descheduler 定时触发] -- B[遍历集群所有 GPU 节点] B -- C{检查节点碎片率} C --|碎片率 阈值| D[标记为碎片候选] C --|正常| E[跳过] D -- F[扫描候选节点上的 GPU Pod] F -- G{筛选可驱逐 Pod} G -- H[检查 PodDisruptionBudget] H --|允许| I[检查优先级/Annotation] H --|禁止| E I -- J[生成驱逐计划] J -- K[调用 Eviction API] K -- L[Pod 重新调度到紧凑节点] L -- M[释放碎片节点 GPU] M -- N{碎片节点 GPU 全释放?} N --|是| O[节点可回收/缩容] N --|否| DDescheduler 与 Scheduler 的本质区别Scheduler 负责把新 Pod 放到最合适的节点Descheduler 负责把已运行的 Pod 从不合适的节点挪走。对于 GPU 集群需要自定义策略判断不合适Node Utilization 策略标记低利用率的节点驱逐上面的 Pod 以合并到高利用率节点。GPU 版需要将阈值设为节点空闲 GPU 数量 ≤ 1 且 Pod 不能被其他 Pod 补齐场景。RemoveDuplicates 策略同一 ReplicaSet 的 Pod 分散在不同节点时优先驱逐零散 Pod 重新调度。但 GPU 推理 Pod 通常不需要此策略——推理 Pod 之间不需要反亲和性。TopologySpreadConstraint配合 Topology Manager将分散在不同 NUMA node 的 GPU Pod 重整到同一 NUMA node。仅在启用 NUMA 感知调度的集群有效。三、GPU 专用 Descheduler 配置与驱逐保护步骤 1安装 DeschedulerHelmhelm repo add descheduler https://kubernetes-sigs.github.io/descheduler/ helm install descheduler descheduler/descheduler \ --namespace kube-system \ --set schedule*/5 * * * * \ --set cmdOptions.v4步骤 2GPU 碎片整理策略配置apiVersion: v1 kind: ConfigMap metadata: name: descheduler-policy-configmap namespace: kube-system data: policy.yaml: | apiVersion: descheduler/v1alpha2 kind: DeschedulerPolicy strategies: # 策略一低利用率节点驱逐 LowNodeUtilization: enabled: true params: nodeResourceUtilizationThresholds: # 按 GPU 数量判断非百分比 thresholds: nvidia.com/gpu: 1 # 节点 ≤ 1 张空闲 GPU 时触发检查 targetThresholds: nvidia.com/gpu: 3 # 目标释放到 ≥ 3 张空闲 # 策略二移除违反 Pod 反亲和性的 PodGPU 专用 RemovePodsViolatingInterPodAntiAffinity: enabled: true # 策略三拓扑分布约束 RemovePodsViolatingTopologySpreadConstraint: enabled: true params: includeSoftConstraints: false topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: DoNotSchedule # 全局驱逐限制 maxNoOfPodsToEvictPerNode: 1 # 单次驱逐每节点最多 1 个 Pod避免雪崩 maxNoOfPodsToEvictPerNamespace: 5 # 单次每命名空间最多 5 个步骤 3GPU Pod 的反驱逐保护apiVersion: v1 kind: Pod metadata: name: llm-inference-critical labels: app: vllm-server annotations: # 标记不可驱逐生产主力服务 descheduler.alpha.kubernetes.io/evict: false spec: containers: - name: vllm image: vllm/vllm-openai:latest resources: requests: nvidia.com/gpu: 2 --- # PodDisruptionBudget限制并发驱逐数量 apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: vllm-server-pdb spec: minAvailable: 2 # 至少保持 2 个 Pod 在线 selector: matchLabels: app: vllm-server步骤 4Prometheus 监控碎片率# 各 GPU 节点的空闲 GPU 数量 sum(kube_node_status_allocatable{resourcenvidia_com_gpu}) by (node) - sum(kube_pod_container_resource_requests{resourcenvidia_com_gpu}) by (node) # 碎片率 有碎片节点数 / 总 GPU 节点数 count( sum(kube_node_status_allocatable{resourcenvidia_com_gpu}) by (node) - sum(kube_pod_container_resource_requests{resourcenvidia_com_gpu}) by (node) 0 and 2 ) / count(kube_node_status_allocatable{resourcenvidia_com_gpu})四、驱逐风暴、服务中断与保守策略的代价驱逐风暴Eviction Storm。Descheduler 按 CronJob 定时运行每次可能驱逐多个 Pod。如果配置不当——比如同时驱逐了服务 A 的 5 个 Pod——会导致服务 A 瞬间中断。必须配置 PDBPodDisruptionBudget和maxNoOfPodsToEvictPerNamespace限制。冷启动惩罚。被驱逐的 GPU Pod 需要重新调度、重新加载模型权重、重新 JIT 预热。一个 70B 模型的完整启动周期可能超过 3 分钟模型加载 2 分钟 预热 1 分钟。在此期间该 Pod 的服务容量为零。频繁驱逐会降低整体服务可用性。调度器博弈。驱逐后的 Pod 由默认 Scheduler 重新调度。但如果碎片问题没有根本解决Scheduler 可能将 Pod 再次调度到碎片化节点。这形成了驱逐 → 重调度到碎片节点 → 再驱逐的死循环。需要确保驱逐计划中的紧凑节点确实有足够资源。保守策略可能无效。maxNoOfPodsToEvictPerNode1的保守设置下每个 5 分钟周期最多移动 1 个 Pod/节点。对于 200 卡的集群彻底整理一轮需要数小时。需要根据集群碎片严重度动态调整驱逐速率。不适用场景推理 Pod 均为单 GPU 请求无碎片化问题——单卡总有地方放集群规模极小 10 节点手动整理更简单Pod 生命周期极短 5 分钟碎片自然消亡速度 Descheduler 整理速度。五、总结GPU 碎片化是资源浪费的隐形杀手——利用率数字好看实际可调度容量却大打折扣。Descheduler 通过定期驱逐零散 GPU Pod 并重调度将碎片整理到紧凑节点释放整块 GPU 资源。落地建议先用 Prometheus 监控空闲 GPU 的节点分布量化碎片率再以LowNodeUtilization策略部署 Descheduler初始设为保守档每节点 1 个/5 分钟最后为主力推理服务配置 PDB 和descheduler.alpha.kubernetes.io/evict: falseannotation确保碎片整理不伤核心业务。

相关新闻