Table of Contents
- Understanding the Kubernetes Troubleshooting Workflow
- Common Kubernetes Issues and Solutions
- 2.1 Pods Not Starting or Stuck in Pending/CrashLoopBackOff
- 2.2 Services Not Routing Traffic Correctly
- 2.3 Resource Constraints (CPU/Memory Issues)
- 2.4 Network Policy Blocks (Unexpected Connectivity Loss)
- 2.5 StatefulSet Failures (e.g., Volume Claims, DNS Issues)
- 2.6 Ingress Controller Problems (404/503 Errors)
- 2.7 Node-Level Issues (Unhealthy Nodes, Disk Pressure)
- Essential Troubleshooting Tools
- Best Practices for Effective Troubleshooting
- Conclusion
- References
1. Understanding the Kubernetes Troubleshooting Workflow
Before diving into specific issues, it’s critical to adopt a systematic workflow. Kubernetes is a distributed system, so problems often stem from interactions between components (e.g., pods, services, nodes). Follow this steps:
- Identify the affected component: Is it a pod, service, node, or ingress? Start with the most granular object (e.g., a pod) before moving up the stack.
- Check the status: Use
kubectl get <resource>(e.g.,kubectl get pods) to see the current state (e.g.,Pending,CrashLoopBackOff). - Inspect events and details: Run
kubectl describe <resource> <name>to view events, configuration, and errors (e.g.,kubectl describe pod my-pod). - Check logs: For pods, use
kubectl logs <pod>(orkubectl logs <pod> -pto view previous logs). - Validate dependencies: Ensure supporting resources (e.g., services, ConfigMaps, Secrets, StorageClasses) exist and are correctly configured.
2. Common Kubernetes Issues and Solutions
2.1 Pods Not Starting or Stuck in Pending/CrashLoopBackOff
Pods are the smallest deployable units in Kubernetes, so they’re often the first place to look. Common symptoms include:
Pending: Pod is not scheduled on any node.CrashLoopBackOff: Pod starts but crashes repeatedly.ImagePullBackOff: Kubernetes fails to pull the container image.
Common Causes
- Insufficient resources: Nodes lack CPU/memory to meet pod
requests. - Invalid container image: Image name/tag is incorrect, or the registry is unreachable.
- Misconfigured probes: Liveness/readiness probes fail, causing the pod to restart or stay unready.
- Invalid YAML: Syntax errors in the pod/deployment manifest (e.g., missing commas, incorrect indentation).
Troubleshooting Steps & Solutions
Step 1: Check pod status and events
Run kubectl describe pod <pod-name> to view events (under the “Events” section at the bottom). For example:
kubectl describe pod my-pod
Look for messages like:
FailedScheduling: 0/3 nodes are available: 3 Insufficient cpu.(Resource issue)Failed to pull image "my-app:v1": rpc error: code = Unknown desc = failed to pull and unpack image(Image pull error)
Step 2: Resolve resource constraints
If events show Insufficient cpu or Insufficient memory, check the pod’s resources in its manifest. Nodes must have enough free resources to satisfy the pod’s requests.
Example fix: Reduce requests or add more nodes to the cluster.
resources:
requests:
cpu: 100m # Lower from 500m if nodes are constrained
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
Step 3: Fix image pull issues
- Verify the image name/tag (e.g.,
nginx:latestvs.nginx:1.21). - Ensure the cluster has access to the registry (e.g., add
imagePullSecretsfor private registries). - Test image pull manually with
docker pull <image>(on a node) to confirm the image exists.
Step 4: Debug probes
If probes are failing, check logs to see why the container isn’t responding. For example, a liveness probe might expect a /health endpoint that isn’t implemented.
View probe configuration in kubectl describe pod:
Liveness: http-get http://:8080/health delay=0s timeout=1s period=10s #success=1 #failure=3
Fix: Update the probe path/port, or disable probes temporarily (not recommended for production).
2.2 Services Not Routing Traffic Correctly
Services expose pods internally or externally, but traffic may fail to route. Symptoms include:
- Unable to access pods via the service’s ClusterIP or DNS name.
curl <service-name>from another pod returnsconnection refusedorno route to host.
Common Causes
- Selector mismatch: Service
selectordoesn’t match pod labels, so no endpoints are created. - Port misconfiguration: Service
portdoesn’t match the container’scontainerPort. - Pods are unready: Readiness probes fail, so pods aren’t added to the service’s endpoints.
Troubleshooting Steps & Solutions
Step 1: Verify the service and endpoints
Check if the service has endpoints (pods that match its selector):
kubectl describe service <service-name> # Look for "Endpoints" section
kubectl get endpoints <service-name> # List healthy pods attached to the service
If endpoints are empty, the selector is likely incorrect.
Step 2: Fix selector/label mismatch
Ensure the service’s selector matches pod labels. For example:
# Service manifest (incorrect selector)
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app # Pods must have label "app: my-app"
ports:
- port: 80
targetPort: 8080
If pods have app: wrong-name, update the selector or pod labels.
Step 3: Test port connectivity
- Confirm the service’s
targetPortmatches the container’s listening port (e.g., container listens on 8080, buttargetPortis set to 80). - Test directly from a pod:
kubectl run test-pod --image=busybox --rm -it -- sh wget -qO- <service-name>:<service-port> # Should return a response if routing works
Step 4: Debug DNS resolution
If the service isn’t reachable via its DNS name (e.g., my-service.default.svc.cluster.local), test DNS with:
kubectl run dns-test --image=busybox --rm -it -- sh
nslookup my-service.default.svc.cluster.local # Should resolve to the service’s ClusterIP
If DNS fails, check the coredns pods in the kube-system namespace (they may be crashing or misconfigured).
2.3 Resource Constraints (CPU/Memory Issues)
Pods rely on CPU and memory, and misconfigured requests/limits can cause instability. Symptoms include:
Evictedpods (due to node pressure).OOMKilled(Out-of-Memory) errors in pod logs.- Slow performance or unresponsive applications.
Common Causes
- Limits too low: Pod exceeds its memory
limit, triggering an OOM kill. - No requests set: Pods without
requestsmay be scheduled on nodes with insufficient resources. - Node resource exhaustion: Nodes run out of CPU/memory due to overcommitment.
Troubleshooting Steps & Solutions
Step 1: Identify resource-hungry pods
Use kubectl top to check pod resource usage:
kubectl top pods --sort-by=cpu # Sort pods by CPU usage
kubectl top pods --sort-by=memory # Sort by memory usage
Step 2: Adjust requests/limits
Set requests (minimum resources required) and limits (maximum allowed) to prevent starvation and OOM kills:
resources:
requests:
cpu: 200m # 200 millicores (0.2 CPU)
memory: 256Mi
limits:
cpu: 500m # Prevent CPU throttling if exceeded
memory: 512Mi # OOM kill if exceeded
Step 3: Use auto-scaling
For dynamic workloads, use:
- Horizontal Pod Autoscaler (HPA): Scale pod count based on CPU/memory usage.
- Vertical Pod Autoscaler (VPA): Automatically adjust
requests/limits(requires the VPA add-on).
2.4 Network Policy Blocks (Unexpected Connectivity Issues)
Network Policies control traffic flow between pods, but overly restrictive policies can block legitimate traffic. Symptoms include:
- Pods unable to communicate with each other suddenly.
curl <pod-ip>from another pod returnsconnection timed out.
Common Causes
- Overly restrictive policies: A policy denies all ingress/egress by default, blocking necessary traffic.
- Incorrect CIDR ranges: Policies target the wrong IP ranges (e.g., blocking the cluster’s internal CIDR).
Troubleshooting Steps & Solutions
Step 1: Check network policies
List all network policies in the namespace and describe them:
kubectl get networkpolicy -n <namespace>
kubectl describe networkpolicy <policy-name> -n <namespace>
Step 2: Test connectivity
Use a test pod to simulate traffic and identify blocked paths:
kubectl run test-pod --image=busybox --rm -it -- sh
telnet <target-pod-ip> <port> # Check if the port is reachable
Step 3: Relax the policy
If a policy is too strict, update it to allow necessary traffic. For example, allow ingress from pods with label app: frontend:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
spec:
podSelector:
matchLabels:
app: backend # Pods to protect
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # Allow traffic from frontend pods
2.5 StatefulSet Failures (e.g., Volume Claims, DNS Issues)
StatefulSets manage stateful applications (e.g., databases) with stable network identities and persistent storage. Common issues include:
- Pods failing to create (e.g.,
0/x nodes are available: x pod has unbound immediate PersistentVolumeClaims). - DNS resolution failures for stateful pod names (e.g.,
my-statefulset-0.my-service.default.svc.cluster.local).
Common Causes
- Missing headless service: StatefulSets require a headless service (no ClusterIP) to assign stable DNS names.
- StorageClass unavailable: No StorageClass exists to provision the PersistentVolumeClaim (PVC).
- PVCs stuck in
Pending: The storage backend (e.g., AWS EBS, GCP PD) can’t provision volumes.
Troubleshooting Steps & Solutions
Step 1: Check PVC status
StatefulSets create PVCs with names like <statefulset-name>-<ordinal>-<volume-name>. Verify they’re bound:
kubectl get pvc -n <namespace>
If PVCs are Pending, check the StorageClass:
kubectl get sc # Ensure a default StorageClass exists
Step 2: Verify the headless service
StatefulSets require a headless service with the same serviceName as specified in the StatefulSet:
# Headless service (required)
apiVersion: v1
kind: Service
metadata:
name: my-stateful-service
spec:
clusterIP: None # Headless (no ClusterIP)
selector:
app: my-statefulset
ports:
- port: 80
Step 3: Debug DNS for stateful pods
Stateful pod DNS names follow the format <pod-name>.<service-name>.<namespace>.svc.cluster.local. Test resolution:
kubectl run dns-test --image=busybox --rm -it -- sh
nslookup my-statefulset-0.my-stateful-service.default.svc.cluster.local
2.6 Ingress Controller Problems (404/503 Errors)
Ingress controllers (e.g., NGINX, Traefik) route external traffic to services. Common issues:
404 Not Found: Ingress rule doesn’t match the request path.503 Service Unavailable: Backend service has no healthy endpoints.
Common Causes
- Ingress controller not running: The controller pod (e.g.,
nginx-ingress-controller) isCrashLoopBackOff. - Path/host mismatch: Ingress
rulesdon’t match the request’s host/path. - TLS misconfiguration: Invalid certificates or missing
tlssection in the ingress manifest.
Troubleshooting Steps & Solutions
Step 1: Check the ingress controller
Ensure the controller is running and has healthy pods:
kubectl get pods -n <ingress-namespace> # e.g., ingress-nginx
Step 2: Verify ingress rules
Describe the ingress to check backend services and paths:
kubectl describe ingress <ingress-name>
Step 3: Check controller logs
Ingress controllers log traffic and errors. For NGINX:
kubectl logs -n ingress-nginx <nginx-controller-pod> # Look for 404/503 entries
2.7 Node-Level Issues (Unhealthy Nodes, Disk Pressure)
Nodes are the worker machines in Kubernetes. Issues here affect all pods on the node. Symptoms include:
- Nodes marked
NotReady. DiskPressureorMemoryPressuretaints on nodes (pods are evicted).
Common Causes
- Kubelet failure: The kubelet (agent on nodes) is down or misconfigured.
- Resource exhaustion: Node disk/CPU/memory is full.
- Network issues: Node can’t communicate with the API server.
Troubleshooting Steps & Solutions
Step 1: Check node status and events
kubectl get nodes
kubectl describe node <node-name> # Look for "Conditions" (e.g., DiskPressure)
Step 2: Fix disk pressure
If DiskPressure is detected, free up space on the node:
# On the node (via SSH)
df -h # Check disk usage
du -sh /var/lib/docker # Docker often uses significant space
docker system prune -a # Clean up unused containers/images (use with caution!)
Step 3: Restart the kubelet
If the kubelet is unresponsive:
# On the node
sudo systemctl restart kubelet
sudo journalctl -u kubelet -f # Check kubelet logs for errors
3. Essential Troubleshooting Tools
- kubectl: The primary CLI for interacting with Kubernetes clusters (e.g.,
kubectl describe,kubectl logs). - stern: Tail logs from multiple pods/containers (e.g.,
stern my-deployment). - k9s: A terminal UI for managing Kubernetes clusters (simplifies viewing pods, logs, and events).
- kube-ps1: A shell prompt plugin that shows the current Kubernetes context/namespace.
- Prometheus + Grafana: Monitor cluster metrics (CPU, memory, pod status) to identify trends.
- kube-debug: A plugin for debugging pods with ephemeral debug containers (e.g.,
kubectl debug -it <pod> --image=busybox).
4. Best Practices for Effective Troubleshooting
- Reproduce the issue: Replicate the problem in a staging environment to avoid disrupting production.
- Document everything: Log commands run, error messages, and fixes for future reference.
- Monitor proactively: Use tools like Prometheus to set alerts for common issues (e.g., high pod restarts, OOM kills).
- Version control manifests: Store YAML files in Git to track changes and roll back quickly.
- Understand the architecture: Learn how components (pods, services, CNI, CSI) interact to diagnose root causes faster.
5. Conclusion
Kubernetes troubleshooting can be challenging, but with a systematic approach, the right tools, and an understanding of common issues, you can resolve problems efficiently. Start with the pod level, check events and logs, and validate dependencies to isolate root causes. Remember: Kubernetes is a distributed system—issues rarely exist in isolation, so always consider the bigger picture!