Kubernetes Scheduler Failing to Place AI Pods on AMD GPU Edge Nodes
Problem Description
In a remote edge site the AI inference workload never leaves the Pending state. Typical scheduler messages include:
0/5 nodes are available: 5 node(s) didn't match node selector.
Insufficient amd.com/gpu: 0/5 nodes are available: 5 node(s) have insufficient resources.
scheduler: no nodes match pod's node affinity
These errors indicate that the scheduler cannot find a node that satisfies the amd.com/gpu resource request or the node selector/affinity defined in the pod spec.
Root Cause Analysis
The underlying reasons fall into three categories, each documented in the evidence package:
- Incorrect node labeling. The AMD GPU Operator expects nodes to carry the label
amd.com/gpu(see AMD GPU Operator guide). In one incident the label was manually set togpu=amd, causing the selectoramd.com/gputo miss all nodes. - Device plugin registration failure. If the ROCm driver stack does not expose GPUs to the kubelet, the device plugin reports
amd.com/gpu: 0as allocatable (see the ROCm documentation). Kernel updates or missing firmware can break this path, resulting in “Insufficient amd.com/gpu”. - Resource name mismatch across clusters. In a federation scenario the control plane used
rocm.com/gpuwhile edge nodes reportedamd.com/gpu, leading to unschedulable pods (see the multi‑cluster incident).
All three failures share a common symptom: the scheduler sees either no matching label or zero allocatable GPU resources.
Investigation and Debugging Steps
Follow this checklist on the edge node(s) and the control plane.
1. Verify node labels
kubectl get nodes -L amd.com/gpu
Expected output (healthy node):
NAME STATUS ROLES AGE VERSION AMD.COM/GPU
edge-gpu-01 Ready 12d v1.27.3 2
If the column is empty or shows a different key (e.g., gpu=amd), the label is wrong.
2. Inspect device plugin registration
kubectl logs -n kube-system $(kubectl get pods -n kube-system -l app=amd-gpu-device-plugin -o jsonpath='{.items[0].metadata.name}')
Look for messages such as:
Failed to register device plugin: connection timed out
Failed to get device plugin resources: AMD GPU not found
These correspond to the “Failed to register device plugin” errors in the evidence.
3. Check allocatable resources
kubectl describe node edge-gpu-01 | grep -A3 "Allocated resources"
Sample problematic output:
Allocated resources:
cpu: 4
memory: 8192Mi
amd.com/gpu: 0
If amd.com/gpu is zero, the kubelet is not seeing any GPUs.
4. Validate ROCm driver and firmware
rocm-smi -i
Expected output lists each GPU with its health status. Missing entries indicate a driver or firmware issue (see the “Edge node reports 0 AMD GPUs after a kernel update” incident).
5. Confirm pod spec resource requests
apiVersion: v1
kind: Pod
metadata:
name: ai-inference
spec:
containers:
- name: model
image: myregistry/ai-model:latest
resources:
limits:
amd.com/gpu: 1
nodeSelector:
amd.com/gpu: "present"
Ensure the resource name matches the node label exactly.
Resolution
Apply the fixes that correspond to the identified cause.
Fix A – Correct Node Labeling
Remove the incorrect label and apply the required one.
# Remove wrong label
kubectl label node edge-gpu-01 gpu- amd
# Add correct label (GPU count is optional; presence is enough)
kubectl label node edge-gpu-01 amd.com/gpu=present --overwrite
After relabeling, the scheduler will match the pod’s nodeSelector or nodeAffinity.
Fix B – Restore ROCm Device Plugin Functionality
Typical steps after a driver regression:
- Reinstall the ROCm driver matching the kernel version (e.g.,
rocm-dkms-5.4). - Ensure firmware packages (
amdgpu-firmware) are present. - Restart kubelet to trigger device plugin registration:
systemctl restart kubelet
Validate with the kubectl describe node command; amd.com/gpu should now show the correct count.
Fix C – Align Resource Names Across Clusters
If using federation or a central CI pipeline, standardize on the official name amd.com/gpu everywhere.
# Example patch for a Deployment manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: inference
spec:
template:
spec:
containers:
- name: model
resources:
limits:
amd.com/gpu: 1 # changed from rocm.com/gpu
Verification
After applying the appropriate fix, run the following checks:
- Pod scheduling:
kubectl get pods -w– the pod should transition toRunning. - Node resource view:
kubectl get nodes -L amd.com/gpu– should display a non‑zero GPU count. - Device plugin logs: No “Failed to register device plugin” entries.
- GPU visibility inside the container:
kubectl exec -it ai-inference -- rocm-smi -i
Output should list the GPU(s) with health OK.
Prevention and Best Practices
- Automated label enforcement: Use a
DaemonSetthat runskubectl labelon every node after the GPU Operator completes, ensuring the label is always present. - Driver version pinning: Keep the ROCm driver version locked to a known‑good release in the edge node OS image; test kernel upgrades in a staging environment before rollout.
- Health monitoring: Export
amd.com/gpuallocatable metrics to Prometheus and alert when the value drops to zero. - Device plugin readiness probe: Add a
livenessProbeto the GPU Operator pod that checks the plugin socket (/var/lib/kubelet/device-plugins/amd.com/gpu.sock). - Consistent resource naming: Store the GPU resource name in a ConfigMap (e.g.,
gpu-resource-name: amd.com/gpu) and reference it in all manifests via{{ .Values.gpuResourceName }}to avoid mismatches.
FAQ
- Why does the pod stay Pending even though the node has a GPU?
Because the node either lacks the requiredamd.com/gpulabel or reports zero allocatable GPUs due to a failed device plugin registration. - Can I use a generic
gpulabel instead ofamd.com/gpu?
The AMD GPU Operator and Kubernetes device plugin expose the resource under the fully qualified nameamd.com/gpu. Using a different key will not be recognized by the scheduler. - How do I know which ROCm version is compatible with my kernel?
Consult the ROCm release notes (e.g., ROCm Documentation) for the supported kernel range. Pin the driver package to that version on edge nodes. - What if I need to run multiple AI pods on the same node?
Request the exact number of GPUs in each pod (amd.com/gpu: 1) and ensure the node’sallocatablecount reflects the total GPUs. The scheduler will pack pods until the count is exhausted. - Is there a way to debug intermittent device plugin registration failures?
Enable verbose logging for the GPU Operator (--v=4) and capture kubelet logs (journalctl -u kubelet -f). Look for timeout or “plugin not found” messages that correlate with network latency spikes to the edge node.
Related Topic Hub: GPU Infrastructure Troubleshooting Hub