Skip to content
EgyKode
11 · Operating itLab 52 / 59
Incidentkubernetes

Incident: CrashLoopBackOff

A container starts, dies, and restarts forever. The current logs are empty. Find out what the one that died said.

Time
35 min
Level
Advanced
Objectives
3 objectives
Cost
Free

Where this fits in the platform

This lab adds

  • A pod diagnosed from its own evidence

Which lets you

Before you start

You will need

  • kind or minikube
  • kubectl 1.28+

You do not need these already — the lab environment below provides them.

You will be able to

  • Read the logs of a container that has already exited
  • Map an exit code to a cause
  • Separate a crash from a failing health check

CostFree

— runs on kind or minikube.

Nothing to pay in the browser. Open the terminal runs this against a simulated cloud — the same API calls and the same commands, with no account and no bill. The figure above applies only if you build it in your own.

The incident#

A Pod has restarted 14 times in six minutes and sits in CrashLoopBackOff. kubectl logs prints nothing.

Find out why, and fix it.

Hands-on environment

Run this lab in a real terminal, free and in your browser. The environment is temporary and yours alone — break it as much as you like.

Start the challenge

Opens in Killercoda, in a new tab — keep this page open for the steps.

Run it on your own machine

Run this lab on your own machine. One command starts the environment, with everything the lab needs already installed:

You will need:

  • docker
  • kubectl
  • kind
git clone https://github.com/EgyKode/EgyKode-lab.git
cd EgyKode-lab
./egykode start k8s
./egykode shell

You need Docker and Git installed. Everything else runs inside the environment. The first start downloads it and takes a few minutes; later starts are seconds.

Not sure what you already have? Run: npm run doctor — it checks and changes nothing.

Anything you tick here is your own record. EgyKode cannot see inside that terminal, so the success criteria stay self-assessed even when the environment checks your work for you.

Reproduce it

Step 1 of 9

Reproduce it#

Terminal
kubectl create namespace incident-02
kubectl apply -n incident-02 -f https://raw.githubusercontent.com/EgyKode/EgyKode-Academy/master/content/labs/fixtures/incident-02.yaml

By hand: deploy any image whose entrypoint reads a required environment variable that is not set, and let it exit non-zero.

What CrashLoopBackOff actually means#

It is not an error in itself. It means the container exited, Kubernetes restarted it, it exited again, and the kubelet is now backing off — waiting longer between attempts (10s, 20s, 40s…) so a broken container cannot spin the node.

The useful information is in the container that already died.

The one command people miss#

Terminal
kubectl -n incident-02 logs <pod>              # the container that just started
kubectl -n incident-02 logs <pod> --previous   # the one that died

--previous is the whole lab. The current container has been alive for two seconds and knows nothing; the evidence is in its predecessor.

Then the exit code#

Terminal
kubectl -n incident-02 describe pod <pod>

Look at Last State: Terminated and its Exit Code:

Exit codeMeansLook at
0Exited cleanlyA one-shot command in a Deployment — it needs to be a Job
1Application errorThe previous logs
2Shell misuseThe command or args in the manifest
126 / 127Not executable / not foundThe entrypoint path
137SIGKILL — almost always OOMKilledMemory limit versus what it needs
143SIGTERM — asked to stopSomething else is terminating it

137 is the one worth recognising instantly: the container exceeded its memory limit and the kernel's OOM killer terminated it. describe says OOMKilled explicitly in Last State.

This is the cgroup limit you met in Linux and set with --memory in Docker — Kubernetes declares it in resources.limits, and the kernel enforces it. Same mechanism, three names. Which is why the evidence is also on the node: dmesg -T | grep -i oom shows the kill from the kernel's side, and it is worth looking at once so the chain stops being abstract.

Rule out the probes#

A container that is running fine but failing its liveness probe restarts in a loop that looks identical from the outside:

Terminal
kubectl -n incident-02 describe pod <pod> | grep -A5 Liveness
kubectl -n incident-02 get events --sort-by=.lastTimestamp | tail -20

An event saying Liveness probe failed means the application is alive and the check is wrong — often a slow-starting process with no startupProbe, being killed before it ever finishes booting.

Before you change anything#

Finish this sentence: "The container exits because ___, which I know from ___."

The second half matters as much as the first.

The candidates#

  1. A required environment variable or config file is missing, so the process exits at startup.
  2. A referenced ConfigMap or Secret does not exist — the Pod never starts and describe says so in Events.
  3. The memory limit is below what the process needs — exit 137, OOMKilled.
  4. The command or args are wrong — exit 127.
  5. It is a one-shot task in a Deployment: it succeeds, exits 0, and gets restarted because a Deployment expects a long-running process.
  6. A liveness probe is killing a healthy but slow-starting container.

Check your reasoning#

Read this after you have fixed it, or after a genuine attempt. Being handed the answer costs you the only thing this tier teaches.

Root cause: the container requires an environment variable that the manifest never sets. It exits 1 at startup, before writing anything to the log the current container would show.

The command that found it: kubectl logs <pod> --previous — the dead container's output names the missing variable directly.

The fix: add the variable via env or envFrom. If it belongs in a ConfigMap, note that editing that ConfigMap later will not restart the Pod — envFrom values are read once at container start.

Why kubectl logs alone showed nothing: by the time you ran it, the kubelet had already started a replacement that had not reached the failure yet, or had produced no output at all.

Clean up#

DestructiveThis removes real resources. Check which environment you are in first.

Terminal
kubectl delete namespace incident-cr

Success criteria

0 of 3

The concept behind it

Next up

Lab 52 of 59 on the project path

Incident: 502 Bad GatewayThe site returns 502. You have cluster access and no explanation. Work the path from the edge inwards.40 minAdvanced

Previous: Centralised Logging with Loki and Grafana