Kubernetes GPU 调度:一个 2x2 的实践模型 (节点 × GPU 的紧凑与分散策略)
Kubernetes GPU 调度:一个 2x2 的实践模型 (节点 × GPU 的紧凑与分散策略)
Pod 不仅仅是落在节点 (Node) 上——对于 GPU 类型的 Pod 来说,它们还落在具体的 GPU 上。如今的 Kubernetes 提供了可靠的节点层面 (node-level) 的调度策略(比如 MostAllocated 或拓扑分布),但设备层面 (GPU-level) 的调度策略仍需要一个设备感知 (device-aware) 的实现。Kubernetes 1.34 版本中的 DRA (动态资源分配) 让设备的描述和分配成为了一等公民,甚至通过扩展资源 (extended resources) 的方式为平滑迁移搭建了桥梁——但通用的设备评分机制(即实现内置 GPU 紧凑/分散策略的关键部分)仍在开发中。
为什么是“两个维度”?
-
节点维度 (Node axis):
- 紧凑打包 (Binpack) (例如
MostAllocated,RequestedToCapacityRatio策略):有助于资源整合,让集群自动伸缩器 (Cluster Autoscaler) 更容易缩容,从而控制成本。 - 分散部署 (Spread) (Pod 拓扑分布):通过避免单点故障域,提高可用性并稳定尾部延迟。
- 紧凑打包 (Binpack) (例如
-
GPU 维度 (GPU axis):
- 紧凑打包 (Binpack):将小型任务打包到更少的物理 GPU 上,从而释放出完整的 GPU 用于模型训练或未来的突发流量。
- 分散部署 (Spread):减少 GPU 内部的资源竞争 (如 HBM/SM/PCIe/NVLink),为在线推理服务平滑 P99 延迟。
目前,Kubernetes 在第二个维度(GPU)上的原生调度能力有限。默认的节点评分器无法“看到”一个 Pod 将会使用哪一个具体的 GPU。DRA 为设备分配添加了必要的结构,但针对 DRA 的设备/节点评分机制仍在进行中。并且,NodeResourcesFit 评分策略不适用于由 DRA 在背后支持的扩展资源(这是 1.34 版本中新增的迁移桥梁)。
DRA 解决了什么(以及尚未解决什么)
- 解决了什么: 提供了一个标准化的模型来描述设备 (
ResourceSlice)、声明请求 (ResourceClaim) 和对设备分类 (DeviceClass)。Kubernetes 可以据此分配匹配的设备,并将 Pod 调度到能够访问这些设备的节点上。在 1.34 版本中,KEP-5004 允许DeviceClass将 DRA 管理的设备映射回一个扩展资源名称,这样现有的应用清单 (manifests) 可以在迁移期间继续使用经典的vendor.com/gpu: N语法。 - 尚未解决什么: 一个通用的调度器评分器,它能为设备/节点打分,从而实现“内置的 GPU 紧凑/分散策略”。社区已经创建了 issue 来添加一个
dynamicresources评分器以实现正确的紧凑打包;在此功能落地之前,设备层面的调度策略仍需依赖驱动程序或外部的、具备设备感知能力的调度器。此外,NodeResourcesFit评分机制对于由 DRA 代理的扩展资源无效。
可实际感知的 2×2 模型:节点 × GPU = 四种调度模式
下面我将使用一个最小化的、可复现的环境来展示这四种模式。重点不是推销任何特定的技术栈,而是为了观察你在生产环境中可能遇到的不同权衡。
一键部署环境
所有的 YAML 文件和 Terraform 配置都在这里:
- 仓库:
https://github.com/dynamia-ai/hami-ecosystem-demo - Demos:
demo/binpack-spread(四个 YAML 文件对应四种模式)。每个 YAML 都是一个最小化的Deployment,只调整了两个参数:
通过 annotations 设置策略(两个维度):
template:
metadata:
annotations:
hami.io/node-scheduler-policy: "binpack" # 或 "spread"
hami.io/gpu-scheduler-policy: "binpack" # 或 "spread"
通过 HAMi 强制执行 GPU 配额:
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem: "7500" # 约 7.5GB 显存,这样两个 Pod 就可以共享一张 GPU
除以上配置外,四个文件中的其他部分(如镜像、启动参数)完全相同。
启动 EKS 环境:
git clone https://github.com/dynamia-ai/hami-ecosystem-demo
cd hami-ecosystem-demo/infra/aws
terraform init
terraform apply -auto-approve
这会创建两个 GPU 节点(一个配备 4×T4,另一个配备 4×A10G)。
A) 节点紧凑打包 × GPU 紧凑打包 — “成本优先,并保留完整的 GPU”
- 适用场景: 大量小型的推理或批处理任务;希望为自动缩容留出空间,并保留完整的 GPU 用于后续的训练任务。
- 优势: 活跃节点数更少;获得完整 GPU 的可能性更高。
- 代价: GPU 内部资源竞争加剧,对延迟敏感的服务存在 P99 延迟风险。

