, ,

How to share one GPU between workloads in Kubernetes

Kubernetes hands out GPUs in whole numbers, so a notebook using 4% of an H100 holds the whole card. Time-slicing, MPS and MIG compared: what each protects you from, how to choose, and how to turn it on. With a live demo.

How to share one GPU in Kubernetes: one H100 shown as a whole GPU, time-slicing, MPS and MIG

AI infrastructure · Kubernetes · NVIDIA GPU Operator · MIG · MPS

In the monitoring post, one of the first alerts was a GPU sitting idle while a pod held it. The cause is simple: Kubernetes hands out GPUs in whole numbers. A notebook that uses 4% of an H100 still gets the whole card. This post explains the three ways to share one GPU (time-slicing, MPS and MIG), what each one protects you from, and how to pick. There is a live demo where you can put the same workloads on one GPU four ways and break each setup.

Part 1Monitoring Part 2Logging Part 3Lifecycle
Part 4 · this postSharing
Try it: GPU Sharing Lab

Four teams, one simulated 80 GB H100. Switch between a whole GPU, time-slicing, MPS and MIG, then add a noisy neighbour or crash a tenant and watch who suffers.

Open the demo →

The problemKubernetes counts GPUs in whole numbers

A pod asks for nvidia.com/gpu: 1. There is no 0.25. So every workload gets a full card, however little it uses. Here is a typical mix of four teams, each holding its own H100:

Chatbot
30%of one GPU, 18 GB
Embeddings job
45%of one GPU, 12 GB
Notebook
4%of one GPU, 8 GB
Dev testing
10%of one GPU, 6 GB

Four GPUs bought, less than one GPU of work done. At $2 to $4 per H100 hour, that is $6 to $12 an hour paid for idle silicon. Sharing fixes it, but each way of sharing gives up something different.

The optionsThree ways to share, plus the default

Option 1Time-slicing

The device plugin tells Kubernetes one GPU is, say, four. Four pods land on it and take turns on the whole card, like processes sharing a CPU.

Good atPacking lots of light, bursty work: notebooks, dev, CI tests. Works on almost any NVIDIA GPU.
Does not protectMemory or speed. One pod can take all 80 GB and others crash with out-of-memory. Everyone slows down when anyone gets busy.
Option 2MPS (Multi-Process Service)

A CUDA server runs the pods’ work at the same time instead of in turns. Each pod gets a cap on compute and memory.

Good atMany small inference services. Better throughput and latency than time-slicing because nothing waits for its turn.
Does not protectAgainst crashes. A fatal fault in one client can stop every client on that GPU. The compute cap is a ceiling, not a guarantee.
Option 3MIG (Multi-Instance GPU)

The GPU is cut in hardware into up to seven slices, each with its own compute, memory and cache. Each slice behaves like a small GPU.

Good atReal isolation between teams. A busy or crashing neighbour cannot touch your slice. Predictable latency.
Does not protectAgainst waste. Slice sizes are fixed, a slice cannot borrow idle capacity, and changing the layout needs the node drained. Only on A100, H100, H200, B200 and similar.
Whole GPUTime-slicingMPSMIG
Pods per GPU1As many as you setUp to 48 clientsUp to 7
Run at the same timen/aNo, take turnsYesYes
Memory isolationn/aNoneLimit per clientHardware
Crash isolationn/aYesNoYes
Speed guaranteeFull cardNoneCeiling onlyFixed slice
Change itn/aEdit a ConfigMapEdit a ConfigMapDrain the node

The testsThree things that go wrong, and which mode survives

Each of these is a button in the demo. Run them in every mode and the table above stops being theory.

A noisy neighbour arrives a fine-tuning job wants 40 GB and all the compute
Time-slicingEveryone now gets about half their speed. The chatbot’s p95 latency goes from about 87 ms to 144 ms.
MPSThe fine-tune hits its 20 GB memory limit and fails by itself. The others carry on.
MIGThe fine-tune gets its own 3g.40gb slice. The chatbot does not notice. But the notebook now has no slice left and waits.
A tenant needs more memory the embeddings job loads a bigger batch, +8 GB
Time-slicingOnly 2 GB are free because the fine-tune took the rest. The embeddings job crashes with CUDA out of memory, through no fault of its own.
MPSIts 20 GB limit still fits 20 GB. It carries on.
MIGIts 2g.20gb slice holds exactly 20 GB. It carries on.
One tenant crashes the notebook hits an illegal memory access
Time-slicingOnly the notebook dies. Each pod has its own CUDA context.
MPSThe fault can take down the MPS server, and with it every client on that GPU, including the chatbot.
MIGOnly the notebook’s slice is affected.

