, ,

How to monitor GPUs in Kubernetes

Kubernetes knows a pod asked for a GPU, not whether that GPU is busy, hot or dead. How DCGM Exporter, Prometheus and four alert rules fill the gap, with a live demo cluster to break.

How to monitor GPUs in Kubernetes: DCGM Exporter, Prometheus and alerts, with a GPU map showing one GPU with Xid 79

AI infrastructure · Kubernetes · NVIDIA GPU Operator · Prometheus · Observability

Kubernetes knows that a pod asked for one GPU. It does not know if that GPU is busy, overheating, out of memory or dead. That information sits inside the card, and you have to bring it out yourself. This post shows how the pieces fit, which numbers matter, and the four failures you will see first. I also built a live demo so you can break a cluster and watch the monitoring react.

Try it: GPU Cluster Watch

A simulated 12-GPU Kubernetes cluster in your browser. Click a scenario, such as a fan failure, an Xid error or a job that cannot be scheduled, and watch the metrics, alerts and events change. Nothing to install.

Open the demo →

The problemWhy Kubernetes alone is not enough

When you install the NVIDIA device plugin, each GPU node advertises a resource called nvidia.com/gpu. A pod asks for one, two or four of them, and the scheduler finds a node with that many free. That is the whole contract. To Kubernetes a GPU is a counter, like a slot in a car park.

So Kubernetes can tell you how many GPUs are handed out. It cannot tell you what happens to them after that. A pod can hold an H100 for a week and use none of it. A card can run at 88 °C and quietly slow down your training job. A GPU can drop off the PCIe bus, and the only sign is a line in the kernel log. You need three layers of information, and they come from different places.

Layer 1 · Allocation Who has which GPU?

Requests, free GPUs per node, pods stuck in Pending. Comes from the Kubernetes API.

kube-state-metrics
Layer 2 · Health Is the card working?

Temperature, power, clocks, ECC and Xid errors. Comes from the GPU driver.

DCGM Exporter
Layer 3 · Usage Is the workload using it?

Utilisation, memory, tensor-core activity, each tagged with the pod that owns the GPU.

DCGM Exporter + pod labels

The pipelineHow the numbers get from the card to your dashboard

The standard setup has four parts. The NVIDIA GPU Operator installs most of them for you: the driver, the container toolkit, the device plugin and the DCGM Exporter. You add Prometheus and Grafana, usually with the kube-prometheus-stack Helm chart.

EACH GPU NODE GPU + driver NVML counters DCGM Exporter DaemonSet, port 9400 kubelet pod-resources API pod labels Prometheus scrapes every 15–30 s /metrics kube-state-metrics GPU requests, Pending Grafana dashboards Alertmanager pages and tickets

The exporter asks the kubelet which pod owns each GPU, so every metric carries pod and namespace labels. That one join is what turns hardware numbers into something you can charge back to a team.

Two details are easy to miss. First, the exporter runs as a DaemonSet, one pod per GPU node, and only on nodes that have GPUs. Second, Prometheus only scrapes it if a ServiceMonitor exists and the Prometheus instance is allowed to pick it up. That second point is the usual reason people install everything and see no GPU metrics at all.

The numbersSix metrics worth a panel each

The DCGM Exporter publishes dozens of fields. These six answer most questions. Every name below is the real Prometheus series name, and every one is shown live in the demo.

DCGM_FI_DEV_GPU_UTIL GPU utilisation, %

Share of time in the last sample when at least one kernel was running. Good for spotting idle cards. Misleading for spotting busy ones (see below).

Watch for: an allocated GPU near 0% for hours.
DCGM_FI_DEV_FB_USED GPU memory used, MiB

Framebuffer in use. Pair it with DCGM_FI_DEV_FB_FREE to get a percentage. vLLM grabs about 90% at start-up by default, so a flat high line on an inference pod is normal.

Watch for: training jobs creeping towards 100%, then CUDA out-of-memory.
DCGM_FI_DEV_GPU_TEMP Temperature, °C

Core temperature. When a card gets too hot the driver lowers its clocks to protect it, and the job just runs slower. Nothing crashes.

Watch for: one card running much hotter than its neighbours in the same node.
DCGM_FI_DEV_POWER_USAGE Power draw, W

Real-time board power. An H100 SXM is rated at 700 W. Power is a good second opinion on utilisation: a card that is truly busy draws close to its limit.

Watch for: “100% utilised” with power near idle.
DCGM_FI_DEV_SM_CLOCK SM clock, MHz

The speed the compute cores are running at. It drops when the card throttles for heat or power. The throttle-reason field tells you which.

Watch for: clocks well below normal while the GPU is busy.
DCGM_FI_DEV_XID_ERRORS Last Xid error code

The driver’s error code for the last GPU fault. Zero means no error. Any other value needs a look, and some values mean the hardware is broken.

Watch for: anything above zero. This is your page-someone alert.

The utilisation trap

GPU_UTIL answers “was anything running?”, not “how much of the card was used?”. One small kernel running all the time scores 100%, even if it touches a tiny part of the chip. For a truer picture, the exporter also publishes profiling fields on data-centre GPUs, such as DCGM_FI_PROF_SM_ACTIVE and DCGM_FI_PROF_PIPE_TENSOR_ACTIVE.

GPU_UTIL100%
PROF_SM_ACTIVE38%
PROF_PIPE_TENSOR_ACTIVE12%

An illustrative example of one inference pod with small batches. The dashboard says “full”. The tensor cores, which are what you paid for, are mostly idle. Larger batches would fix it.

The failuresFour things you will see in your first month

Each of these is a button in the demo. Read the card, then open the demo and trigger it.

The GPU nobody is usingCost
What happensSomeone starts a notebook with a GPU, runs one cell and goes home. The pod keeps the card. Nobody else can have it.
What shows itavg_over_time(DCGM_FI_DEV_GPU_UTIL{pod!=""}[30m]) < 5
Why it mattersAt a typical cloud price of $2 to $4 per H100 hour, one idle card left for a month costs about $1,400 to $2,900.
In the demo: the GPUAllocatedButIdle alert is already firing on notebook-research-2. Click Delete idle notebook to clear it.
The job that never startsScheduling
What happensA training job asks for four GPUs. There are free GPUs in the cluster, but no single node has four. The pod sits in Pending.
What shows itkube_pod_status_unschedulable == 1 and the event Insufficient nvidia.com/gpu.
Why it mattersFree GPUs are not the same as usable GPUs. Multi-GPU jobs need them on the same node, so scattered small jobs block big ones.
In the demo: click Submit 4-GPU training job and watch it wait.
The slow cardPerformance
What happensA fan fails. One GPU gets hot, the driver lowers its clocks, and that GPU now runs slower than the other three.
What shows itDCGM_FI_DEV_GPU_TEMP > 85 with a falling DCGM_FI_DEV_SM_CLOCK.
Why it mattersIn multi-GPU training every step waits for the slowest card. One hot GPU slows the whole job, and nothing reports an error.
In the demo: click Break a fan on gpu-node-a, then select GPU 1 and watch the temperature cross the red line.
The GPU that disappearsHardware
What happensThe card stops responding on the PCIe bus (Xid 79). The device plugin marks it unhealthy, and the pod using it crashes.
What shows itDCGM_FI_DEV_XID_ERRORS > 0, then the series for that GPU stops. The node’s allocatable GPUs drop from 4 to 3.
Why it mattersMissing data is a signal too. Alert on the error, and also on a GPU that has stopped reporting.
In the demo: click Inject Xid 79. The training job fails, and the 4-GPU job can no longer fit on that node.

Which Xid errors mean broken hardware

Xid codes come from the NVIDIA driver and also appear in dmesg. Some point at your code, some at the card. A short list that covers most cases:

13XidGraphics engine exceptionUsually a bug in the application, such as an out-of-range memory access.Check the code
31XidGPU memory page faultUsually the application. Look at the job before the hardware.Check the code
48XidDouble-bit ECC errorMemory error the card could not correct. Drain the node and reset the GPU.Hardware
74XidNVLink errorA problem on the link between GPUs. Multi-GPU jobs on that node will fail or slow down.Hardware
79XidGPU has fallen off the busThe card stopped answering. Needs a node reboot at least, often a hardware ticket.Hardware
Useful default. The NVIDIA device plugin already ignores the application-type Xids (such as 13 and 31) when it decides whether a GPU is healthy. So if the plugin marks a GPU unhealthy, treat it as a hardware problem until you prove otherwise.

The setupBuild it on your own cluster

This assumes a Kubernetes cluster with at least one NVIDIA GPU node and Helm installed. The steps are in order: each one needs the one before.

  1. Install Prometheus and Grafana

    The last flag lets Prometheus pick up ServiceMonitors from other Helm releases, including the GPU Operator’s. Without it you get no GPU metrics.

    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm repo update
    helm install kps prometheus-community/kube-prometheus-stack \
      -n monitoring --create-namespace \
      --set prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues=false
  2. Install the GPU Operator with its ServiceMonitor on

    helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
    helm repo update
    helm install gpu-operator nvidia/gpu-operator \
      -n gpu-operator --create-namespace --wait \
      --set dcgmExporter.serviceMonitor.enabled=true

    If your nodes already have the NVIDIA driver installed, add --set driver.enabled=false.

  3. Check that the exporter is publishing

    kubectl -n gpu-operator port-forward svc/nvidia-dcgm-exporter 9400:9400 &
    curl -s localhost:9400/metrics | grep DCGM_FI_DEV_GPU_UTIL

    You should see one line per GPU, with gpu, UUID, Hostname and, for GPUs in use, pod and namespace labels.

  4. Add the alert rules

    These are the four rules the demo uses. Apply them with kubectl apply -f gpu-alerts.yaml. The release: kps label is what the Prometheus from step 1 looks for.

    apiVersion: monitoring.coreos.com/v1
    kind: PrometheusRule
    metadata:
      name: gpu-alerts
      namespace: monitoring
      labels:
        release: kps
    spec:
      groups:
      - name: gpu
        rules:
        - alert: GPUXidError
          expr: DCGM_FI_DEV_XID_ERRORS > 0
          labels: {severity: critical}
          annotations:
            summary: "Xid {{ $value }} on {{ $labels.Hostname }} GPU {{ $labels.gpu }}"
        - alert: GPUThermalThrottle
          expr: DCGM_FI_DEV_GPU_TEMP > 85
          for: 5m
          labels: {severity: warning}
        - alert: GPUAllocatedButIdle
          expr: avg_over_time(DCGM_FI_DEV_GPU_UTIL{pod!=""}[30m]) < 5
          for: 30m
          labels: {severity: info}
        - alert: GPUPodUnschedulable
          expr: kube_pod_status_unschedulable == 1
          for: 10m
          labels: {severity: warning}
  5. Import a dashboard

    In Grafana, go to Dashboards → New → Import and enter ID 12239, the NVIDIA DCGM Exporter dashboard. It is a good start. Add a panel per team using sum by (namespace) (DCGM_FI_DEV_GPU_UTIL) so people can see their own usage.

Pick your temperature line per card. The 85 °C in the rule above is a starting point. Slowdown temperatures differ between GPU models. Run nvidia-smi -q -d TEMPERATURE on a node to see the real limits for your cards, and set the alert a few degrees below.
Before you call it done
  • Every GPU node has a running nvidia-dcgm-exporter pod.
  • Prometheus shows the exporter as a healthy target under Status → Targets.
  • GPU metrics carry pod and namespace labels for GPUs in use.
  • The Xid alert goes to a person, not just a channel.
  • You have an alert for a GPU that stops reporting, not only for one that reports an error.
  • Each team can see its own GPU usage and idle time.
See it before you build it

Open GPU Cluster Watch and run all four failures in two minutes. Every chart shows the exact PromQL query behind it, so you can copy it into your own Grafana.

Open the demo →

Related on this site: AI Infrastructure Lab Workbook (section F covers observability hands-on) and sizing GPUs for Kubernetes.

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