Skip to main content

Container Lifecycle

The sequence of states a Docker container moves through from creation to removal — created, running, paused, stopped, and dead — each triggered by specific Docker CLI commands or container exit events.

Container Lifecycle — Every State a Container Can Be In

What Is the Container Lifecycle in Simple Terms?

Every Docker container exists in exactly one state at any moment. Those states have names, and specific commands move a container from one state to another. Understanding this lifecycle is what lets you know the difference between a container that stopped because it finished its work (exit code 0) versus one that crashed (exit code 1) versus one that was killed (exit code 137).

Bash
docker create
|
v
+------------------------------------------+
| CREATED |
| Container created but process not started|
| docker ps -a shows it, docker ps does not|
+------------------------------------------+
|
docker start
|
v
+------------------------------------------+
| RUNNING |
| Container process is executing |
| docker ps shows it |
+------------------------------------------+
| | |
docker pause docker stop docker kill
| (SIGTERM) (SIGKILL)
v | |
+----------+ v v
| PAUSED | +------------------+ |
| Process | | STOPPED (EXITED) |<-+
| frozen | | Process finished |
| SIGSTOP | | docker ps -a shows|
+----------+ +------------------+
docker unpause |
| docker start
v | docker rm
RUNNING RUNNING | v
DELETED

All Five States Explained

Bash
# CREATED — exists but not started
docker create --name my-nginx nginx
docker ps # not shown (not running)
docker ps -a # shown with status Created
# RUNNING — process is executing
docker start my-nginx
docker ps # shown with status Up
# PAUSED — process is frozen (SIGSTOP)
docker pause my-nginx
docker ps # shown with status Up (Paused)
# Process is suspended — not using CPU
# Memory is preserved — instant resume
# STOPPED (EXITED) — process has ended
docker unpause my-nginx # resume from paused
docker stop my-nginx # send SIGTERM
docker ps # not shown
docker ps -a # shown with status Exited (0)
# DELETED — container no longer exists
docker rm my-nginx
docker ps -a # gone completely

Exit Codes — Why a Container Stopped

Bash
# See exit code of a stopped container
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
# NAMES STATUS
# api Exited (0) 2 minutes ago <- clean exit
# worker Exited (1) 5 minutes ago <- application error
# processor Exited (137) 1 minute ago <- OOMKilled or docker kill
# Decode exit codes:
# 0 = clean exit (batch job finished, intentional stop)
# 1 = generic application error
# 126 = cannot execute (permission denied)
# 127 = command not found
# 137 = SIGKILL (OOMKilled or docker kill)
# 143 = SIGTERM (docker stop or graceful shutdown)
# Check OOMKilled specifically
docker inspect api --format '{{.State.OOMKilled}}'
# true -> exceeded memory limit
# false -> some other cause

Restart Policies and Lifecycle

Bash
# Restart policies affect what happens after STOPPED state:
# no (default) — stays stopped
docker run --restart=no nginx
# Crashes -> stays in EXITED state
# on-failure — restart only on error exit code
docker run --restart=on-failure:5 payment-api
# Exits with code 0 -> stays EXITED
# Exits with code 1 -> restarts (up to 5 times)
# always — always restart
docker run --restart=always nginx
# Any exit -> restart (including clean exit)
# Survives daemon restart (starts on boot)
# unless-stopped — restart unless manually stopped
docker run --restart=unless-stopped trading-engine
# docker stop -> stays stopped (respects manual stop)
# Crash -> restarts
# Daemon restart -> restarts (starts on boot)

Complete Lifecycle Commands

Bash
# Full lifecycle from creation to deletion
docker create --name api nginx # CREATED
docker start api # RUNNING
docker pause api # PAUSED
docker unpause api # RUNNING
docker stop api # STOPPED
docker start api # RUNNING again
docker kill api # STOPPED (SIGKILL)
docker rm api # DELETED
# Shortcut: run = create + start
docker run -d --name api nginx # RUNNING directly
# Shortcut: rm -f = kill + rm
docker rm -f api # DELETED directly
Tip

Use docker events to watch container lifecycle events in real time. It shows every state transition with a timestamp — useful for understanding why a container keeps restarting or when exactly it crashed.

Remember

docker stop sends SIGTERM and waits 10 seconds for a clean exit before sending SIGKILL. docker kill sends SIGKILL immediately. Applications that handle SIGTERM (flush buffers, close connections, finish in-flight requests) need docker stop — not docker kill — to shut down cleanly.

Frequently Asked Questions

What's the practical difference between a stopped and a paused container?

A paused container (via `docker pause`) has all its processes frozen in place using the cgroup freezer — memory state, open connections, everything stays intact, just not executing, and `docker unpause` resumes instantly. A stopped container has had its main process terminated (via SIGTERM then SIGKILL after a grace period) — its filesystem changes persist, but application state is gone. Pausing is useful for temporarily freeing CPU without losing in-memory state; stopping is a real shutdown.

What's a common lifecycle-related mistake with container restarts?

Not setting an explicit restart policy (`--restart unless-stopped` or `on-failure`) and assuming Docker will bring a crashed container back automatically — by default it won't. Also common: relying on `docker rm` cleanup for stopped containers rather than periodically pruning, which lets dead containers accumulate and consume disk space from their writable layers indefinitely until someone notices the host running low on storage.