MIG in detailThe slice sizes on an H100 80GB

An H100 has seven compute slices and eight memory slices of 10 GB. Each MIG profile is named after both: 3g.40gb means three compute slices and 40 GB. You can mix sizes on one card as long as they fit.

1g.10gb
×7
1g.20gb
×4
2g.20gb
×3
3g.40gb
×2
4g.40gb
×1
7g.80gb
×1

The number on the right is how many of that profile fit on one card if you use only that profile.

The MIG trap. Once a node is in MIG mode it stops offering nvidia.com/gpu and offers slices such as nvidia.com/mig-2g.20gb instead (with the “mixed” strategy). Pods must ask for the slice by name. Plan which nodes are MIG and which are whole GPUs, and label them so teams know where to go.

The choiceWhich one should you use?

Big training job, or inference that keeps a GPU busy on its own?Whole GPU
Different teams or customers who must not affect each other?MIG
Many small inference services from one team, where throughput matters?MPS
Notebooks, development, tests, demos: light and bursty?Time-slicing
Need isolation and dense packing?MIG + time-slicing inside each slice

The setupTurn it on with the GPU Operator

  1. Write a sharing config

    Time-slicing and MPS both live in a device plugin config. This one turns each GPU into four.

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: gpu-sharing-config
      namespace: gpu-operator
    data:
      any: |-
        version: v1
        sharing:
          timeSlicing:          # or: mps:
            renameByDefault: false
            resources:
            - name: nvidia.com/gpu
              replicas: 4

    With renameByDefault: true the shared resource is called nvidia.com/gpu.shared, so pods have to opt in to sharing on purpose. MPS support needs a recent device plugin.

  2. Point the GPU Operator at it

    kubectl apply -f gpu-sharing-config.yaml
    kubectl patch clusterpolicies.nvidia.com/cluster-policy --type merge \
      -p '{"spec":{"devicePlugin":{"config":{"name":"gpu-sharing-config","default":"any"}}}}'

    After a minute, kubectl describe node shows nvidia.com/gpu: 4 per physical GPU, and GPU Feature Discovery adds a -SHARED suffix to the product label.

  3. Or switch a node to MIG

    # once, in the ClusterPolicy
    kubectl patch clusterpolicies.nvidia.com/cluster-policy --type merge \
      -p '{"spec":{"mig":{"strategy":"mixed"}}}'
    
    # per node, after draining it
    kubectl label node gpu-node-d nvidia.com/mig.config=all-1g.10gb --overwrite

    The MIG manager applies the layout and sets nvidia.com/mig.config.state=success. The lifecycle post shows the drain that has to come first.

  4. Ask for a share from a pod

    # time-slicing or MPS: same as before
    resources:
      limits:
        nvidia.com/gpu: 1
    
    # MIG: ask for the slice by name
    resources:
      limits:
        nvidia.com/mig-2g.20gb: 1
Before you call it done
  • You know which workloads may share and which must not.
  • Time-sliced GPUs only run work that can survive an out-of-memory crash caused by someone else.
  • Nothing that matters shares an MPS server with untrusted code.
  • MIG nodes are labelled, and teams know to ask for slices by name.
  • Your monitoring shows usage per pod, not just per GPU, so you can see who is taking what.
  • You checked GPU idle time before and after. Sharing should push it down.
Break it four ways

Open GPU Sharing Lab, add the noisy neighbour in time-slicing mode, then switch to MIG and do it again. The difference is the whole argument of this post.

Open the demo →

The series so far: monitoring, logging, node lifecycle and this post on sharing. Next: scheduling and queues.

About The Author


Discover more from Journal of Intelligent Infrastructure

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure

Subscribe now to keep reading and get access to the full archive.

Continue reading