Symptom
kubectl -n llm describe pod vllm-llama-7f9c-abcde
# Events:
# Warning FailedScheduling 0/6 nodes are available: 3 Insufficient nvidia.com/gpu,
# 3 node(s) didn't match Pod's node affinity/selector.
Step 1: do nodes advertise GPUs?
kubectl get nodes -L agentpool,node.kubernetes.io/instance-type \
-o custom-columns='NAME:.metadata.name,GPU_ALLOC:.status.allocatable.nvidia\.com/gpu,GPU_CAP:.status.capacity.nvidia\.com/gpu'
| Result | Meaning |
|---|---|
GPU nodes show <none> | Device plugin not running/registered on them (Step 2) |
| Numbers shown but all in use | Real capacity shortage (Step 4) |
| GPU nodes absent | Node pool scaled to 0 or failed to scale (Step 4) |
What's using GPUs now:
kubectl get pods -A -o json | jq -r '.items[] | select(.spec.containers[].resources.limits."nvidia.com/gpu" != null)
| [.metadata.namespace, .metadata.name, .spec.nodeName, .status.phase] | @tsv'
Completed or stuck pods (e.g. failed jobs) may still hold GPUs.
Step 2: device plugin / GPU operator health
kubectl -n gpu-operator get pods # or kube-system for a standalone device plugin
kubectl -n gpu-operator logs ds/nvidia-device-plugin-daemonset --tail=50
kubectl -n gpu-operator get pods -l app=nvidia-operator-validator
Common failures:
- Driver not loaded after a node image upgrade (driver container failing, or pre-installed driver mismatch). Logs:
could not load NVML library. - Node image already has drivers and the operator also tries to install them. Set
driver.enabled=falsein the operator values for images with pre-installed drivers (common on managed GPU node images). - Container toolkit not configured for the runtime (containerd config).
On a node:
kubectl debug node/gpu-node-01 -it --image=ubuntu -- chroot /host nvidia-smi
Step 3: scheduling constraints
GPU node pools are usually tainted. The pod needs the matching toleration and selector:
tolerations:
- key: "nvidia.com/gpu" # or sku=gpu:NoSchedule on AKS, depending on your pool setup
operator: "Exists"
effect: "NoSchedule"
nodeSelector:
agentpool: gpua100
resources:
limits:
nvidia.com/gpu: 1
Check node taints:
kubectl describe node gpu-node-01 | grep -A3 Taints
Also check: MIG profiles (a pod requesting nvidia.com/gpu won't fit a node advertising nvidia.com/mig-1g.10gb), time-slicing config, and ResourceQuota limits in the namespace.
Step 4: capacity
- Cluster autoscaler events:
kubectl -n kube-system logs deploy/cluster-autoscaler | grep -i gpu(on AKS/EKS managed autoscaler, check the provider's logs/events). - Node pool at max count → raise the maximum.
- Scale-up fails with allocation or capacity errors → regional GPU shortage or quota. See the GPU capacity runbook (other zones/regions, reservations, smaller GPUs).
- Quota: check vCPU quota for the GPU VM family in the subscription/account.
Quick recovery options
| Option | Effect |
|---|---|
| Delete finished/stuck GPU pods | Frees GPUs immediately |
| Lower replicas of non-critical GPU workloads (batch, dev) | Frees GPUs for production inference |
| PriorityClass for production inference | Scheduler preempts lower-priority GPU pods automatically |
| Serve a smaller/quantized model on available GPUs | Fewer or smaller GPUs per replica |
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata: { name: inference-critical }
value: 100000
preemptionPolicy: PreemptLowerPriority
Tip
Separate GPU node pools for production inference and for experiments/training. Shared pools turn every big experiment into a production incident.
Prevent it next time
- Alerts on Pending pods requesting GPUs for more than a few minutes.
- GPU operator/device plugin version pinned and tested with each node image upgrade.
- PriorityClasses and separate pools; quotas for non-production namespaces.
- Capacity reservations for baseline inference.