Run:
运行:
kubectl apply -f demo/binpack-spread/a-node-binpack-gpu-binpack.yaml
# 使用以下脚本查看 Pod 分布
{
printf "POD\tNODE\tUUIDS\n";
kubectl get po -l app=demo-a -o json \
| jq -r '.items[] | select(.status.phase=="Running") | [.metadata.name,.spec.nodeName] | @tsv' \
| while IFS=$'\t' read -r pod node; do
uuids=$(kubectl exec "$pod" -c vllm -- nvidia-smi --query-gpu=uuid --format=csv,noheader | paste -sd, -);
printf "%s\t%s\t%s\n" "$pod" "$node" "$uuids";
done;
} | column -t -s $'\t'
观察结果 (示例):
POD NODE UUIDS
demo-a-node-binpack-gpu-binpack-6899f6dfdd-8z8rx ip-10-0-52-161.us-west-2.compute.internal GPU-b0e94721-ad7c-6034-4fc8-9f0d1ac7d60d
demo-a-node-binpack-gpu-binpack-6899f6dfdd-nfbz4 ip-10-0-52-161.us-west-2.compute.internal GPU-b0e94721-ad7c-6034-4fc8-9f0d1ac7d60d
demo-a-node-binpack-gpu-binpack-6899f6dfdd-dtx7b ip-10-0-52-161.us-west-2.compute.internal GPU-85caf98e-de2d-1350-ed83-807af940c199
demo-a-node-binpack-gpu-binpack-6899f6dfdd-wtd47 ip-10-0-52-161.us-west-2.compute.internal GPU-85caf98e-de2d-1350-ed83-807af940c199
分析: 所有 Pod 都被调度到了单个节点上,并且它们被紧凑地打包到了满足其资源限制的最少数 GPU 上(这里是 2 个 GPU)。
B) 节点分散部署 × GPU 紧凑打包 — “跨节点高可用,同时保留完整的 GPU”
- 适用场景: 需要跨区/跨节点部署以实现高可用的多副本服务,但同时希望将节点内的小任务打包到少数 GPU 上。
- 优势: 实现了高可用性,同时也能保留完整的 GPU。
- 代价: 集群缩容变得更加困难。

运行:
kubectl delete -f demo/binpack-spread/a-node-binpack-gpu-binpack.yaml
kubectl apply -f demo/binpack-spread/b-node-spread-gpu-binpack.yaml
# ... 使用相同的脚本查看,只需将 app label 改为 app=demo-b
观察结果 (示例):
POD NODE UUIDS
demo-b-node-spread-gpu-binpack-548cb55c7d-8tg22 ip-10-0-52-161.us-west-2.compute.internal GPU-dedbdfb2-408f-9ded-402f-e3dc22c08f66
demo-b-node-spread-gpu-binpack-548cb55c7d-h9ds6 ip-10-0-61-248.us-west-2.compute.internal GPU-5f432a79-775e-db04-1e15-82307fdb5a1b
demo-b-node-spread-gpu-binpack-548cb55c7d-ncwdl ip-10-0-61-248.us-west-2.compute.internal GPU-5f432a79-775e-db04-1e15-82307fdb5a1b
demo-b-node-spread-gpu-binpack-548cb55c7d-stx67 ip-10-0-52-161.us-west-2.compute.internal GPU-dedbdfb2-408f-9ded-402f-e3dc22c08f66
分析: Pod 被分散到了不同的节点上,但在每个节点内部,它们仍然被打包到了同一张 GPU 上。
C) 节点紧凑打包 × GPU 分散部署 — “节约部分成本,同时保护尾部延迟”
- 适用场景: 在线推理服务;希望在合理整合资源的同时,避免将所有负载都堆积到同一张 GPU 上。
- 优势: 仍在节点级别进行了资源整合;GPU 间的竞争更低。
- 代价: 不如模式 A 成本效益高。

