Skip to main content

DRA or HAMi? What Actually Shares Your GPUs in 2026

12 min readDora NodaDora Noda
Share
On this page

On August 7, 2026, the CNCF published the question every self-hosted GPU operator had been asking in private: does Kubernetes Dynamic Resource Allocation make HAMi obsolete? The post, written by HAMi contributor Mesut Oezdil, gives a short answer of no — and then spends several thousand words explaining why the short answer is the least interesting part.

Here is the version you can act on. DRA absorbs exactly one of HAMi's two jobs: expressing fractional GPU requests in a language the Kubernetes scheduler natively understands. It does not touch the other job: enforcing those fractions inside the container at runtime.

HAMi's response has been to split along that exact line — keep the enforcement muscle, rebuild the scheduling half on top of DRA — across three repositories you can install today. So the real 2026 question is not which project wins. It is which layer of the converged stack your fleet should standardize on, and what moving HAMi-sliced workloads onto DRA claims concretely involves.

That is what this post delivers: the verdict first, the cost math that makes sharing non-optional, the mechanism on both sides, the migration path with its checklist and honest caveats, and a decision table for four fleet shapes.


Why sharing is non-optional: the one-tenant-per-card tax

Kubernetes' legacy device-plugin API schedules GPUs the way it schedules everything else it cannot see inside: by integer count. A pod requests nvidia.com/gpu: 1 and gets an entire physical card. There is no vocabulary for half a GPU or 4GB of one — the smallest unit the API understands is one whole device.

That model is fine for a training job that saturates a card for hours. It is ruinous for the workload a self-hosted platform actually runs at the tenant edge: AI-agent sandboxes and small inference services that each need a few gigabytes of VRAM and then sit mostly idle between requests. Put one 4GB sandbox on a card via the stock device plugin and everything else on that card is reserved and unusable, because the scheduler has no way to hear "this pod only needs a slice."

The numbers make the tax concrete. Take the two GPU servers a self-hosted fleet can actually rent today — a 20GB card at €184/month and a 96GB card at €889/month, each reserving roughly 2GB for driver and scheduler overhead — and size them for 4GB and 8GB sandboxes:

Card (list price)SandboxWhole-GPU tenantsSliced tenants€/tenant unsliced€/tenant sliced
20GB, €184/mo4GB14€184.00€46.00
20GB, €184/mo8GB12€184.00€92.00
96GB, €889/mo4GB123€889.00€38.65
96GB, €889/mo8GB111€889.00€80.82

Slicing cuts the per-tenant cost by 50% in the worst case shown and 96% in the best, and every combination lands in that range. This is not a lab result, either: DaoCloud runs HAMi across more than 10,000 GPUs in 10-plus data centers at over 80% average utilization, cutting GPU operating costs roughly in half, and SF Technology shrank its GPU footprint up to 57%. Fractional sharing is the difference between one tenant per card and a real multi-tenant platform.


How HAMi filled the gap the API left

HAMi — Heterogeneous AI Computing Virtualization Middleware, voted into CNCF Incubating status on July 15, 2026 — built its entire pipeline to express what the device-plugin vocabulary could not: give this pod 8,000 MiB and 10% of a GPU, and make the limit stick. A user writes three extended resources (nvidia.com/gpu, nvidia.com/gpumem, nvidia.com/gpucores), and four pieces of machinery make them real:

  1. A mutating webhook routes the pod to HAMi's scheduler extender, because the default scheduler treats extended resources as opaque integers and cannot even parse the request.
  2. The extender filters nodes, scores cards, and picks a specific device UUID — rejecting overcommitted placements with the CardInsufficientMemory event HAMi operators know well.
  3. The decision is recorded where the API has room for it: an annotation string only HAMi components understand.
  4. The device plugin on the node reads that annotation during Allocate(), injects memory and compute limits into the container, and preloads libvgpu.so so the limits are enforced.

It works at serious scale, but notice how much of the design is a workaround. The webhook exists because the scheduler cannot parse the request. The annotation exists because the API has no field for which card and how much.

The whole agreement between scheduler and kubelet rides on a private string format. Every fractional-GPU project of that era made the same trade with its own private dialect — which is exactly the situation DRA was built to end.


What DRA changes underneath

