Skip to content
DevOpsSociety

Kubernetes 1.37 Makes DRA Extended Resources GA: GPU Scheduling Without a Separate Device Plugin

Kubernetes 1.37 graduates DRA extended resources to GA, so pods requesting nvidia.com/gpu can be served by a DRA driver without a device plugin. What changes and how to migrate node pools.

Published your local timeupdated

Kubernetes 1.37 Makes DRA Extended Resources GA: GPU Scheduling Without a Separate Device Plugin

Verified

Kubernetes 1.37

If you started piloting Dynamic Resource Allocation on your GPU nodes this year, you probably ended up running two things that both claim to own the same cards: the NVIDIA device plugin, because every Helm chart, Kueue queue and notebook template in the company still asks for nvidia.com/gpu: 1, and a DRA driver, because that's where the scheduling features are going. Kubernetes 1.37, released on 26 August, promotes DRA extended resources to GA, and that removes the reason for the second component. This piece covers what actually changed, what a migration off the device plugin looks like node by node, and what 1.37 on its own doesn't fix.

What went GA in Kubernetes 1.37

The feature is tracked as KEP-5004, "DRA: Handle extended resource requests via DRA Driver". A cluster admin sets an extendedResourceName on a DeviceClass. From then on, a Pod that asks for that name in its ordinary container resources gets a device allocated by the DRA scheduler plugin, with no ResourceClaim in the workload spec. The Kubernetes v1.37 DRA updates post frames it as what makes DRA adoption gradual: existing workloads keep working unmodified while allocation moves to DRA underneath them.

The facts you'll want for a change ticket:

  • Feature gate: DRAExtendedResource, needed on kube-apiserver, kube-controller-manager, kube-scheduler and kubelet. In 1.37 it's GA, defaults to true and is locked to that default, so you can't switch it off. The source marks the gate for removal in 1.40.

  • Maturity path: alpha in 1.34 (off by default), beta in 1.36 (on by default), stable in 1.37. The 1.37 DRA blog post and the KEP's implementation-history section say alpha arrived in 1.35, but the feature-gate reference, the KEP metadata and the Kubernetes source all put it in 1.34. If you're on 1.35, it was still alpha and off by default either way.

  • Implicit names: every DeviceClass, whether it sets extendedResourceName or not, can be requested as deviceclass.resource.kubernetes.io/<class-name>. That only works if the class name is also a valid extended resource name.

Why teams ended up running two GPU stacks

Before this change, DRA and the device plugin model spoke different request languages. DRA wanted a ResourceClaim or ResourceClaimTemplate referenced from the Pod. Everything that already existed (vendor charts, internal templates, admission policies, quota objects, the spreadsheet finance uses to charge back GPU hours) spoke resources.limits: nvidia.com/gpu. Rewriting all of it before you could turn DRA on wasn't realistic, so the device plugin stayed, advertising the cards through node.status.capacity, while the DRA driver published the same cards through ResourceSlice objects.

That's two sources of truth for one piece of hardware. NVIDIA's own DRA driver chart refuses to enable its full-GPU resources by default for exactly this reason: its validation template says the driver can't run alongside the standard GPU device plugin on the same node, and it makes you set an explicit override to prove you've removed the plugin. The KEP authors considered rewriting Pod specs with a mutating webhook or a CLI, and rejected both as extra infrastructure to own.

A device plugin and a DRA driver on a GPU node merging into a single DRA driver while pod requests flow through unchanged

How the DeviceClass mapping works

The mapping is a single field on the cluster-scoped DeviceClass. This is essentially what NVIDIA's DRA driver chart (v25.12.0 and current main) creates when the cluster serves resource.k8s.io/v1:

apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
  name: gpu.nvidia.com
spec:
  selectors:
  - cel:
      expression: "device.driver == 'gpu.nvidia.com' && device.attributes['gpu.nvidia.com'].type == 'gpu'"
  # Any device matching the selector can now satisfy a plain nvidia.com/gpu request
  extendedResourceName: nvidia.com/gpu

And the workload doesn't change at all:

apiVersion: v1
kind: Pod
metadata:
  name: cuda-vectoradd
spec:
  restartPolicy: Never
  containers:
  - name: cuda
    image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0
    resources:
      limits:
        nvidia.com/gpu: 1   # same syntax as the device plugin; no resourceClaims block

"No ResourceClaim" means none that you write. The scheduler creates one on the Pod's behalf during binding: one per Pod, owned by the Pod and deleted with it, using a device request per container per extended resource. It then records the mapping in a new Pod status field, status.extendedResourceClaimStatus, with resourceClaimName and a requestMappings list of containerName, resourceName and requestName. The kubelet reads that to hand the right devices to the right containers through CDI. Expect generated claims in kubectl get resourceclaims, and keep cleanup scripts away from them.

Two constraints matter for planning. First, only one DeviceClass should carry a given extendedResourceName. If two do, the more recently created one wins, and a tie goes to whichever name sorts first alphabetically. Second, on any one node a given resource name comes from the device plugin or from DRA, never both. Mixing across nodes is supported: the same Pod spec can land on a plugin-backed node or a DRA-backed node.

Before 1.37 (or with the gate off)

Kubernetes 1.37

nvidia.com/gpu: 1 in a Pod

Served only by the device plugin

Served by the plugin or by a DRA driver, depending on the node

Components per GPU node during migration

Plugin for legacy specs, DRA driver for claims

One per node: either the plugin or the DRA driver

Where capacity is visible

node.status.capacity

Plugin nodes: node.status.capacity. DRA nodes: ResourceSlice

Workload changes needed

Rewrite to ResourceClaim to use DRA

None for basic whole-device requests

DRAExtendedResource gate

Off by default in 1.34 and 1.35, on in 1.36

GA, locked on

Migrating off the NVIDIA device plugin, node pool by node pool

The KEP's rollout guidance boils down to "replace device plugins with DRA drivers one node at a time," and that's the right shape. Here's the sequence we'd use.

  1. Confirm prerequisites. Control plane and kubelets on 1.37 (or 1.36 with the beta gate still on). A container runtime with CDI support. A DRA driver release that ships a DeviceClass with extendedResourceName: nvidia.com/gpu, and preferably that has been tested against your GPU driver and OS image.

  2. Inventory what reads node capacity. Anything computing GPU headroom from node.status.capacity or allocatable (dashboards, chargeback jobs, autoscaler logic) will see zero GPUs on migrated nodes, because DRA advertises through ResourceSlice. The KEP calls out cluster-autoscaler integration as something that may need extra work. Check your autoscaler's DRA support against its own release notes before you move a pool that scales.

  3. Create one new node pool labelled so the device plugin DaemonSet doesn't schedule there, and deploy the DRA driver's kubelet plugin only on that pool. Existing pools keep the plugin.

  4. Run real workloads through it. The Pod spec is identical, so you shift traffic with node selectors or taints, not manifest rewrites.

  5. Verify each Pod. Check that status.extendedResourceClaimStatus is populated, that a generated ResourceClaim exists, and that the container can see the expected device.

  6. Watch the right metrics. scheduler_pending_pods, especially the unschedulable queue. Scheduler plugin latency for NodeResourcesFit and DynamicResources. dynamic_resource_allocation_resourceclaim_creates_total{status="failure"}. dynamic_resource_allocation_resource_claims{source="extended_resource"} on kube-controller-manager to count generated claims.

  7. Convert the remaining pools by cordoning, draining, removing the plugin, and adding the DRA driver. The KEP's tell for a botched swap is nvidia.com/gpu capacity on the node that doesn't drop to zero after the plugin is gone.

  8. Remove the device plugin DaemonSet once no node carries it, then drop the chart override you needed to get past NVIDIA's coexistence check.

One gap to note: NVIDIA's chart at current main still enforces that override and still says it'll relax the default "once KEP 5004 has reached GA." Until a release changes that, treat vendor support as the gating item, not the Kubernetes version.

Rolling migration of GPU nodes from device plugin to DRA driver, one node pool at a time

What 1.37 does not fix

The biggest caveat is also the easiest to forget. Kubernetes supplies the mapping, and your hardware vendor supplies the driver. The KEP lists a third-party DRA driver and CDI support in the runtime as hard dependencies, and says upgrade and downgrade behaviour of those drivers is the vendor's responsibility. How mature a driver is for your GPU generation, MIG layout or OS image is a vendor question that upstream GA doesn't answer.

Extended-resource syntax also doesn't gain DRA's expressiveness. The generated claim requests an exact count of devices from one class. You can't put attribute selectors, cross-device constraints or per-workload device config in resources.limits. For those you still write a ResourceClaim. You can publish several classes under distinct names (NVIDIA's demo specs map a MIG profile this way) so teams pick a shape without learning the claim API.

Managed Kubernetes is the other brake. As of today, GKE's Rapid channel release notes list 1.37 builds. Azure's published calendar shows AKS 1.37 preview in September and GA in October 2026, and those are plan dates, not promises. Amazon EKS's standard-support page tops out at 1.36. Check your provider's release calendar, and check separately whether its managed GPU add-ons have moved off the device plugin, before you schedule the work. More upgrade-planning coverage lives in our Kubernetes section.

Decision rule: if you're on 1.36+ and already run a DRA driver next to the device plugin, start step 3 now; the dual-stack workaround is the thing 1.37 lets you delete. If you're below 1.36, or your vendor's chart still makes you override its coexistence check, plan the upgrade and keep the plugin until the vendor release lands.

Written by

DevOpsSociety Editorial Team

Editorial Team

The DevOpsSociety Editorial Team covers DevOps, cloud infrastructure, Kubernetes, AI infrastructure, platform engineering, cybersecurity, FinOps, and modern engineering practices. We publish practical insights, technical guides, architecture analysis, and research for engineers and technology leaders.

More from DevOpsSociety
The Infrastructure Briefing

Get the infrastructure briefing.

Practical DevOps, cloud, AI infrastructure and engineering insights, delivered weekly. Read by engineers and engineering leaders.

No spam. Unsubscribe anytime.