skip to content

Name the states a Docker container can be in and describe what moves it between them, including what the `dead` state means.

level: middleimportance: must knowfreq 52%

answer

  1. created / running / paused / restarting / removing / exited / dead
  2. exited ≠ removed — rm frees the writable layer
  3. pause = freezer cgroup, no signal, memory kept
  4. dead = teardown failed, needs rm -f
  5. inspect .State.Status; docker events for transitions

basics

~20 s

created, running, paused, restarting, removing, exited, dead. run/start move created or exited to running; stop/kill or the process ending move running to exited; pause/unpause toggle paused; rm moves through removing to gone. dead means partial removal failed and the container is unusable.

solid answer

~50 s

Docker reports a container's status in `docker ps -a` and in `docker inspect -f '{{.State.Status}}'`. The states are: - **created** — configured by `docker create` but never executed. - **running** — the entrypoint process is alive. Entered via `docker run`/`docker start`/`docker unpause`/a restart-policy restart. - **paused** — all processes frozen by the kernel's freezer cgroup via `docker pause`; memory intact, nothing scheduled. `docker unpause` resumes. - **restarting** — the daemon is bringing it back up under its restart policy. - **removing** — `docker rm` is tearing it down. - **exited** — the main process ended (cleanly, by signal, or via `docker stop`/`kill`); the writable layer and the container object still exist, so it can be started again or inspected. - **dead** — removal or teardown partially failed, typically from a wedged mount or storage-driver error; the container cannot be started and usually needs `docker rm -f`. The practical points: exited is not the same as removed, and only `docker rm` reclaims the writable layer.

code

bash · 3 lines
bash
docker inspect -f '{{.State.Status}} {{.State.ExitCode}} {{.State.Error}}' api
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
docker events --filter container=api

go deeper

for a junior

List the states and the commands that move between them, and be clear that exited is not the same as removed.

for a middle

Add the mechanics — the freezer cgroup behind pause, restarting as a restart-policy artifact, dead as a failed teardown — and read state from docker inspect rather than the ps text.

for a senior

Use docker events and .State fields to diagnose fast flapping and stuck teardown, and know the recovery path for dead containers.

for a principal

Care about the operational consequences: disk reclamation policy for exited containers, alerting on containers stuck in restarting or dead, and keeping hosts free of manual state.

## Where the states live Docker exposes the state in two places. `docker ps -a` shows a human STATUS column ("Up 3 minutes", "Exited (137) 2 hours ago", "Created", "Paused"). The machine-readable truth is in `docker inspect`: ``` docker inspect -f '{{.State.Status}} {{.State.Running}} {{.State.ExitCode}} {{.State.StartedAt}} {{.State.FinishedAt}}' c ``` `.State.Status` is one of: `created`, `running`, `paused`, `restarting`, `removing`, `exited`, `dead`. ## The states **created** — the container object exists: writable layer allocated, configuration recorded (command, env, mounts, ports, network), but the entrypoint has never run. It occupies disk and a name. `docker ps` hides it; `docker ps -a` shows it. **running** — the entrypoint process is alive in its namespaces. Reached from `created` or `exited` via `docker start`, from `paused` via `docker unpause`, from `restarting` when the daemon restarts it, or directly via `docker run`. **paused** — every process in the container is frozen by the kernel freezer cgroup. Memory is retained, the processes are not scheduled, and no signal-based negotiation happened. `docker unpause` resumes exactly where things were. Note pausing is not a lifecycle event from the application's perspective — it never knows. **restarting** — a transient state while the daemon applies a restart policy after an exit. You will catch a crash-looping container here between attempts. **removing** — a transient state during `docker rm` while the writable layer, network endpoints and metadata are torn down. **exited** — the main process has terminated, for any reason: it returned from main, it was signalled by `docker stop`/`docker kill`, it crashed, or the kernel OOM-killed it. The container object survives: the writable layer, the logs, the configuration and the recorded exit code all remain, which is precisely what makes post-mortem work possible (`docker logs`, `docker inspect`, `docker cp` out of it). It can be started again with `docker start` — same filesystem, fresh process. **dead** — the odd one out. It is not a normal step in the lifecycle; it means the daemon tried to remove or tear down the container and could not complete the operation, usually because a resource is stuck: an unmountable filesystem, a busy mount point, a storage-driver or overlayfs error, or the daemon dying mid-removal. A dead container cannot be started. The remedy is `docker rm -f <id>`; if that also fails, the underlying mount or storage problem must be cleared first, sometimes with a daemon restart. ## Transitions worth memorizing ``` (image) --create--> created --start--> running --stop/kill/exit--> exited \--pause--> paused --unpause--> running exited --start--> running exited/created --rm--> removing --> (gone) running --restart policy--> restarting --> running any --failed teardown--> dead ``` `docker restart` is stop + start on the **same** container: same ID, same name, same writable layer, new process. It is not a replacement. ## Two distinctions candidates blur **exited vs removed.** An exited container still consumes disk for its writable layer and its logs, still holds its name (so `docker run --name api ...` will refuse to reuse it), and still shows in `docker ps -a`. Only `docker rm` frees all of that. Machines accumulating hundreds of exited containers is the most common form of "Docker ate my disk". **paused vs stopped.** Pausing freezes processes in place with memory intact and no signals involved; the application cannot react and does not know time passed. Stopping sends a signal, the process shuts down and its memory is released. Anything holding a network connection open across a pause will find peers timing out, because the clock keeps running even though the processes do not. ## Practical inspection ``` docker ps -a --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}' docker ps -a --filter status=exited --filter status=dead docker inspect -f '{{.State.Status}} {{.State.ExitCode}} {{.State.Error}}' c docker events --filter container=c ``` `docker events` is the underused one: it streams lifecycle transitions (create, start, die, stop, pause, unpause, destroy, oom) as they happen, which is how you catch a container that flips through states too fast for `docker ps` to show.

  • What is the practical difference between an exited container and a removed one?
    An exited container still exists as an object: its writable layer, logs, configuration and exit code are all retained, its name is still taken, and you can inspect it, copy files out of it, or start it again. A removed container is gone entirely and its writable layer's disk is reclaimed. That is why `docker ps -a` on a long-lived host often lists hundreds of exited containers quietly consuming space.
  • How does `docker restart` differ from removing a container and running a new one from the same image?
    `docker restart` stops and starts the *same* container object — same ID, same name, same configuration and, importantly, the same writable layer, so files written during the previous run are still present. Running a fresh container from the image gives a brand-new writable layer, so anything written outside a volume during the old run is gone.

saying these in an interview costs you the question

  • Treating exited as meaning the container no longer exists or consumes disk
  • Thinking `dead` just means "stopped" or "crashed"
  • Believing paused containers have been signalled or given a chance to shut down
  • Saying `docker restart` creates a new container from the image
  • Claiming `docker ps` shows all containers by default (it only shows running ones)

context