Skip to content

Design: multiple accelerator vendors in the serving stack - #432

Merged
haarchri merged 2 commits into
modelplaneai:mainfrom
haarchri:design/serving-stack-accelerator-vendors
Oct 20, 2026
Merged

haarchri merged 2 commits into
modelplaneai:mainfrom
haarchri:design/serving-stack-accelerator-vendors

Conversation

@haarchri

@haarchri haarchri commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

Description of your changes

The serving stack we propose in #422 is NVIDIA-only by construction: every clouds component list installs the NVIDIA operator or DRA driver unconditionally, the accelerator taint and toleration are nvidia.com/gpu, and nothing checks that the devices an InferenceClass declares match the stack its cluster gets. AMD Instinct GPUs are reaching the clouds Modelplane targets, CPU inference (#509) adds a third device stack, and TPU and Trainium sit
behind the same gap: a cluster may carry devices served by more than one DRA driver, and the stack must install each driver's components exactly where that driver's devices are.

The design identifies the accelerator by the DRA driver name the class already carries (gpu.nvidia.com, gpu.amd.com, dra.cpu), with no vendor enum or map. The cluster composition derives the claimed drivers onto ServingStack
spec.accelerators, a component that is part of one driver's device stack is tagged with that driver's name, and the component join installs tagged components only where their driver is present. Every cloud participates, hand-written and generated: spec.accelerators is always sent, the generated halves tag through one more value per generate.py ALLOW entry, and each cloud's supported set is derived from its tags. Mismatches fail early in the composition functions: on the class, on the class/cluster pairing, and in the join. CPU is just another accelerator: dra-driver-cpu becomes one tagged chart, replacing #509's spec.cpu.pools field and transform.

Fixes #

I have:

  • Read and followed Modelplane's contribution process.
  • Run nix flake check (or ./nix.sh flake check) and made sure it passes.
  • Added or updated tests covering any composition function changes.
  • Signed off every commit with git commit -s.

@dennis-upbound dennis-upbound left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vendor tag needs to cover the metrics exporter, not just the driver.

DCGM ships as an NVIDIA-stack component (nvidia-dcgm, per the allowlist in #456), so tagging it NVIDIA is correct — and it means an AMD-only cluster installs no GPU exporter at all. The telemetry design in #363 names DCGM as the source for temperature, throttling, ECC and interconnect errors, which is the fault taxonomy behind a drain. Those go silent on AMD, and nothing says so.

AMD's GPU Operator ships a Device Metrics Exporter with Prometheus-format temperature, utilization, memory and power, so the fix looks like the driver case:

Chart(key="amd-device-metrics-exporter", accelerator_vendor="AMD", ...)

Worth a line in the design saying a vendor's stack includes its exporter. Keeping modelplane_gpu_* meaning the same thing whichever exporter produced it is #363's problem, not this one — I'll take that side.

dennis-upbound added a commit to dennis-upbound/modelplane that referenced this pull request Sep 22, 2026
The Upbound Inference environment runs this stack against real traffic
and records what it found. Five things from it.

The GPU exporter is vendor-dependent, which modelplaneai#432 makes true rather than
hypothetical: DCGM on NVIDIA, the Device Metrics Exporter on AMD, chosen
by the serving stack alongside the driver. This document had named DCGM
as the source, which would have left an AMD cluster with no GPU series
and no statement that it had. modelplane_gpu_* means the same thing
whichever exporter produced it, which is the point of renaming at all.

Three metrics that environment's dashboard has and this set did not.
Termination reason is the important one: a response cut off at the token
cap reports length and still returns 200 with a well-formed body, and
every layer above reads it as success. A timeout severing a stream looks
the same from the other side. That environment has now been truncated
twice, once by a route timeout and once by a load balancer, and neither
showed in a status code. Tool-call parse outcome fails the same quiet
way, returning the unparsed call as text. Tensor-pipe activity is the
third, and is closer to useful for inference than the graphics-engine
figure beside it.

Two traps, both observed rather than reasoned about. An engine
container's port is unnamed by default, so selecting it by name matches
nothing and reports nothing, which is how that environment's first
PodMonitor scraped no engines at all. Modelplane has to name it, and
matching by number instead would find the sidecar on a disaggregated
pod. And vLLM's model_name is the LLM while DCGM's modelName is the
card: one underscore and one capital apart, and a join across them pairs
every model with every GPU type.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Dennis Ramdass <dennis@upbound.io>

@negz negz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few questions and suggestions but I like this direction overall.

I think we should close #509 and roll CPU support into this design, since they're so closely related.

Comment thread design/multi-accelerator.md Outdated
Comment thread design/multi-accelerator.md Outdated
Comment thread design/multi-accelerator.md Outdated
Comment thread design/multi-accelerator.md
Comment thread design/multi-accelerator.md
@haarchri
haarchri force-pushed the design/serving-stack-accelerator-vendors branch from 3fe0dab to ddd9fe7 Compare October 16, 2026 16:25
Signed-off-by: Christopher Haar <christopher.haar@upbound.io>
@haarchri
haarchri force-pushed the design/serving-stack-accelerator-vendors branch from ddd9fe7 to 1b11f26 Compare October 16, 2026 16:25
@haarchri
haarchri requested a review from negz October 16, 2026 16:25
@haarchri haarchri moved this from Backlog to In Review in Modelplane Roadmap Oct 19, 2026

@negz negz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this addresses most of my earlier comments. A few more below.

Comment thread design/multi-accelerator.md Outdated
Comment on lines +179 to +181
acceptable: the stack components are per-cluster Helm releases holding no
state worth keeping, the nodes they served leave with the pools that claimed
them, and a stack reinstalls cleanly when a class returns. It is also the

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Existing the nodes stick around when their pool goes away. If someone removes the last NVIDIA pool while ModelDeployments are still running on it, nothing orders uninstalling the NVIDIA DRA driver against deleting the engine pods. If the driver goes first, the kubelet can't unprepare their claims, and the pods hang in Terminating until someone force deletes them.

I don't think this design needs to fix that, though. We should probably handle deleting a pool with running replicas better instead.

Comment thread design/multi-accelerator.md Outdated
Comment thread design/multi-accelerator.md Outdated
Comment thread design/multi-accelerator.md Outdated
Comment thread design/multi-accelerator.md Outdated
Signed-off-by: Christopher Haar <christopher.haar@upbound.io>
@haarchri
haarchri merged commit a128d50 into modelplaneai:main Oct 20, 2026
5 checks passed
@negz negz moved this from In Review to Done in Modelplane Roadmap Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants