Kubernetes Pod Stuck in Pending State Fix
In this tutorial, you'll learn about Kubernetes Pod Stuck in Pending State Fix. We cover key concepts, practical examples, and best practices.
The Problem
Your pod stays in Pending state for minutes and never transitions to Running:
NAME READY STATUS RESTARTS AGE
my-pod-6b4c9f8d7-abc12 0/1 Pending 0 5m
Running kubectl describe pod reveals a FailedScheduling event: the scheduler cannot find a node that satisfies the pod's resource requests, taint tolerations, node selectors, or PVC requirements.
Quick Fix
Step 1: Describe the pod
kubectl describe pod my-pod-6b4c9f8d7-abc12
Look at the Events section at the bottom:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2m default-scheduler 0/3 nodes are available: 1 Insufficient cpu, 2 Insufficient memory.
The message tells you exactly what is missing. Common reasons: CPU, memory, PVC not bound, node taints, or node selector mismatch.
Step 2: Check node resources
kubectl get nodes
kubectl top nodes
If nodes show low allocatable resources, your requests are too high:
NAME STATUS ROLES CPU MEMORY
node-1 Ready <none> 100m 512Mi # almost full
node-2 Ready <none> 50m 256Mi
Step 3: Reduce resource requests
Compare what the pod requests to what nodes offer:
kubectl get pod my-pod-6b4c9f8d7-abc12 -o jsonpath='{.spec.containers[*].resources.requests}'
WRONG -- requesting more than available:
resources:
requests:
memory: "4Gi" # node has only 2Gi free
cpu: "2000m" # node has only 500m free
RIGHT -- match realistic usage:
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
Apply the fix:
kubectl set resources deployment my-deployment --requests=cpu=250m,memory=256Mi --limits=cpu=500m,memory=512Mi
Step 4: Check taints and tolerations
kubectl get nodes -o jsonpath='{.items[*].spec.taints}'
If nodes have taints, your pod needs matching tolerations. Check using DodaTech's K8s Debugger tool for a visual taint-toleration map:
WRONG -- no toleration for node taint:
spec:
containers:
- name: app
image: nginx
# No tolerations section
RIGHT -- match the taint:
spec:
tolerations:
- key: "gpu"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: app
image: nginx
Step 5: Verify PVC status
If the pod uses a PersistentVolumeClaim, ensure it is bound:
kubectl get pvc
kubectl describe pvc <pvc-name>
STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
Pending 2m
A Pending PVC means no matching PV exists. Either create a PV or use dynamic provisioning with a StorageClass.
Step 6: Remove incorrect node selectors
kubectl get pod my-pod-6b4c9f8d7-abc12 -o jsonpath='{.spec.nodeSelector}'
If the selector does not match any node labels, remove it from the deployment spec.
Prevention
- Use
kubectl top nodesandkubectl top podsto monitor capacity before deploying. - Set resource requests based on observed usage, not guesses.
- Use
cluster-autoscalerto add nodes when resources are tight. - Define default resource limits with a
LimitRangein each namespace. - Use
kustomizeor Helm templates to standardize toleration and selector settings.
Common Mistakes with pending pod
- Mixing let bindings with <- bindings in do notation, producing type errors
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
These mistakes appear frequently in real-world K8S code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro