NVIDIA GPU Workloads on Kubernetes — Part 10: MIG vs Time-Slicing — Choosing a GPU Sharing Mode

Part 10 of the Falcon AI workbook series. Every post so far treated each H100 as a single, whole unit of scheduling. This post changes that assumption — and uses the observability stack from Part 9 to actually show the difference rather than just describe it.

Prerequisite

You’ve completed Part 9: Prometheus, Grafana, and DCGM dashboards are live and showing real per-GPU utilization data for gpu-wk-01/gpu-wk-02.

Recap: where Falcon AI stands

RoleCountHostnamesStatus after Part 9
Management (control plane)3mgmt-01, mgmt-02, mgmt-03Ready, tainted NoSchedule
GPU worker2gpu-wk-01, gpu-wk-02Ready, full observability stack live

Why this decision matters at Falcon AI’s scale

16 GPUs across 2 nodes is enough for serious training, but it’s not infinite. Once notebooks, small inference tests, and hyperparameter sweeps start competing with large training jobs for the same pool, whole-GPU scheduling wastes capacity — a Jupyter notebook doing exploratory data analysis doesn’t need a full H100. Sharing modes exist to close that gap. The two mechanisms work completely differently, and picking the wrong one for a given workload has real cost and reliability consequences.

The core mechanism difference

MIG carves the physical GPU into genuinely isolated instances at the hardware level — each gets dedicated streaming multiprocessors and a fixed memory slice, walled off from the others. Time-slicing keeps the whole GPU as one unit but rapidly switches which process is executing, the way a CPU scheduler multiplexes cores — no hardware isolation, so one noisy process can starve the others.

The full comparison

FeatureMIG (Multi-Instance GPU)Time-Slicing
MechanismHardware partitioningSoftware context switching
IsolationStrong (hardware level)Weak (shared GPU)
MemoryDedicatedShared
PerformancePredictable / guaranteedVariable
Noisy neighbor riskNoYes
Fault isolationExcellentPoor
K8s resource namenvidia.com/mig-<profile> (e.g. mig-1g.5gb)nvidia.com/gpu (virtualized count)
Best forProduction, multi-tenant, latency-sensitiveDev/test, best-effort, short jobs

Mapping this to Falcon AI’s actual workloads

Falcon AI workloadRecommended modeWhy
KServe production inference endpoint (Part 8)MIGPredictable latency matters for a serving SLA; noisy-neighbor variance is unacceptable
ML engineer’s Kubeflow notebook, exploratory workTime-slicingBursty, low-utilization, tolerates variable performance, needs many cheap slots more than guaranteed throughput
Multi-node NCCL/MPIJob training (Part 8)Neither — full GPUDistributed training wants the entire physical GPU’s SMs and memory bandwidth; partitioning would hurt, not help
CI/CD smoke tests (Rung 1 of Part 7’s ladder, run continuously)Time-slicingShort-lived, low-stakes, just needs “a GPU,” not “the best possible GPU”

Decision flowchart

Step 1 — Enable MIG on a subset of GPUs (on gpu-wk-01)

Falcon AI doesn’t need to commit its whole fleet to one mode — MIG can be enabled per-node, even per-GPU. We’ll dedicate 2 of gpu-wk-01‘s 8 H100s to MIG for the KServe inference workload, leaving the rest full-GPU for training.

kubectl label node gpu-wk-01 nvidia.com/mig.config=all-1g.10gb --overwrite

The MIG Manager (installed as part of the GPU Operator back in Part 2) picks up this label and reconfigures the labeled GPUs automatically — same reconcile pattern from Part 3, just triggered by a label instead of a node join.

kubectl get pods -n gpu-operator -l app=nvidia-mig-manager -o wide -w

Pass criteria:

kubectl describe node gpu-wk-01 | grep mig

Expected: nvidia.com/mig-1g.10gb listed under Allocatable with the correct instance count.

Step 2 — Enable time-slicing on the remaining GPUs (cluster-wide default, or per-node)

yaml

# time-slicing-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: time-slicing-config
  namespace: gpu-operator
data:
  any: |-
    version: v1
    sharing:
      timeSlicing:
        resources:
        - name: nvidia.com/gpu
          replicas: 4
kubectl apply -f time-slicing-config.yaml

kubectl patch clusterpolicy cluster-policy --type merge -p \
  '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config"}}}}'

Pass criteria:

kubectl describe node gpu-wk-01 | grep "nvidia.com/gpu"

Expected: Allocatable now shows 4x the physical GPU count on time-sliced GPUs (replicas: 4 — four workloads can share each physical device).

Step 3 — Validate with the observability stack from Part 9

This is where Part 9 pays off directly — pull up the DCGM Exporter Grafana dashboard and compare:

  • A MIG instance’s utilization graph should show a flat, dedicated ceiling regardless of what else runs on the parent GPU
  • A time-sliced GPU’s utilization graph should show visible contention — total utilization climbing but individual process throughput dropping as more processes share the same physical device

If you don’t see that pattern, something’s misconfigured — go back to Step 1 or 2 before trusting the sharing mode in production.

Where we are

✅ Understand the hardware-partitioning vs software-context-switching distinction concretely, not just by definition ✅ MIG enabled on 2 of gpu-wk-01‘s GPUs for the KServe inference workload ✅ Time-slicing enabled on the remainder for notebooks and short-lived jobs ✅ Used Part 9’s Grafana dashboards to visually confirm both modes behave as expected


Next in the series: Part 11 — Key Concepts Deep Dive, covering RuntimeClass, taints/tolerations, node affinity/topology, and gang scheduling in more depth than we’ve touched on so far — the last set of building blocks before this workbook is a complete reference.

One Comment

Add a Comment

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