运行:
kubectl delete -f demo/binpack-spread/b-node-spread-gpu-binpack.yaml
kubectl apply -f demo/binpack-spread/c-node-binpack-gpu-spread.yaml
# ... 使用相同的脚本查看,只需将 app label 改为 app=demo-c
观察结果 (示例):
POD NODE UUIDS
demo-c-node-binpack-gpu-spread-d5f686b67-8zbz9 ip-10-0-61-248.us-west-2.compute.internal GPU-041286d5-ed3d-4823-096e-a4c80fe17fb9
demo-c-node-binpack-gpu-spread-d5f686b67-hn2md ip-10-0-61-248.us-west-2.compute.internal GPU-b639414c-f867-90c3-dd3b-a2bd094a703e
demo-c-node-binpack-gpu-spread-d5f686b67-rrpzb ip-10-0-61-248.us-west-2.compute.internal GPU-4bfe5899-5368-2e73-de03-d34894b6d75c
demo-c-node-binpack-gpu-spread-d5f686b67-sv8fg ip-10-0-61-248.us-west-2.compute.internal GPU-5f432a79-775e-db04-1e15-82307fdb5a1b
分析: 所有 Pod 都位于同一个节点上,但被分散到了该节点上的多张不同 GPU 上。
D) 节点分散部署 × GPU 分散部署 — “尾部延迟优先”
- 适用场景: 对服务等级协议 (SLA) 有严格要求的场景(如搜索、广告、聊天),其中 P99 延迟是关键指标。
- 优势: 在节点和 GPU 两个维度上的干扰都最低。
- 代价: 成本最高;资源碎片化最严重。

运行:
kubectl delete -f demo/binpack-spread/c-node-binpack-gpu-spread.yaml
kubectl apply -f demo/binpack-spread/d-node-spread-gpu-spread.yaml
# ... 使用相同的脚本查看,只需将 app label 改为 app=demo-d
观察结果 (示例):
POD NODE UUIDS
demo-d-node-spread-gpu-spread-c4555d97c-5gqkf ip-10-0-52-161.us-west-2.compute.internal GPU-b0e94721-ad7c-6034-4fc8-9f0d1ac7d60d
demo-d-node-spread-gpu-spread-c4555d97c-666dc ip-10-0-61-248.us-west-2.compute.internal GPU-5f432a79-775e-db04-1e15-82307fdb5a1b
demo-d-node-spread-gpu-spread-c4555d97c-8xjbh ip-10-0-61-248.us-west-2.compute.internal GPU-4bfe5899-5368-2e73-de03-d34894b6d75c
demo-d-node-spread-gpu-spread-c4555d97c-k727x ip-10-0-52-161.us-west-2.compute.internal GPU-dedbdfb2-408f-9ded-402f-e3dc22c08f66
分析: Pod 被同时分散到了不同的 GPU 和不同的节点上。
DRA 的现状与未来
- 现状: DRA 标准化了分配什么以及可以在哪里运行。如果你同时启用了 KEP-5004,应用程序可以继续请求扩展资源,而底层的驱动和
ResourceSlice会完成实际的分配工作——这对于从 DevicePlugin 迁移非常有用。但是:原生的NodeResourcesFit评分机制不适用于由 DRA 支持的扩展资源,而用于为动态资源提供正确紧凑打包的dynamicresources评分器仍在开发中。 - 未来: 一旦 DRA 的设备/节点评分机制落地,更多这类调度逻辑就可以在 Kubernetes“核心”中实现(至少对于通用场景)。但对于显卡内部拓扑(如 NUMA/NVLink)和更细致的策略,具备设备感知能力的实现方案仍然至关重要。
代码复现与参考资料
- 环境与四种 Demo
https://github.com/dynamia-ai/hami-ecosystem-demohttps://github.com/dynamia-ai/hami-ecosystem-demo/tree/main/demo/binpack-spread
- 背景资料
- Virtualizing Any GPU on AWS with HAMi: Free Memory Isolation (《使用 HAMi 在 AWS 上虚拟化任意 GPU:实现免费的显存隔离》,详见其中的“一键部署”部分)
- A Quick Take on K8s 1.34 GA DRA: 7 Questions You Probably Have (《速览 K8s 1.34 GA 版本的 DRA:你可能关心的 7 个问题》)
- DRA 相关背景 (v1.34)
- Kubernetes PR #130653 (kubelet/scheduler 支持由 DRA 代理的扩展资源;注意:
NodeResourcesFit评分机制不适用于这类资源) - KEP #5004 (DRA: 通过 DRA 驱动处理扩展资源请求)
- Issue #133669 (添加
dynamicresources评分器;作为 Beta 阶段的要求,需要实现正确的紧凑打包)
- Kubernetes PR #130653 (kubelet/scheduler 支持由 DRA 代理的扩展资源;注意:

Dynamia 密瓜智能, 专注以 CNCF HAMi 项目为核心底座,提供 灵活、可靠、按需、弹性的 GPU 虚拟化 与异构算力调度、统一管理的全球化解决方案。可以插拔式、轻量化、无侵入地部署在任意公有云、私有云、混合云环境中,可支持 NVIDIA、昇腾、沐曦、寒武纪、海光、摩尔线程,天数智芯等异构芯片。