DRA replaces integer counting with a claims model deliberately shaped like PersistentVolumeClaims. Four objects in the resource.k8s.io/v1 API group carry the flow — device classes, claims, resource slices published per node by drivers, and allocation state — each with a different owner. The timeline matters for planning, because "DRA" graduated feature by feature, not all at once:

VersionDateWhat shipped
1.34Sep 2025Core DRA graduates to GA; consumable capacity lands as alpha behind the DRAConsumableCapacity gate
1.35Core DRA locked on by default
1.36 "Haru"Apr 22, 2026Prioritized lists go stable; partitionable devices and consumable capacity reach beta, on by default
1.37Sep 2026Fractional values in CapacityRequestPolicyRange (new DRAFractionalCapacityRange beta gate); NVIDIA DRA driver now community-governed under kubernetes-sigs after the March 2026 CNCF donation

Core DRA alone does not give you HAMi-style sharing — its baseline model is multiple pods referencing one claim, i.e. sharing an allocation rather than each getting an accounted slice. The piece that maps onto HAMi is consumable capacity, and it adds exactly two things.

A driver can mark a device with allowMultipleAllocations, declaring that independent claims, even from different namespaces, may land on it simultaneously. And a claim can carry a capacity request: a quantity of a named resource on the device instead of the whole device. The scheduler then does for GPU memory what it has always done for node memory — bookkeeping, guaranteeing the sum of granted capacity never exceeds what the device advertised.

Line that up against HAMi's extended resources and the mapping is nearly mechanical. gpumem: 8000 becomes a capacity request for memory. gpucores: 10 becomes a capacity request for compute. The extender's filter step ("does this card still have 8,000 MiB unpromised?") becomes the upstream scheduler's own math, and the CardInsufficientMemory rejection turns into a standard unschedulable claim.

Upstream Kubernetes adopted the model the workaround had been implementing all along — which is why HAMi's maintainers treat DRA as convergence, not competition, and why their 2026 roadmap names complete DRA adaptation as a goal.


The line DRA does not cross: enforcement

Here is the boundary that decides whether you still need HAMi at all. DRA, consumable capacity included, is a promise tracker. It guarantees the scheduler never promises more than a device has. It does nothing about a container that breaks the promise at runtime.

With GPUs, that is the failure mode that actually hurts, because CUDA does not care what a ResourceClaim says. One greedy allocation loop will happily take VRAM a neighbor was counting on.

Enforcement is HAMi's second job, and it lives in HAMi-core: a C library preloaded into the container that intercepts CUDA and NVML calls and applies the granted limits from user space. The behavior is easy to verify on any shared card. Give two pods 8,000 MiB grants each, then have one deliberately allocate past its limit.

The offender gets a CUDA out-of-memory at exactly its 8,000 MiB boundary while the neighbor keeps running untouched — even if the physical card still has free VRAM. The quota is the limiter, per container, which is precisely what a shared multi-team cluster needs.

Be equally honest about the ceiling, because it decides the adversarial case. This is software enforcement via library interposition. A workload that bypasses the preload — static linking against the driver, unsetting the control flag, containers nested inside containers — escapes it. For mutually untrusting tenants you still want hardware partitioning (MIG, which HAMi can also schedule); for cooperative teams sharing expensive cards, interception wins on granularity: 1 MiB memory steps and 1% compute steps against MIG's fixed profiles.

Nothing in DRA replaces this layer. A DRA driver's job ends at the Container Device Interface: mounting device nodes and setting environment for the runtime. What happens after the process starts calling CUDA is out of scope by design. So the realistic architecture pairs the two — DRA as the request-and-scheduling language, HAMi-core as the runtime muscle, and a driver in between translating one into the other.


The migration, concretely

