DRA:K8s 高效管理和分配专用硬件资源
ref: K8s官网定义;
Allocate Devices to Workloads with DRA;
Set Up DRA in a Cluster;
Dynamic Resource Allocation with Structured Parameters
想象一下,你正在管理一个拥有数百个 GPU 和其他专用硬件设备的 Kubernetes 集群。如何确保这些昂贵的资源被高效利用?如何让多个 pod 共享同一个设备?当设备出现故障时,如何自动迁移工作负载?
过去的 Kubernetes 调度更多聚焦 CPU/内存等“静态资源”的放置和分配,设备资源通常靠设备插件(Device Plugin)按容器级的请求进行绑定,缺乏跨 Pod 的共享、表达式筛选、统一的设备分类以及对设备状态的可观测性。DRA 提供了系统层面的统一方法来解决这些问题
Kubernetes 的(DRA,dynamic resource allocation)提供了这些问题的答案。DRA引入了设备级的“资源切片”(ResourceSlice)、“设备类别”(DeviceClass)、“资源声明/资源声明模板”(ResourceClaim/ResourceClaimTemplate)等对象,调度决策要基于这些设备级的声明和切片信息,而不仅仅是节点的 CPU/内存容量。
也就是说,DRA(动态资源分配)把设备资源(如 GPU、NIC、加速器等)从传统调度的“固定容量”里提出来,引入了全新的资源模型和调度流程,使调度器能够基于对设备的声明、分配和驱动的信息来确定 Pod 的放置,从而实现设备的灵活分类、共享和动态管理。
DRA 是对设备资源(如 GPU、NIC 等)的独立治理框架,与原有的 kube-scheduler 协同工作。CPU/内存调度仍然存在,DRA 在此基础上增加对设备资源的声明、切片、分配、绑定与生命周期管理。
With DRA, device drivers and cluster admins define device classes that are available to claim in workloads. Kubernetes allocates matching devices to specific claims and places the corresponding pods on nodes that can access the allocated devices.
Allocating resources with DRA is a similar experience to dynamic volume provisioning, in which you use PersistentVolumeClaims to claim storage capacity from storage classes and request the claimed capacity in your pods.
DRA 与原有 Kubernetes 调度的对照
| 维度 | 传统 Kubernetes 调度 | DRA(动态资源分配) | 备注/要点 |
|---|---|---|---|
| 关注的资源粒度 | 主要对 CPU、内存、存储等静态资源进行放置;设备资源通常通过设备插件在容器级进行绑定,跨 Pod 共享能力不足 | 以设备级资源切片、设备类别、资源声明/模板等对象为核心,基于设备级信息进行调度与绑定,支持跨 Pod 共享 | 引入统一的设备治理单元,超越单容器级绑定的局限 |
| API 与治理对象 | 节点资源和设备插件状态为主要信息,缺乏统一的设备治理模型 | 新增治理对象:DeviceClass、ResourceSlice、ResourceClaim、ResourceClaimTemplate 等,提供统一的设备治理入口 | 将设备资源从“插件绑定”提升为可声明、可切片、可观测的资源单元 |
| 调度与绑定分工 | 调度阶段尽量确定放置,设备绑定通常在后续阶段完成,设备不可用时容易重调度 | 多阶段工作流:驱动/控制平面创建资源切片、管理员配置设备类别、工作负载创建 ResourceClaim/Template,调度器据切片与声明进行放置并绑定 | 释放放置与绑定的耦合,提升鲁棒性与可观测性 |
| 设备共享与筛选 | 设备通常是单 Pod 的专有资源,跨 Pod 共享困难;筛选能力有限 | 支持跨 Pod 共享、基于 CEL 表达式的属性筛选、候选设备优先级、对不同设备类别的灵活匹配 | 提升资源利用率与调度灵活性 |
| 设备状态与观测 | 设备状态观测有限,治理能力薄弱 | 引入设备健康监控、绑定条件、访问权限控制、观测状态报告等,调度对设备状态有更强的感知与治理能力 | 提高运维可观测性和诊断能力 |
| 多租户治理 | 多租户隔离和统一治理较困难 | 提升了设备治理的清晰度与多租户友好性,职责分离更明确(设备管理员、Driver、调度/运营人员分工清晰) | 更适合复杂租户场景 |
| 与设备插件的关系 | 设备插件驱动设备并与 Pod 绑定,角色较单一 | 设备插件仍存在,但提供一个统一治理框架,声明、切片、分配、绑定在框架内协同完成 | 插件仍然重要,但职责分离、协同治理增强 |
| 对现有调度器的影响 | 仍以传统调度为主,设备资源需额外处理或插件侧绑定 | 与调度器协同工作,形成多阶段、对设备切片和资源声明的依赖,调度器在匹配时考虑设备切片和声明 | 不是替代,而是扩展与协同 |
| 场景适用性 | 适合在不强依赖设备级细粒度治理的环境中使用 | 适用于含 GPU/NIC 等异构设备的集群,强调跨 Pod 共享、精细筛选和多租户治理 | 针对设备资源密集场景提供更高的治理粒度 |
动机和目标
动机
Kubernetes 最初只把 CPU/内存等资源视为容器的核心资源,后续才扩展到存储和可逐节点计数的扩展资源;设备本地资源通过设备插件暴露给容器使用。但对新型设备(GPU, NIC, SmartNIC, FPGA),现有方式和请求自定义资源的 Kubernetes API 显得受限。因此提出 DRA 的 KEP,旨在解决以下用例中的局限性:
- 设备初始化:如 FPGA 等加速设备在 workload 启动时需要重新配置,而不必让应用获得完整的硬件访问或提升至 root 权限,从而提升集群安全性。
- 设备清理:工作负载结束后,需有清理机制,确保设备不保留前一个作业的配置、参数或数据,并正确进入休眠/关机等状态。
- 部分分配:设备能力的部分分区(如 Nvidia MIG、SR-IOV)以更好地匹配工作负载需求,提升资源利用率。当前 API 不支持按需动态部分分配,需预分区设备并逐一选取,带来灵活性与利用率的折中。
- 可选分配:在部署时希望支持软性设备需求。若设备可分配则分配,若不可用则让工作负载仍可在无设备情况下运行(如使用 GPU 的任务回退到 CPU)。当前设备插件和 Pod 资源声明都不支持这种可选分配。
- Fabric 设备支持:希望在容器部署时利用通过 Fabric(网络、专用链路等)可用的设备资源。
- 现有设备插件 API 面临的挑战包括:节点本地资源的发现局限、难以实现跨 Pod 的共用、缺乏统一的设备分类与治理、对健康状态和绑定条件的观测不足等。
- CDI(Containerized Data Interface)等现有扩展已被用于在容器内部暴露资源,但仍需要一个更统一、可观测的治理框架来覆盖设备资源的声明、切片、分配、绑定与生命周期管理。
目标
- 实现集群在使用资源声明(ResourceClaim、ResourceClaimTemplate)时的自动扩缩容能力,确保在资源声明变动导致需要扩容时,集群规模可在一个时间内超出单节点的范围进行调整。
- 同时支持节点本地资源和网络附着资源,覆盖更加多样化的设备场景。
- 支持供应商定义的配置参数格式,使设备资源的性质和属性可由厂商自定义且可被集群理解和治理。
- 允许与现有设备插件并存:不是要替换设备插件 API,而是通过一个独立的治理框架来扩展对设备资源的声明、切片、分配、绑定与生命周期管理,与插件能力协同工作。
- 提供设备资源抽象层的进阶能力,允许不同厂商在不同实现之间灵活选择 API 模型(如保留设备插件的场景,同时引入动态资源分配的能力)。
非目标(Non-Goals)
- 不打算替换设备插件 API。对于符合单线性容量模型的设备,设备插件仍然是可行且有效的解决方案;动态资源分配(DRA)与设备插件 API 将并存,厂商可按场景选择最合适的 API。
- 不提供一个简单的“我想要某种 GPU”这样的通用抽象。要力求让厂商通过 DeviceClass、ResourceSlice 等对象暴露具体的配置参数和属性,减少用户对具体实现的依赖。
- 通过对属性的标准化来实现工作负载的可移植性是一项未来工作,当前重点在于明确设备资源的声明、切片、分配、绑定及治理框架,而不是直接强制统一跨厂商的属性定义。
核心概念

