CertGrid CertGrid

Kubernetes troubleshooting cheat sheet

Organised by symptom, not by command. Each row is what you actually saw, what it means, and the one command that confirms it. Start with the sweep at the top.

The sweep: run this first

  • kubectl get nodes

    Nothing runs on a node that is not Ready. Ten seconds, and it rules out a whole class of cause.

    Also read the version column: a node left behind by a partial upgrade explains behaviour that differs by node.

    Full guide
  • kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded

    Every Pod in the cluster that is neither working nor finished. Scales to thousands.

    Reads current state, so unlike events it is not subject to the one-hour TTL.

    Full guide
  • kubectl get events -A --field-selector type=Warning --sort-by=.lastTimestamp

    Every warning in the cluster, in order. Finds problems in namespaces you were not thinking about.

    Events expire after an hour by default, so an absence of warnings is not evidence of health.

    Full guide
  • kubectl get --raw='/livez?verbose'

    API server health per subsystem. A failing check is marked with a minus and names the subsystem.

    componentstatuses is deprecated and reports nothing useful. Use this and the kube-system Pod list instead.

    Full guide
  • kubectl get pods -n kube-system

    The control plane and add-ons. A CoreDNS Pod not Ready explains every resolution failure at once.

    Watch restart counts: a number that is climbing is much worse than a high number that has not moved in days.

    Full guide

Pod will not start

  • Pending, no node assigned

    The scheduler could not place it. The FailedScheduling event accounts for every node and says why each was rejected.

    `Insufficient cpu` is about requests, not usage. A node idle in kubectl top can be fully booked.

    Full guide
  • kubectl describe node <name> | sed -n '/Allocated resources/,/Events/p'

    The requests already committed on a node, which is what the scheduler is actually looking at.

    Full guide
  • Pending, and the PVC is Pending too

    A Pod does not schedule until its PVCs bind. The storage is the cause and the Pod is the symptom.

    kubectl describe pvc names the reason, usually a StorageClass that does not exist.

    Full guide
  • ContainerCreating with a CNI error

    The kubelet cannot set up the network. The CNI is not installed or not running on that node.

    On the node: sudo ls /etc/cni/net.d. Empty means the CNI DaemonSet has not run there.

    Full guide
  • ImagePullBackOff / ErrImagePull

    The image could not be pulled. The event message distinguishes not-found from unauthorized from a network failure.

    Read the whole message. `not found` is a name or tag error; `unauthorized` needs an imagePullSecret.

    Full guide
  • kubectl get events --field-selector type=Warning -n <ns>

    The warnings for one namespace, which is where the scheduler's and kubelet's reasons are.

    Full guide

Pod starts and dies

  • CrashLoopBackOff

    The container exits and the kubelet keeps restarting it with growing backoff.

    A report, not an attempt at repair. Kubernetes cannot fix why your process exits.

    Full guide
  • kubectl logs <pod> --previous

    The previous run's output, which is where the cause is. The current run may show nothing.

    The single most useful flag in Kubernetes troubleshooting.

    Full guide
  • kubectl get pod <pod> -o jsonpath='{.status.containerStatuses[0].lastState.terminated}'

    Exit code, reason and signal from the previous run.

    Exit 137 is SIGKILL, usually an OOM kill. Exit 1 is the application. Exit 127 is a command not found in the image.

    Full guide
  • OOMKilled

    The container exceeded its memory limit and was terminated by the kernel.

    Memory is not compressible, so a limit is enforced by killing. Compare limits against kubectl top pods --containers.

    Full guide
  • Running but never Ready

    A failing readiness probe. The container is up and the Service will not send it traffic.

    Readiness removes from endpoints; liveness restarts. Describe shows the probe failures with their HTTP codes.

    Full guide
  • Restarting shortly after start, every time

    A liveness probe firing before the application has finished starting.

    The fix is a startupProbe, not a longer liveness period, which would also delay real failure detection.

    Full guide
  • Init:Error or Init:CrashLoopBackOff

    An init container is failing, so the app containers never start.

    kubectl logs <pod> -c <init-container>. The app container's logs are empty because it has not run.

    Full guide

It is running and unreachable

  • kubectl get endpointslice -l kubernetes.io/service-name=<svc>

    The addresses behind a Service. Empty is the most common cause of a Service that does not work.

    Empty means selector mismatch, failing readiness, or Pods Pending. Populated means look further along the path.

    Full guide
  • Timed out versus connection refused

    Timeout means packets dropped, so a policy or firewall. Refused means routing worked and nothing is listening.

    They point in opposite directions and are the fastest way to halve the search space.

    Full guide
  • wget: bad address <name>

    DNS failed before any connection was attempted.

    Under an egress NetworkPolicy this means port 53 to kube-system is not allowed. Otherwise check CoreDNS.

    Full guide
  • kubectl exec <pod> -- cat /etc/resolv.conf

    What the Pod was told to use for DNS, including the search domains.

    Full guide
  • kubectl get netpol -A

    Whether any policy could be involved. Check both the source and destination namespaces.

    Also check the CNI's own policy resources; kubectl get netpol shows only networking.k8s.io objects.

    Full guide
  • kubectl port-forward svc/<name> 8080:80

    Reach the backend bypassing Ingress, Services' external path and NetworkPolicy.

    Working here and failing normally localises the problem to the path, not the application.

    Full guide
  • kubectl logs -n ingress-nginx deploy/ingress-nginx-controller --tail=50

    The access log. A request missing from it never reached the controller.

    That absence moves the search in front of the controller: DNS, the load balancer, the node port, or the client.

    Full guide

Node problems

  • kubectl describe node <name> | grep -A6 '^Conditions:'

    The conditions behind the word Ready.

    For DiskPressure, MemoryPressure, PIDPressure and NetworkUnavailable, False is healthy. Only Ready inverts.

    Full guide
  • NetworkUnavailable=True

    The CNI has not initialised on that node. Pods schedule there and never get an IP.

    The condition most often mistaken for a Service or DNS problem.

    Full guide
  • DiskPressure=True

    The kubelet is evicting Pods and refusing new ones.

    Usually image or log accumulation. The symptom is Pods vanishing with no obvious cause.

    Full guide
  • LastHeartbeatTime minutes old, still Ready

    The node has stopped reporting and the controller manager has not flipped it yet.

    It flips after node-monitor-grace-period, so a node can be genuinely gone and still read Ready for a short window.

    Full guide
  • sudo journalctl -u kubelet -n 50 --no-pager

    The kubelet's log. Where node-level failures are actually explained.

    Run this before anything else on a NotReady node. Config errors, cgroup driver mismatches and CNI failures all surface here.

    Full guide
  • sudo systemctl status kubelet

    Whether it is running at all, and the exit status if not.

    A kubelet that will not start with swap enabled, or with a cgroup driver that disagrees with the runtime, is the usual pair.

    Full guide

Control plane and etcd

  • kubectl times out or is refused

    The API server is unreachable, so none of the kubectl-based checks apply.

    Switch to the node: sudo crictl ps, sudo journalctl -u kubelet, and the container logs. Also check your kubeconfig points where you think.

    Full guide
  • sudo crictl ps -a --name kube-apiserver

    Whether the API server container exists and how many times it has exited.

    Full guide
  • sudo crictl logs <container-id>

    A static Pod's logs without the API server. Often the only way to read why it will not start.

    Full guide
  • Forbidden for a cluster-admin identity that has always worked

    etcd has lost quorum, so the API server cannot read the RBAC objects that would authorise you.

    The most misleading symptom in the control plane. Check etcd before reading a single ClusterRoleBinding.

    Full guide
  • Unauthorized, or 'the server has asked for the client to provide credentials'

    The client certificate was rejected in the TLS handshake, most often expired.

    Forbidden means authentication worked and permission did not. Unauthorized means it never got that far.

    Full guide
  • sudo etcdctl ... endpoint health --cluster

    Ask every etcd member whether it can commit a proposal.

    `Error: unhealthy cluster` means at least one member is unhealthy. Two healthy of three is a working cluster; read the per-endpoint lines.

    Full guide
  • 'agreement among raft nodes before linearized reading' in etcd's log

    The signature of a member that cannot reach quorum.

    Search for this phrase. It is the definitive confirmation of quorum loss.

    Full guide
  • sudo kubeadm certs check-expiration

    Every certificate's expiry. Works without a functioning API server.

    Leaf certificates last one year. A cluster built and never upgraded stops working on its first birthday.

    Full guide

Rollouts, RBAC and storage

  • Rollout stuck while Available=True

    The rolling update kept old Pods serving, so the Deployment is available and the new ReplicaSet is failing.

    Do not check Available alone. Watch for Progressing=False with reason ProgressDeadlineExceeded.

    Full guide
  • kubectl get rs -n <ns>

    Two ReplicaSets, the new one at 0 ready, is a stalled rollout visible sooner than the condition.

    Full guide
  • A ConfigMap change had no effect

    Environment variables are read once at container start, and nothing in the Pod template changed.

    kubectl rollout restart, or use a generated ConfigMap whose name carries a content hash so the change is a template change.

    Full guide
  • Forbidden, with the user and resource named

    Authentication worked; RBAC denied. This is the genuine permissions error.

    kubectl auth can-i --list -n <ns> as the affected identity is faster than reading bindings. A new CRD is not covered by existing roles.

    Full guide
  • kubectl auth can-i <verb> <resource> --as=system:serviceaccount:<ns>:<sa>

    Test another identity's permissions without becoming it.

    Full guide
  • PVC Pending

    No provisioner answered. Usually a StorageClass that does not exist, or WaitForFirstConsumer with no Pod yet.

    The visible symptom is often an unschedulable Pod, one step removed from the cause.

    Full guide
  • volume node affinity conflict

    The PV carries node or zone affinity and no suitable node is available.

    For new volumes, volumeBindingMode: WaitForFirstConsumer lets the scheduler choose first and avoids it.

    Full guide
  • PVC expanded and the application still sees the old size

    FileSystemResizePending. The volume grew and the filesystem has not.

    Restart the Pod. Most drivers can only resize a filesystem while the volume is unmounted.

    Full guide
  • Namespace or PVC stuck Terminating Caution

    A finalizer is waiting for a controller that may no longer exist.

    Clearing finalizers by hand skips whatever external cleanup they existed to do, so check for orphaned resources afterwards.

    Full guide