HAMi ships the converged stack as three pieces, and each one answers a different operator question:

  • k8s-dra-driver is the foundation: a DRA driver that publishes each GPU's memory and compute as consumable capacity in ResourceSlices, resolves allocations on the node via its kubelet plugin, and wires containers up through CDI with HAMi-core enforcement attached. The project describes it as the first open-source NVIDIA DRA driver with consumable capacity enabled.
  • HAMi-DRA answers the "what about my existing manifests?" question. It is a mutating webhook that strips classic extended resources out of incoming pods and generates equivalent ResourceClaims on the fly — the resource names it translates are configurable, so renamed or vendor-specific resources keep working. Because it emits a standard ResourceClaim and leaves scheduling to whoever owns it, it drops into clusters running Volcano, KAI Scheduler, or any other scheduler without patching them. The traditional pipeline had to inject an extender into every scheduler; DRA removes that coupling. HAMi-DRA v0.2.0 was declared production-ready alongside HAMi v2.9 (now at v0.2.1), with support grown past NVIDIA to Ascend, Enflame, and Hygon DCU.
  • HAMi itself documents DRA mode as an installation option since v2.8, and observability carries over: the DRA monitor is on by default and exposes per-container device metrics over Prometheus, so dashboards built against HAMi exporters survive the switch.

The convergence is easiest to see in YAML. What HAMi users have written for years — one card, 10 GiB of its memory, half its compute:

yaml
resources:
  limits:
    nvidia.com/gpu: 1
    nvidia.com/gpumem: 10240
    nvidia.com/gpucores: 50

keeps working unchanged in DRA mode, because the webhook rewrites it at admission into the native claim form: a device count plus memory and cores capacity requests against HAMi's DeviceClass, visible to kubectl and guarded by RBAC instead of hidden in an annotation. Either way, nvidia-smi inside the running container reports 10,240 MiB — the granted slice, not the physical card — because HAMi-core is doing the same interception it always did. The request language changed; the runtime contract did not.

Before you plan the move, four requirements and three caveats, stated flatly:

  1. Kubernetes v1.34 or newer with consumable capacity enabled. On 1.34 and 1.35 the gate is alpha and off by default, so you must set it on the API server — which rules out managed clusters that hide those flags. On 1.36 it is beta and on by default, which quietly removes the biggest adoption blocker.
  2. A DRA driver for your silicon. NVIDIA is the mature path; Ascend, Enflame, and Hygon DCU are arriving. Traditional mode covers 12-plus device families through per-vendor plugins, so heterogeneous clusters stay on the device-plugin path until drivers catch up.
  3. One mode per cluster, never both. Two bookkeepers that each believe they own the same VRAM — the scheduler extender and the DRA scheduler — will double-promise it, because neither sees the other's promises.
  4. If the GPU Operator manages your drivers, install it with the device plugin disabled first, because the DRA stack replaces that job. Confirm with kubectl get resourceslice, then watch kubectl get resourceclaim once a workload lands.

The caveats: consumable capacity is still beta upstream, the driver's own Helm chart is still marked work-in-progress, and DRA-side vendor coverage is a fraction of traditional mode's. And one architectural loss is worth naming — HAMi-DRA ships no scheduler of its own, so it cannot make topology-aware placement decisions. A claim for two GPUs on an NVLink-wired node gets a count and a capacity, not a "prefer the connected pair" constraint, so bandwidth-sensitive multi-GPU workloads either stay on a topology-modeling scheduler or accept bandwidth-blind placement.


Which layer to standardize on now

Your fleetStandardize onWhy
NVIDIA-only, Kubernetes 1.36-plus, you control the control planeDRA mode in staging now, production on your workload mix's evidenceNative scheduling math, RBAC-visible claims, no scheduler patching; start via the HAMi-DRA webhook so no manifest changes
Mixed-vendor accelerators (AMD, Cambricon, Moore Threads, and the rest)Traditional HAMi modeThe widest moat DRA touches last: no DRA drivers exist for most of that silicon yet
Mutually untrusting tenants on shared cardsMIG hardware partitioning (which HAMi can schedule)Library interposition is bypassable; only silicon-enforced boundaries hold against adversaries
Managed cluster without API-server flags, pre-1.36Traditional mode until you upgradeThe alpha gate cannot be enabled where the control plane is hidden from you

Note what is deliberately absent from that table: ripping out working traditional-mode HAMi to chase DRA on principle. The enforcement layer is identical on both sides — the migration changes how requests are expressed and scheduled, not what protects neighbors at runtime. Move when the native API buys you something concrete (scheduler portability, claim visibility, dropping the extender), not when a version number tells you to.

GPU sharing on Kubernetes was built in the gaps of an API that could only count. DRA closed the gap, HAMi kept the muscle, and for the first time the request, the schedule, and the enforcement all speak the same language.

Running agent sandboxes or inference on GPUs you own? Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex