GPU sharing can cut idle capacity, but node metrics miss inference demand and memory contention. Queue depth offers a clearer signal for scaling.

GPU waste in Kubernetes often hides behind healthy pods and ordinary-looking dashboards. A cluster can report that workloads are running normally while expensive accelerators sit partly idle, because the scheduler sees allocated devices rather than the useful work being done on them. For teams running their own AI inference, the challenge isn’t that standard Kubernetes optimization has stopped working; it’s that whole-GPU allocations and weak visibility can leave hardware underused or exposed to noisy neighbors. The gap is between a resource that looks fully assigned and one that’s producing value.
Whole GPUs create expensive idle capacity
Kubernetes typically allocates a GPU as a whole device, even when an inference workload uses only a slice of its compute. That model is simple to reason about, but it can leave capacity stranded: one pod holds the device, while other workloads wait or run elsewhere. Teams may provision for peak demand that never arrives, leaving costly accelerators underused during quieter periods. The result is a familiar infrastructure trade-off: capacity reserved to protect response times can become a persistent cost when demand doesn’t reach the level it was sized for.
NVIDIA’s Multi-Instance GPU (MIG) can divide supported cards into smaller instances, while Kubernetes Dynamic Resource Allocation offers more flexible resource management. These approaches address allocation at different layers, and neither makes planning disappear. MIG’s available partition sizes shape how workloads can fit together; more flexible allocation still depends on the cluster and its workloads being configured to use it. Adoption remains uneven, however, so the theoretical ability to share hardware doesn’t guarantee that a team can do so in practice.
Conventional monitoring may not expose the waste. Pods appear healthy, while GPU costs blend into the node group’s bill, making it hard to connect a particular service’s demand with the accelerators it occupies. This is more significant than it looks: if teams can’t see the relationship between allocation and useful work, they may respond to perceived shortages by adding capacity rather than changing how existing devices are assigned.
Sharing saves capacity but adds risk
Time-slicing through the NVIDIA device plugin or GPU Operator lets multiple jobs take turns on one GPU. It can raise the amount of work served by a device when workloads don’t all need it at the same moment. Inference engines such as vLLM also use continuous batching to improve compute utilization, though batching and GPU sharing solve different problems and each has trade-offs. Batching groups requests within an inference system; time-slicing shares a physical device across jobs. Treating them as interchangeable can obscure where contention is coming from.
With time-slicing, jobs share the GPU’s memory pool without isolation. A workload that suddenly consumes more memory can trigger out-of-memory errors for neighboring jobs, including an inference server that wasn’t responsible for the spike. That’s a different failure pattern from a single overloaded pod: the job that appears to fail may be only the closest visible victim. Context switching also takes time away from useful computation, so sharing can improve access to capacity without making every workload faster.
The resulting failures can be hard to diagnose. A batch job may get blamed while other workloads sharing the card are restarted, and the underlying cause may be a memory spike or contention elsewhere on the device. If you’re working in this space, the operational question isn’t simply whether sharing is enabled; it’s whether teams can identify which workloads share a GPU and correlate their behavior when something goes wrong.
Node metrics can obscure real demand
Memory use alone can be a poor signal for inference load. Engines such as vLLM may reserve a large block of GPU memory at startup, so a quiet server and a busy one can look similar in memory dashboards. That reservation may reflect how the engine manages available memory, rather than the amount of active work at a given moment. A metric can be accurate and still answer the wrong operational question.
Compute utilization can mislead too. Continuous batching makes it difficult to tell from node-level figures how much work is useful, and a utilization reading doesn’t by itself explain whether requests are waiting, being processed efficiently, or competing for capacity. Node metrics are still useful for understanding the hardware, but they offer a coarse view of demand inside the serving system. Here's the thing: autoscaling based on a coarse signal can react late, or react to activity that doesn’t correspond neatly to user demand.
Demand signals often live inside the serving engine, beyond the reach of autoscalers that rely on node metrics. Queue depth—the number of requests waiting for service—is one useful measure because it can track incoming demand more directly than allocated memory. It isn’t a complete description of performance on its own; teams still need to interpret it alongside the behavior of the service and the GPU resources available to it. But it brings the scaling decision closer to the work the system is meant to handle.
Scale from the serving layer
For inference workloads, feed serving-engine metrics such as queue depth into autoscaling decisions instead of relying on node memory or compute alone. This shifts the signal from what hardware has been reserved toward whether requests are accumulating at the service. The distinction matters when memory remains high even as demand changes. A serving-layer signal can give autoscalers a more direct view of pressure, though it still needs to be chosen and interpreted in context.
Keep jobs with volatile, high memory demands off time-sliced GPUs. Where workloads need to share a card, MIG provides memory isolation on supported NVIDIA hardware, though its predefined partition sizes limit flexibility and require capacity planning. These choices involve different costs: time-slicing can make more use of a device, while isolation can reduce the risk that one workload’s memory behavior disrupts another. The right fit depends on how predictable the jobs are and how much interference the team can tolerate.
Start with the clearest source of savings: workloads holding an entire GPU while using little of its compute. The practical lesson for Kubernetes operators is to measure what inference is doing inside the serving engine, then match GPU allocation and scaling to that demand. And yet, better measurement won’t remove every constraint: hardware partition options, workload variation, and the operating model all shape what teams can change. A more useful signal is a starting point. Not a capacity plan by itself.
What operators should watch next
The implications reach beyond a single autoscaling rule. Allocation, monitoring, and workload placement have to tell a consistent story: which service owns a GPU, what demand it’s seeing, and whether another job can safely share the device. When those views don’t line up, operators may see healthy pods and still miss idle capacity or the source of a disruption (and this is the part most people overlook). Better visibility won’t guarantee higher utilization, but it can make the trade-offs explicit.
What this means for you is that GPU efficiency needs to be judged at the level where inference work happens, while failures need to be traced across workloads that share hardware. Queue depth can help indicate pressure; memory and compute metrics can add context; allocation choices determine how much isolation or sharing is possible. The numbers here are underwhelming if they stop at a dashboard showing devices as busy. The more useful question is whether those devices are serving the work the cluster was built to run.
Discussion
Sign in to join the discussion.