Get Started with DRA Support for NVIDIA GPUsΒΆ
OverviewΒΆ
Dynamic Resource Allocation (DRA) is a Kubernetes API for flexibly requesting, configuring, and sharing specialized devices like GPUs β a modern replacement for the extended-resource model (nvidia.com/gpu: 1) used by the NVIDIA Kubernetes Device Plugin. Starting with GPU Operator v26.7.0, the Operator can deploy and manage the DRA Driver for NVIDIA GPUs directly as a native operand, through a GPUCluster custom resource β no separate Helm chart required.
This guide walks through installing the GPU Operator with DRA support enabled, then allocating GPUs to workloads under two scenarios:
- Full GPU β exclusive access to an entire physical GPU
- MIG β a hardware-isolated Multi-Instance GPU slice of a supported GPU
AssumptionsΒΆ
This guide assumes the following are already in place:
- A Kubernetes cluster on v1.34.2 or later, with the
resource.k8s.ioDeviceClass API served by the cluster (this is the DRA API; if it isn't served, the Helm install in Part 2 fails with a validation error) - One or more nodes with NVIDIA GPUs attached
- For the MIG scenario, at least one MIG-capable data center GPU (Ampere architecture or newer β A100, A30, H100, and similar)
helmandkubectlconfigured against the target cluster
What You Will DoΒΆ
| Step | Action |
|---|---|
| 1 | Install the GPU Operator with GPUCluster (DRA) support enabled |
| 2 | Validate the installation |
| 3 | Allocate a Full GPU to a workload |
| 4 | Allocate a MIG slice to a workload |
Part 1 β Understand the DRA ModelΒΆ
The GPU Operator supports two GPU resource management models, and a cluster can only run one of them at a time:
Device-plugin model (ClusterPolicy) |
DRA model (GPUCluster) |
|
|---|---|---|
| GPU allocation | NVIDIA Kubernetes Device Plugin (extended resources) | DRA Driver for NVIDIA GPUs (ResourceClaims) |
| GPU driver | Managed by ClusterPolicy or NVIDIADriver |
Pre-installed, or managed separately by NVIDIADriver β not managed by GPUCluster |
| NVIDIA Container Toolkit | Deployed | Not deployed (workloads use CDI through DRA) |
| MIG Manager | Deployed | Not deployed β MIG is handled by the DRA driver itself |
Important: deploying and managing the DRA driver through
GPUClusteris currently a Technology Preview, served under thenvidia.com/v1alpha1API, and supports greenfield (new) installations only. There is no supported path to migrate an existingClusterPolicy(device-plugin) installation toGPUClusterin place β don't run both on the same cluster.
Since GPUCluster doesn't manage the GPU driver, decide up front how the driver gets onto your GPU nodes:
- Operator-managed β the GPU Operator installs and manages the driver through the
NVIDIADrivercustom resource - Pre-installed β the NVIDIA GPU driver is already installed on each GPU node, and the Operator leaves it alone
Both options are covered in Part 2.
Part 2 β Install the GPU Operator with DRA SupportΒΆ
Step 1 β Add the NVIDIA Helm RepositoryΒΆ
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia \
&& helm repo update
Step 2 β Install with GPUCluster EnabledΒΆ
Choose the command matching how the driver is managed on your cluster. Both set gpuCluster.deployCR=true and clusterPolicy.deployCR=false β the chart's own values file states plainly that having both CRs deployed at once is an invalid configuration, so clusterPolicy.deployCR=false isn't optional.
Operator-managed driver:
helm upgrade --install gpu-operator nvidia/gpu-operator \
--version=v26.7.0 \
--create-namespace \
--namespace gpu-operator-resources \
--set gpuCluster.deployCR=true \
--set clusterPolicy.deployCR=false \
--set driver.nvidiaDriverCRD.enabled=true
Pre-installed driver:
helm upgrade --install gpu-operator nvidia/gpu-operator \
--version=v26.7.0 \
--create-namespace \
--namespace gpu-operator-resources \
--set gpuCluster.deployCR=true \
--set clusterPolicy.deployCR=false \
--set driver.enabled=false
Note: if you're managing drivers through an
NVIDIADriverresource on DRA nodes, disable automatic driver upgrades (spec.driver.upgradePolicy.autoUpgrade: false) β automatic driver upgrades aren't yet supported for DRA nodes.If this node was already running device-plugin-model GPU workloads before this install: the driver-manager's uninstall step will fail if any process still holds the old NVIDIA kernel modules open (
resource temporarily unavailablein thek8s-driver-managerinit container logs, with ref counts onnvidia/nvidia_uvmgreater than zero). Stop or delete whatever pod is still using the GPU on that node β the driver-manager can't unload a kernel module that's actively in use, and the DRA install won't proceed until it's free.
Part 3 β Validate the InstallationΒΆ
Step 1 β Confirm the GPUCluster Resource is ReadyΒΆ
kubectl get gpucluster
Expected output:
NAME STATUS AGE
gpu-cluster ready 3m12s
If this returns "No resources found" instead: Helm doesn't error on an unrecognized
--setpath β it silently accepts it and does nothing. Check what actually got deployed:If you see akubectl get clusterpolicyClusterPolicynamedcluster-policyinstead of aGPUCluster, the values keys from Part 2 weren't applied. Double-check them against this chart version's actual values file (helm show values nvidia/gpu-operator --version v26.7.0) rather than trusting a flag name from memory or an older doc.
Step 2 β Confirm the DRA Operands are RunningΒΆ
kubectl get pods -n gpu-operator-resources
Expected output includes:
NAME READY STATUS RESTARTS AGE
gpu-operator-... 1/1 Running 0 4m
nvidia-dra-driver-controller-... 1/1 Running 0 3m
nvidia-dra-driver-kubelet-plugin-... 2/2 Running 0 3m
nvidia-dra-validator-... 1/1 Running 0 2m
nvidia-dcgm-exporter-dra-... 1/1 Running 0 2m
Note:
nvidia-dra-validatorbecomesRunning/Readyonly after the DRA driver successfully allocates a GPU on the node β if it's stuck, the driver isn't allocating GPUs yet, and the rest of this guide won't work until that's resolved. Thekubelet-pluginpod shows2/2because ComputeDomains are enabled by default alongside GPU allocation β if you disable ComputeDomains, expect1/1instead and nonvidia-dra-driver-controllerDeployment.
Step 3 β Confirm the DeviceClasses are AvailableΒΆ
kubectl get deviceclass
Expected output:
NAME AGE
compute-domain-daemon.nvidia.com 3m
compute-domain-default-channel.nvidia.com 3m
gpu.nvidia.com 3m
mig.nvidia.com 3m
vfio.gpu.nvidia.com 3m
gpu.nvidia.comβ Full GPU allocation (Part 4)mig.nvidia.comβ MIG slice allocation (Part 5)- The two
compute-domain-*classes are for Multi-Node NVLink and aren't used in either scenario in this guide
Step 4 β Confirm GPUs are Published as ResourceSlicesΒΆ
kubectl get resourceslices
Expected output:
NAME NODE DRIVER POOL AGE
00000-gpu.nvidia.com-<node>-... <node> gpu.nvidia.com <node> 99s
Each GPU node should have one or more ResourceSlice objects describing its GPUs.
Part 4 β Scenario: Full GPUΒΆ
A Full GPU gives a container exclusive access to one physical GPU β the default allocation mode, requiring no additional configuration.
Step 1 β Create a ResourceClaimTemplateΒΆ
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
name: single-gpu
spec:
spec:
devices:
requests:
- name: gpu
exactly:
deviceClassName: gpu.nvidia.com
allocationMode: ExactCount
count: 1
Save as single-gpu.yaml and apply:
kubectl apply -f single-gpu.yaml
Step 2 β Create a Pod Referencing the ClaimΒΆ
apiVersion: v1
kind: Pod
metadata:
name: gpu-workload
spec:
restartPolicy: Never
resourceClaims:
- name: gpu
resourceClaimTemplateName: single-gpu
containers:
- name: workload
image: nvcr.io/nvidia/cuda:12.6.2-base-ubi9
command: ["nvidia-smi", "-L"]
resources:
claims:
- name: gpu
Save as gpu-pod.yaml and apply:
kubectl apply -f gpu-pod.yaml
Step 3 β VerifyΒΆ
kubectl logs gpu-workload
You should see the GPU listed (e.g. GPU 0: NVIDIA A100-SXM4-80GB (UUID: GPU-...)), confirming the container received exclusive access to a physical GPU through the DRA claim rather than an extended resource request.
Part 5 β Scenario: MIGΒΆ
MIG (Multi-Instance GPU) partitions a MIG-capable GPU into hardware-isolated slices, each with dedicated compute, memory, and L2 cache. Unlike time-slicing, MIG isolation is enforced by the GPU hardware itself.
Prerequisite: MIG mode must already be enabled on the target GPU, and (for static MIG, the default and simplest path) the MIG partitions must already exist on the node β created with
nvidia-smi migormig-partedβ before the DRA driver's kubelet plugin starts. On Ampere GPUs (e.g. A100), MIG mode can't be toggled without a GPU reset; if MIG mode is off, the driver falls back to full-GPU allocation and advertises no MIG partitions at all. Hopper and later architectures can enable MIG mode on demand.Dynamic MIG β where the driver creates and destroys partitions automatically based on workload requests, with no pre-configuration needed β is available as an alpha feature gate (
DynamicMIG, defaultfalse) if you want the driver to manage partitioning itself instead. TheResourceClaimTemplateand pod manifests below work identically in either mode.
Step 1 β Create the Example NamespaceΒΆ
kubectl create namespace mig-example
Step 2 β Request Any MIG DeviceΒΆ
To request any available MIG slice without constraining the profile:
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
namespace: mig-example
name: any-mig
spec:
spec:
devices:
requests:
- name: mig
exactly:
deviceClassName: mig.nvidia.com
Save as any-mig.yaml and apply:
kubectl apply -f any-mig.yaml
Step 3 β Create a Pod Referencing the ClaimΒΆ
apiVersion: v1
kind: Pod
metadata:
namespace: mig-example
name: mig-pod
spec:
containers:
- name: workload
image: ubuntu:22.04
command: ["bash", "-c"]
args: ["nvidia-smi -L; sleep 9999"]
resources:
claims:
- name: mig
resourceClaims:
- name: mig
resourceClaimTemplateName: any-mig
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
Save as mig-pod.yaml and apply:
kubectl apply -f mig-pod.yaml
Note:
ubuntu:22.04doesn't includenvidia-smiβ the DRA driver's CDI integration injectsnvidia-smiand the host driver's libraries into the container at start, so a plain OS image is sufficient for verification.
Step 4 β VerifyΒΆ
kubectl get pod -n mig-example mig-pod
kubectl exec -n mig-example mig-pod -c workload -- nvidia-smi -L
Expected output:
NAME READY STATUS RESTARTS AGE
mig-pod 1/1 Running 0 12s
GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-ba3915a6-7bb2-0987-bcf1-6acec5d998b8)
MIG 1g.10gb Device 0: (UUID: MIG-76b4e048-83cf-5017-9d25-b1fac0396016)
The container sees only its allocated MIG slice (1g.10gb) as a distinct device with its own UUID β not the full physical GPU β confirming the hardware-level isolation.
Step 5 β Select a Specific MIG Profile (Optional)ΒΆ
To request a specific MIG profile (e.g. 1g.5gb) rather than any available slice, add a CEL selector matching the profile attribute the driver advertises:
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
namespace: mig-example
name: mig-profile
spec:
spec:
devices:
requests:
- name: mig
exactly:
deviceClassName: mig.nvidia.com
selectors:
- cel:
expression: "device.attributes['gpu.nvidia.com'].profile == '1g.5gb'"
Note: available profile strings depend on the physical GPU model β check the ResourceSlice attributes on your cluster (
kubectl get resourceslices -o yaml) to confirm what your hardware actually advertises before hardcoding a profile string.
Save as mig-profile.yaml, apply it the same way, and reference it from a pod with resourceClaimTemplateName: mig-profile, following the same pod pattern as Step 3.