Troubleshooting (30%)
Notes on diagnosing and fixing cluster, node, and application failures. The single heaviest-weighted domain on the exam.
Topics
- Evaluate cluster and node logging
- Understand how to monitor applications
- Manage container stdout & stderr logs
- Troubleshoot application failure
- Troubleshoot cluster component failure
- Troubleshoot networking
Directory map
General method
- Scope it: one Pod, one node, one namespace, or the whole cluster?
- Read state:
kubectl get, thenkubectl describe(the Events section usually names the cause). - Read logs: container logs, then component/node logs.
- Form a hypothesis, change one thing, and verify.
- Work from the outside in: Pod, Service, Ingress, then node, kubelet, runtime, control plane.
If kubectl itself fails, the problem is the API server, its kubeconfig, or the network to it. Fall back to the node: crictl, journalctl, and the static Pod manifests.
Cluster and node logging
Where logs live:
| Component | Location (kubeadm cluster) |
|---|---|
| kubelet | systemd unit: journalctl -u kubelet |
| containerd | journalctl -u containerd |
| Control-plane Pods (apiserver, etcd, scheduler, controller-manager) | kubectl -n kube-system logs <pod>; if API is down, crictl logs <id> or files in /var/log/pods/ and /var/log/containers/ |
| Container logs | /var/log/pods/<ns>_<pod>_<uid>/<container>/N.log, symlinked in /var/log/containers/ |
| System | journalctl, /var/log/syslog or /var/log/messages, dmesg |
journalctl -u kubelet -f
journalctl -u kubelet --since "10 min ago" --no-pager | tail -100
journalctl -u kubelet | grep -i -E "error|failed"
systemctl status kubelet containerd
dmesg | tail
Kubernetes does not ship a cluster-wide logging backend. The standard pattern is a node-level agent (Fluent Bit, Fluentd, Vector, Promtail) running as a DaemonSet that ships /var/log contents to a store such as Elasticsearch, Loki, or a cloud service. Node log rotation is handled by the kubelet (containerLogMaxSize, containerLogMaxFiles).
See Logging.
Monitoring applications
See Monitoring. Summary:
- metrics-server provides the resource metrics API for
kubectl topand HPA. It is in-memory only, not a monitoring system. - Full monitoring is third party (Prometheus plus Grafana, Datadog, and so on).
- Probes (liveness, readiness, startup) are the in-cluster health signals.
kubectl top node
kubectl top pod -A --sort-by=memory
kubectl top pod --containers
kubectl get events -A --sort-by=.lastTimestamp
kubectl get --raw /readyz?verbose
kubectl get --raw /healthz
If kubectl top fails with “Metrics API not available”, metrics-server is missing or unhealthy (on lab clusters it often needs --kubelet-insecure-tls).
Container stdout and stderr logs
The container runtime captures anything a container writes to stdout and stderr; kubectl logs reads that. Logs written to files inside the container are not captured, so use a sidecar to tail them to stdout (see Sidecars).
kubectl logs <pod>
kubectl logs <pod> -c <container> # multi-container Pod
kubectl logs <pod> --all-containers
kubectl logs <pod> --previous # last crashed instance (CrashLoopBackOff)
kubectl logs <pod> -f --tail=50
kubectl logs <pod> --since=15m
kubectl logs <pod> --timestamps
kubectl logs -l app=web --prefix --max-log-requests=10 # by label
kubectl logs deployment/web
kubectl logs <pod> -n <ns>
Logs of a Pod that was deleted are gone from kubectl; check the node under /var/log/pods if it still exists. Static control-plane Pods without a working API: crictl ps -a then crictl logs <id>.
Troubleshooting application failure
Start with kubectl get pods and read the STATUS column.
| Status | Meaning and first checks |
|---|---|
Pending | Not scheduled. describe events: insufficient CPU/memory, taints with no toleration, nodeSelector/affinity mismatch, unbound PVC, no nodes Ready |
ContainerCreating | Image pulling, volume mount, or CNI problem. Check events for FailedMount, FailedCreatePodSandBox |
ImagePullBackOff / ErrImagePull | Wrong image name or tag, private registry without imagePullSecrets, no network to registry |
CrashLoopBackOff | App exits repeatedly. kubectl logs --previous, check command/args, config, env, missing Secret or ConfigMap, failing liveness probe |
CreateContainerConfigError | Missing ConfigMap or Secret or key referenced |
OOMKilled (in describe, last state) | Memory limit too low; raise the limit or fix the leak |
Error / Completed | Container exited; check exit code (1 app error, 137 SIGKILL/OOM, 139 segfault, 143 SIGTERM) |
Running but not working | Readiness failing (no endpoints), wrong Service selector/port, app bug, NetworkPolicy |
Terminating (stuck) | Finalizers or an unreachable node; kubectl delete pod <p> --force --grace-period=0 as a last resort |
Evicted | Node pressure (disk, memory); check describe node |
kubectl get pods -o wide
kubectl describe pod <pod>
kubectl logs <pod> [--previous]
kubectl get events --field-selector involvedObject.name=<pod>
kubectl get pod <pod> -o yaml | less
kubectl exec -it <pod> -- sh
kubectl debug -it <pod> --image=busybox:1.36 --target=<container> # ephemeral container
kubectl debug node/<node> -it --image=busybox:1.36 # node shell (host fs at /host)
kubectl rollout status deployment/<d>
kubectl rollout undo deployment/<d>
kubectl get deploy,rs,pods -l app=<label>
For Deployments: if a rollout stalls, rollout status, then inspect the new ReplicaSet’s Pods. A wrong selector or labels mismatch means no Pods are managed or no Service endpoints exist.
Troubleshooting cluster component failure
Node NotReady
kubectl get nodes
kubectl describe node <node> # Conditions: Ready, MemoryPressure, DiskPressure, PIDPressure; Events
Then on the node:
systemctl status kubelet
journalctl -u kubelet -n 100 --no-pager
systemctl status containerd
crictl ps -a
df -h; free -m
swapon --show # swap on makes kubelet fail by default
Common causes and fixes:
- kubelet stopped or crashing:
systemctl enable --now kubelet; read its journal. - Bad kubelet config: check
/var/lib/kubelet/config.yamland/etc/systemd/system/kubelet.service.d/10-kubeadm.conf; the kubelet’s kubeconfig/etc/kubernetes/kubelet.conf(wrong server address or expired certificate). - Container runtime down or wrong CRI socket path.
- CNI not installed or broken: node
NotReadywith “network plugin not ready”. - Expired certificates:
kubeadm certs check-expirationthenkubeadm certs renew alland restart the control-plane static Pods. - Disk, memory, or PID pressure: free space, evict, or resize.
Control-plane failure
Symptoms: kubectl times out or refuses connection (apiserver/etcd), Pods never get scheduled (scheduler), Deployments do not create Pods or nodes are not marked NotReady (controller-manager).
kubectl -n kube-system get pods
ls /etc/kubernetes/manifests
crictl ps -a | grep -E "kube-apiserver|etcd|scheduler|controller"
crictl logs <container-id>
journalctl -u kubelet | grep -i -E "static|manifest|apiserver"
cat /etc/kubernetes/manifests/kube-apiserver.yaml
Checklist per component:
- Manifest typos: a wrong flag, wrong image, wrong path in a hostPath volume, or YAML error in
/etc/kubernetes/manifests/*.yamlmakes the static Pod fail. Compare with the other manifests and fix the file; the kubelet re-creates the Pod within seconds. - kube-apiserver: check
--etcd-serversURL and cert paths,--client-ca-file, port 6443, and etcd health. - etcd: data dir, cert paths, peer/client URLs, disk space;
etcdctl endpoint healthwith the cert flags. - kube-scheduler:
--kubeconfigpath (/etc/kubernetes/scheduler.conf), leader election; Pods stayPendingwith no events when it is down. - kube-controller-manager:
--kubeconfig,--cluster-signing-*file paths,--root-ca-file. - kube-proxy: a DaemonSet; check its ConfigMap and logs if Services do not work.
- kubeconfig problems:
kubectl config view, correct server address,KUBECONFIGenv var, expired client certs.
If a component is a systemd service (non-kubeadm clusters): systemctl status kube-apiserver, journalctl -u kube-apiserver.
Troubleshooting networking
Work in layers:
- Pod networking: do Pods get IPs?
kubectl get pods -o wide.ContainerCreatingwithFailedCreatePodSandBoxmeans a CNI issue. Check the CNI Pods inkube-system,/etc/cni/net.d,/opt/cni/bin, and that the Pod CIDR matches the CNI config. - Pod to Pod:
kubectl execand curl/ping the other Pod IP. Failing across nodes only suggests CNI overlay or firewall problem between nodes (VXLAN UDP 4789, IP-in-IP protocol 4, BGP 179). - DNS: from a Pod,
nslookup kubernetes.default. Check CoreDNS Pods and logs, thekube-dnsService and endpoints, and/etc/resolv.confin the Pod. Check that NetworkPolicies are not blocking port 53. - Service:
kubectl get endpoints <svc>. Empty endpoints means selector or readiness problem. WrongtargetPort. Test the ClusterIP directly, then the DNS name. Check kube-proxy Pods/logs and iptables/IPVS rules. - NetworkPolicy:
kubectl get netpol -n <ns>; temporarily review for default-deny rules; remember policies are additive and AND/OR selector semantics. - Ingress / external: Ingress controller Pods running, Ingress class and host/path correct, backend Service has endpoints, controller Service has an external address, TLS Secret exists.
- Node:
ip route,iptables-save | grep <svc>,sysctl net.ipv4.ip_forward, firewall rules.
kubectl run net --rm -it --image=nicolaka/netshoot --restart=Never -- bash
# inside: dig web.default.svc.cluster.local ; curl -v http://web ; traceroute <ip> ; nc -zv <host> <port>
kubectl get svc,endpoints -n <ns>
kubectl -n kube-system get pods -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns
kubectl -n kube-system get pods -l k8s-app=kube-proxy
kubectl -n kube-system logs -l k8s-app=kube-proxy
kubectl get ingress,netpol -A
Cheat sheet
# Fast triage
kubectl get nodes
kubectl get pods -A | grep -v Running
kubectl get events -A --sort-by=.lastTimestamp | tail -30
kubectl describe <kind> <name>
kubectl logs <pod> [-c c] [--previous]
kubectl top node; kubectl top pod
# Node side
systemctl status|restart kubelet containerd
journalctl -u kubelet -f
crictl ps -a ; crictl logs <id> ; crictl images ; crictl pods
ls /etc/kubernetes/manifests
kubeadm certs check-expiration
# Output shaping
kubectl get pod <p> -o jsonpath='{.status.containerStatuses[*].lastState}'
kubectl get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName,STATUS:.status.phase
kubectl get pods --field-selector=status.phase!=Running -A
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.conditions[-1].type}{"\n"}{end}'
Exam tips:
- Read the task’s namespace and context first.
describebefore anything else; the Events at the bottom answer most questions.- For broken control-plane components fix the static Pod manifest, then confirm with
kubectl get pods -n kube-system. - Use
crictlwhen kubectl is unavailable;sudo -ifor node work andexitback out.