Few status messages in cloud computing inspire as much dread as CrashLoopBackOff. You commit your code, the CI/CD pipeline turns green, and your pods deploy—only for kubectl get pods to reveal an ever-increasing restart count and a status that refuses to stay Running.
The name describes exactly what is happening under the hood: your container starts, immediately crashes, and Kubernetes backs off exponentially before attempting to restart it again.
Because the container is caught in a cycle of crashing and waiting, inspecting it using standard tooling often results in empty screens and dead ends. This guide provides a step-by-step diagnostic framework using kubectl logs and kubectl describe to quickly pinpoint and resolve the root cause of any CrashLoopBackOff.
1. Why kubectl logs Fails by Default
The most common mistake engineers make when troubleshooting a CrashLoopBackOff is running:
Bash
kubectl logs <pod-name>
More often than not, this command returns nothing at all or outputs a single generic startup line.
Why Does This Happen?
When a pod is in CrashLoopBackOff, Kubernetes is waiting out an exponential back-off delay (10s, 20s, 40s, up to 5 minutes) before spinning up a replacement container. If you run kubectl logs during this delay or right as a new container is instantiated:
The container that actually threw the fatal exception has already been terminated.
The new container has not written anything to
stdoutorstderryet.
By default, kubectl logs only displays the output of the currently running instance of a container. To find out why your application crashed, you must query the instance that preceded it.
2. Step 1: Inspect the Previous Container Instance
The single most critical flag in your debugging toolkit is --previous (or -p):
Bash
kubectl logs <pod-name> --previous
What It Does
The --previous flag instructs the container runtime (containerd/CRI-O) to pull the termination logs from the last crashed container instance before Kubernetes attempted to restart it.
What to Look For
Scroll to the very bottom of the output. In 80% of application-level bugs, this reveals the exact stack trace or fatal termination event:
Missing Environment Variables: A null pointer or runtime exception triggered because an expected secret or database connection string was omitted.
Database / Network Timeouts: The application attempts an immediate connection at boot and panics when downstream services do not answer within the timeout window.
Port / Permission Bind Failures: The containerized process attempts to bind to a privileged port (e.g., port 80) while running as a non-root security context.
Syntax / Entrypoint Errors: A malformed start script, missing dependency binary, or bad command passed in the
Dockerfile.
3. Step 2: Streaming Logs in Real Time
If your application takes a few seconds or minutes to boot before hitting a panic condition, catching the logs before the crash occurs can be challenging.
In this scenario, stream the standard output in real time using the -f (follow) flag:
Bash
kubectl logs -f <pod-name>
This keeps the session attached to stdout/stderr. As Kubernetes triggers the next restart, you will see the runtime initialization logs stream in line by line until the crash terminates the process.
(Press Ctrl + C to detach from the log stream.)
4. Multi-Container Pod Considerations
If your pod architecture includes sidecars (such as Envoy, Istio proxies, or log shippers), a generic kubectl logs command will fail with an error like:
Join the conversation! Your thoughts help the community grow.