- DeviceClass(设备类)
对一类可用设备的抽象和分类,例如 GPU、网卡等。它定义了设备的属性、能力以及如何筛选匹配资源的规则。DeviceClass 参数可以匹配 ResourceSlices 中的零个或多个设备。 - ResourceClaim(资源声明)
对某个 DeviceClass 的设备的具体请求,来自 pod 或工作负载,即描述对集群中附加资源(如设备)的访问请求。Claim 与具体的 ResourceSlice 绑定,确保 pod 获得所需的设备资源的访问。 - ResourceClaimTemplate(资源声明模板)
为同一工作负载中的多个 pod 生成独立的设备 Claim 的模板,避免不同 pod 之间争抢同一组设备,确保每个 pod 拥有独立的设备访问权。 - ResourceSlice(资源切片)
在某个节点上由设备驱动创建的、可被分配的设备子集/“切片”,表示具体可用的设备池及其元数据(like 设备标识、属性等)。驱动程序在集群中创建和管理 ResourceSlices。每个资源切片必须包含以下信息:- Resource pool: 驱动程序管理的一组一个或多个资源。该池可以跨越多个资源切片。对池中资源的更改必须在该池中的所有资源切片中传播。管理该池的设备驱动程序负责确保这种传播发生。
- Devices: 管理池中的设备。ResourceSlice 可以列出池中的每个设备或池中设备的子集。ResourceSlice 定义了设备信息,如属性、版本和容量。设备用户可以通过在 ResourceClaims 或 DeviceClasses 中筛选设备信息来选择设备进行分配。
- Nodes: 可以访问资源的节点。驱动程序可以选择哪些节点可以访问资源,无论是集群中的所有节点、单个命名节点,还是具有特定节点标签的节点。
- e.g. 该资源切片由
resource-driver.example.com驱动程序管理,位于black-cat-pool池中。allNodes: true字段表示集群中的任何节点都可以访问设备。该资源切片中有一个设备,名为large-black-cat,具有以下属性:color: black,size: large,cat: true。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
name: cat-slice
spec:
driver: "resource-driver.example.com"
pool:
generation: 1
name: "black-cat-pool"
resourceSliceCount: 1
# The allNodes field defines whether any node in the cluster can access the device.
allNodes: true
devices:
- name: "large-black-cat"
attributes:
color:
string: "black"
size:
string: "large"
cat:
bool: true
通过上述组件,把“需要哪类设备、有哪些属性、在谁的节点上可用、每个 pod 是否有独立的设备访问权”等信息组合起来,在合适的节点上把设备分配给 pod,并尽量提升资源利用率和调度灵活性。
DRA 的主要优势:
- 灵活的设备过滤:使用通用表达式语言(CEL)对特定设备属性进行细粒度过滤
- 设备共享:通过引用相应的资源声明,多个容器或 pod 可以共享同一资源
- 集中式设备分类:设备驱动程序和集群管理员可以使用设备类为应用操作员提供针对各种用例优化的硬件类别
- 简化的 pod 请求:使用 DRA,应用操作员不需要在 pod 资源请求中指定设备数量
用户工作流

Driver creation 驱动程序创建:实现对特定 DeviceClass 的设备暴露与管理,创建并维护 ResourceSlice,确保设备可以被动态分配。
- 参与方:设备驱动开发者/硬件厂商;节点上的驱动组件(与 kubelet 及 DRA 控制平面协同工作)
- DeviceClass 的实现与注册:定义设备的属性、能力、匹配规则
- ResourceSlice 的暴露与维护:在每个节点上代表一个或若干物理设备的可用切片,带有可筛选的属性(厂商、型号、容量等)
- 与调度/Claim 控制器的对接接口:提供设备可用性状态、资源元数据、健康信息
Cluster configuration 集群配置:在集群层面定义和治理 DRA 的行为与策略,使资源声明与调度能够正确工作。
- 参与方:集群管理员、平台团队;需要对接的 API 服务器、调度器、Kubelet 以及驱动组件
- DeviceClass 配置与策略:定义哪些设备可用、哪些属性需要、是否允许分区/共享等
- 安全与访问控制:RBAC、准入控制、特权需求、特性门控(Beta/Alpha 功能开关)
- 调度策略与前置条件:CEL 过滤、属性匹配、节点选择逻辑、对 Claims 的提前绑定策略
- 观测与治理:Metrics、事件、日志、健康检查策略。
Resource claims 资源声明:应用或工作负载主动声明需要的设备资源,通过 ResourceClaim 与(可选)ResourceClaimTemplate 表达需求。
- 参与方:应用开发者、DevOps、CI/CD 流程;调度与运行时系统(控制平面)
- ResourceClaim:对特定 DeviceClass 的设备资源请求,包含数量、分区、属性过滤等约束
- 若需要,应用也可通过注入方式将 Claim 与 pod 的生命周期绑定(确保在 pod 启动前资源就绪)
pod 调度:将具备可用设备资源的 pod 安置到能够访问到绑定设备的节点上,并确保运行时容器能访问到这些设备。
- 参与方:调度器(Scheduler)、Kubernetes 控制平面 kubelet、容器运行时;运行时环境中的设备节点挂载逻辑
- 调度阶段:基于 ResourceClaim 的绑定状态、设备可用性、节点标签、亲和/排除等约束,将 pod 放置在具备相应资源的节点
- Bindings:Claim 与实际 ResourceSlice 的绑定已经在声明阶段或调度前完成,确保 Node 级别具备访问权限
- 运行时接入:kubelet 启动时确保容器能够看到并使用分配的设备切片(如设备节点、设备文件等)
K8s 工作流
ResourceSlice creation 资源切片创建: 集群中的驱动程序创建表示一个或多个设备的资源切片,这些设备位于一个受管理的相似设备池中。
Workload creation 工作负载创建: 集群控制平面检查新工作负载中对资源声明模板或特定资源声明的引用。
- 如果工作负载使用ResourceClaimTemplate,一个名为resourceclaim-controller的控制器会为工作负载中的每个Pod生成资源声明。
- 如果工作负载使用特定的 ResourceClaim,Kubernetes 会检查该 ResourceClaim 是否存在于集群中。如果 ResourceClaim 不存在,Pods 将无法部署。
ResourceSlice filtering 资源切片过滤: 对于每个 Pod,Kubernetes 检查集群中的资源切片,以找到满足以下所有条件的设备:可以访问资源的节点、拥有未分配的资源且这些资源符合 Pod 的 ResourceClaim 的节点。
Resource allocation 资源分配: 在为 Pod 的 ResourceClaim 找到合适的 ResourceSlice 后,Kubernetes 调度器会更新 ResourceClaim 以包含分配细节。
Pod scheduling Pod调度: 当资源分配完成后,调度器将Pod放置在可以访问分配资源的节点上。该节点上的设备驱动程序和kubelet配置设备以及Pod对设备的访问。
实践中注意事项
不同pod类型
Kubernetes 的 pod 其实是可以被多种工作负载控制器管理的,而 DRA 可以应用于任何通过 pod 模板创建的 pod,只要该 pod(或template)声明了资源请求(ResourceClaim/ResourceClaimTemplate)并且集群中存在可满足的 ResourceSlice。
DRA决策是基于每个 Pod 单独做出的,意味着每个 Pod 的设备请求在分配时可能得到不同的结果,即使它们来自同一个 ReplicaSet 或者同一组 Pod。
Standalone Pod(单 Pod 直放)
- 场景:直接创建一个 Pod,非由控制器管理。
- DRA 使用:在该 Pod 的模板或直接 Pod 规范中声明一个或多个 ResourceClaim 即可。资源会按Claim绑定到相应的 ResourceSlice,调度器在有可用资源的节点上安排该 Pod。注意如果直接指定 nodeName,可能绕过调度流程,需谨慎使用。
Deployment / ReplicaSet(副本集驱动的工作负载)
- 场景:大规模复制同一 Pod 模板,如服务副本。
- DRA 使用:在 Pod 模板中通过 ResourceClaim 或 ResourceClaimTemplate(推荐)为每个副本生成独立的设备请求,确保每个副本获得独立的设备访问权(若使用模板,则每个副本自动获得一个 Claim)。
exp1: ReplicaSet 下的3个副本,但设备切片分配不同
设备类别:gpu.nvidia
集群中有两台节点,分别暴露的 ResourceSlice 如下:
–NodeA: slice-01 (NVIDIA A100, 80GB)
–NodeA: slice-02 (NVIDIA A100, 40GB)
–NodeB: slice-03 (NVIDIA RTX A6000, 48GB)
Pod 3 个,通过 ReplicaSet 创建,且都请求 1 个 GPU(同一子请求)
–Pod-1 被调度到 NodeA,绑定到 slice-01。
–Pod-2 被调度到 NodeA,绑定到 slice-02。
–Pod-3 因为 NodeB 可用且也是 NVIDIA 之外的型号,按设备筛选仍然满足,但实际绑定到 slice-03。
三个 Pod 的“子请求”看起来相同(都请求 1 个 GPU),但实际绑定的设备特性不同(80GB A100、40GB A100、48GB RTX A6000)。Workload 需要能处理不同设备型号/容量带来的差异(如某些计算内核对显存有最小需求、或者驱动版本要求不同)。
exp2: 同一物理设备分成多个分区,两个 Pod 各自使用一个分区.每个 Pod 的“子请求”在物理设备层面有所不同(分区不同),即使它们的初始请求看起来一样。需要 workload 能容忍同一 GPU 的不同分区分配情况。
exp3: 两个 Pod 共享同一个设备(在策略允许的条件下).虽然是同一个“子请求”目标(同一设备切片),实际运行时的资源分配会在同一设备上对两个 Pod 进行调度与隔离。需要明确的容错和并发控制策略,否则可能出现性能抹平、资源争抢等问题。
exp4: 跨节点分布的 ReplicaSet,Pod 的设备可用性不同
StatefulSet(有序、唯一标识的有状态副本集)
- 场景:需要稳定网络标识和存储的有状态应用(如数据库、缓存集群)。
- DRA 使用:StatefulSet 与 ResourceClaimTemplate 结合非常自然,因为每个 Pod(有稳定 ordinal)可以获得独立的设备 Claim,且绑定关系随 Pod 的生命周期保持可预见性。
DaemonSet(每个节点一个 Pod)
- 场景:需要在集群每个节点上运行一个 Pod 的场景(如监控代理、节点级服务)。
- DRA 使用:每个 DaemonSet 的 Pod 可以独立申请设备资源(通过 Claim/Template),因每个节点有自己的 ResourceSlice,资源分配与调度相对简单且对齐性好。
Job / CronJob(批处理任务)
- 场景:一次性或定时执行的任务,每个 Job Pod 可以独立申请并绑定设备资源。
- DRA 使用:Job 模板中声明 ResourceClaim;每个 Pod(Job 的一个执行单元)获得独立资源,适合并发执行的场景。
示例
考虑优先级列表
可以为 ResourceClaim 或 ResourceClaimTemplate 中的请求提供优先级子请求列表。调度器将选择第一个可以分配的子请求。在下面的示例中,ResourceClaimTemplate 请求了一台颜色为黑色、尺寸为大型的设备。如果没有符合这些属性的设备,pod 将无法调度。通过优先列表功能,可以指定第二个替代方案,请求两台颜色为白色、尺寸为小型的设备。如果大型黑色设备可用,将会被分配。如果不可用,但有两台小型白色设备可用,pod 仍然能够运行。
1 | apiVersion: resource.k8s.io/v1 |