Illustrative engineer using a laptop beside a Kubernetes container-restart teaching diagram.

WIUNIX ACADEMY

CrashLoopBackOff or OOMKilled? Diagnose the failed container before restarting it

Correlate previous logs, termination state, probes, resource limits and rollout history; choose a bounded recovery and prove it remains healthy.

Advanced35 min readUpdated
Make this guide yours

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Debian 12Reviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment7 editable values

THE OUTCOME

What will you have at the end?

Distinguish application exit, memory kill, failed probes and node pressure, then recover one owned Deployment with evidence.

Supported operating systems and versions

Documented Linux kubectl workflow for an existing Kubernetes cluster. No local crash, memory stress or production command execution is claimed. The current tutorial form accepts simple identifiers of at most32characters. This is a form limitation, not the Kubernetes resource-name limit. Never truncate or rename a live object to fit. For a longer existing resource/context name, follow this same diagnostic sequence in the operator-owned direct CLI/editor workflow with its exact original name; no silent default substitution.

Before you begin

  • Authorized Kubernetes context and a noncritical owned Deployment
  • kubectl supported for the server version; read access to Pod state/logs/events
  • Metrics access and historical application telemetry if available
  • The current tutorial form accepts simple identifiers of at most32characters. This is a form limitation, not the Kubernetes resource-name limit. Never truncate or rename a live object to fit. For a longer existing resource/context name, follow this same diagnostic sequence in the operator-owned direct CLI/editor workflow with its exact original name; no silent default substitution.
01

LET’S BUILD

Prepare the selected operator host

These are operator-host packages only. Review the transaction before approving; do not install tools inside application containers. The cluster, server and application binaries must already exist with owner-approved versions. Use Bash for the following panels. Package installation changes this selected host but starts no new application server.

Use an existing Linux kubectl within one minor version of every API-server version; inspect the actual server version in the authorized context before proceeding. Do not install kubelet/kubeadm or overwrite cluster client repositories for this diagnosis.

bash

Selected operator host; approved package transaction

sudo apt-get update
sudo apt-get install --no-install-recommends ca-certificates curl bash coreutils
cat /etc/os-release
command -v bash curl timeout
command -v kubectl
kubectl version --client --output=yaml
How do I know it worked?

The OS/version matches the selection, required tools resolve, and existing application/client versions satisfy the stated compatibility boundary. Stop if a binary is missing or incompatible.

Preserve host security and existing paths

Ubuntu/Debian may use AppArmor and host firewall rules. This workflow opens no inbound host port and changes no security profile. For denied file/network access, inspect the owning service logs and policy with its administrator. Keep existing executable/config paths; public path fields are reviewed example locations, not discovered installation paths.

Define what the status does and does not mean

CrashLoopBackOff is a waiting/backoff condition following repeated container failures; it is not the root cause or a Pod phase. OOMKilled is a termination reason. A Pod may remain Running while a container restarts. Inspect the correct container, including init containers and sidecars, before drawing conclusions.

Use an existing noncritical Deployment whose owner can approve a rollout. This guide does not create crashes, raise limits automatically or delete a Pod to make a counter disappear. Keep timestamps, revision, container name and a short private incident record. Logs may contain user data or secrets: review locally and redact before sharing.

02

LET’S BUILD

Confirm context, namespace and permission

Every panel pins the configured context explicitly. Check the server and namespace against your change record; a familiar Pod name is not sufficient. The public fields stay only in this browser tab and must never contain credentials.

bash

Operator terminal; authorized lab context

kubectl config get-contexts 'lab'
kubectl --context='lab' get namespace 'academy-lab'
kubectl --context='lab' auth can-i get pods -n 'academy-lab'
kubectl --context='lab' -n 'academy-lab' get pod 'api-example' -o wide
How do I know it worked?

The intended server/context and Pod appear; permission is yes. Stop on any mismatch.

03

LET’S BUILD

Capture container state before another restart

Read state and lastState for the selected name, not just the STATUS column. An exit code of 137 can arise from SIGKILL and alone does not prove the container limit caused an OOM. Look for OOMKilled plus limits, node evidence and the timeline. A restart can overwrite the single previous instance available through the log API.

bash

Operator terminal; authorized lab context

kubectl --context='lab' -n 'academy-lab' get pod 'api-example' -o jsonpath='{range .status.containerStatuses[*]}{.name}{"\nstate="}{.state}{"\nlastState="}{.lastState}{"\nrestarts="}{.restartCount}{"\n\n"}{end}'
kubectl --context='lab' -n 'academy-lab' describe pod 'api-example'
kubectl --context='lab' -n 'academy-lab' get pod 'api-example' -o jsonpath='{range .status.initContainerStatuses[*]}{.name}{"\nstate="}{.state}{"\nlastState="}{.lastState}{"\nrestarts="}{.restartCount}{"\n"}{end}'
How do I know it worked?

Identify the selected container, reason, exit code, started/finished times and relevant events.

04

LET’S BUILD

Compare current and previous logs

Retrieve a bounded timestamped tail. --previous requests the previous terminated container instance, not all historical logs. If it is unavailable, use the authorized central log store; do not infer that no error occurred. Correlate the final error with termination time and rollout timing.

bash

Operator terminal; authorized lab context

kubectl --context='lab' -n 'academy-lab' logs 'api-example' -c 'app' --previous --timestamps --tail=200
kubectl --context='lab' -n 'academy-lab' logs 'api-example' -c 'app' --timestamps --tail=200
How do I know it worked?

Separate an application startup/exception failure from a process killed without its own shutdown message.

Explore all tutorials ↗