Docker Course
Docker Lifecycle
Every container has a life — it's created, it runs, it stops, and eventually it's removed. Knowing exactly what happens at each stage, and which command drives each transition, is what separates someone who uses Docker from someone who understands it.
This lesson walks the complete lifecycle of a container from first creation to final deletion — using a real scenario at every step. By the end, every command you've learned in Section I fits together into one coherent mental model.
The Full Lifecycle at a Glance
A container's life has six distinct phases. Each phase is triggered by a specific command or event. Understanding the transitions is just as important as understanding the states themselves.
Container lifecycle — full flow
Phase 1 — Pull
The image is downloaded from the Registry to the local cache. Triggered by docker pull or automatically by docker run if the image isn't cached locally.
Phase 2 — Create
The Daemon creates a container from the image — sets up the writable layer, networking, and filesystem — but does not start the process yet. Triggered by docker create.
Phase 3 — Running
The main process starts inside the container. Triggered by docker start on a created container, or by docker run which combines phases 1–3 into one command.
Phase 4 — Paused or Stopped
docker pause freezes the process in memory — it's suspended but not killed. docker stop sends SIGTERM then SIGKILL, gracefully ending the process. The container and its writable layer still exist.
Phase 5 — Exited
The container's main process finished on its own — either cleanly (exit code 0) or with an error (exit code non-zero). Visible in docker ps -a. Can be restarted with docker start.
Phase 6 — Deleted
The container is permanently removed with docker rm. The writable layer is wiped. The image it was created from remains untouched in the local cache.
docker run — The Shortcut That Does It All
The docker run command is the most-used command in Docker because it collapses phases 1 through 3 into a single instruction. Under the hood, docker run nginx is the Daemon doing three things in sequence: checking local cache and pulling the image if needed, creating the container, and immediately starting it.
The Vending Machine Analogy
A vending machine's full process is: check the inventory, retrieve the item, dispense it. You don't press three separate buttons — you press one and the machine handles the rest. docker run is that single button. Experienced engineers sometimes split the steps using docker create then docker start when they need fine-grained control — like pre-configuring a container before its first run. For everyday use, docker run covers everything.
Walking the Full Lifecycle — A Real Scenario
The scenario: You're a backend developer at a media platform. You need to spin up a Redis cache container for local development, run it through its paces, stop it for the weekend, restart it on Monday, and eventually clean it up when the feature ships and you no longer need it locally. Every phase of the lifecycle, in order.
# Phase 1+2+3 combined — pull, create, and start in one command
docker run -d --name redis-cache -p 6379:6379 redis:7-alpine
# redis:7-alpine → official Redis image, version 7, Alpine base (only 30 MB)
# -p 6379:6379 → expose Redis's default port to the host
# Verify it's running
docker ps
Unable to find image 'redis:7-alpine' locally 7-alpine: Pulling from library/redis 96526aa774ef: Pull complete 4b665dbf1c32: Pull complete Digest: sha256:4bed291aa5efb9f0d77b76ff7d4ab71eee410962965d052552db1fb80576431d Status: Downloaded newer image for redis:7-alpine CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c7d3e9f1a204 redis:7-alpine "docker-entrypoint.s…" 4 seconds ago Up 3 seconds 0.0.0.0:6379->6379/tcp redis-cache
What just happened?
Phases 1, 2, and 3 happened sequentially — Docker pulled the redis:7-alpine image layer by layer, created the container, and immediately started it. The docker ps output confirms the container is in the Running state — Up 3 seconds in the STATUS column. The port binding is visible: 0.0.0.0:6379->6379/tcp. Your application can now connect to Redis at localhost:6379.
# End of the week — stop the container (Phase 4)
docker stop redis-cache
# Sends SIGTERM to the Redis process, waits for graceful shutdown, then SIGKILL if needed
# Confirm it stopped
docker ps -a
# -a shows all containers including stopped ones
redis-cache CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c7d3e9f1a204 redis:7-alpine "docker-entrypoint.s…" 2 days ago Exited (0) 5 seconds ago redis-cache
What just happened?
The container moved from Running to Exited. Two things to notice in the output: the PORTS column is now empty — a stopped container doesn't hold port bindings. The STATUS shows Exited (0) — the exit code 0 means Redis shut down cleanly. If you saw Exited (1) or any non-zero code, that would indicate a crash or error. The container still exists — it didn't disappear — which is why docker ps -a shows it.
# Monday morning — restart the container (back to Phase 3)
docker start redis-cache
# Brings the same container back up with all its original settings intact
# Same name, same port mapping, same configuration — no need to re-type docker run
docker ps
redis-cache CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c7d3e9f1a204 redis:7-alpine "docker-entrypoint.s…" 5 days ago Up 2 seconds 0.0.0.0:6379->6379/tcp redis-cache
What just happened?
The container jumped straight back to Running from Exited. Notice the CONTAINER ID is the same — c7d3e9f1a204 — it's the exact same container, not a new one. docker start restores it with all its original settings. The port binding is back. The CREATED field still says 5 days ago — confirming this isn't a fresh container, it's the same one you created at the start of the week.
# Feature shipped — clean up completely (Phase 6)
docker stop redis-cache # stop first — can't remove a running container without -f
docker rm redis-cache # permanently delete the container and its writable layer
# Confirm it's gone
docker ps -a
# Optionally remove the image too if you no longer need it
docker rmi redis:7-alpine
redis-cache redis-cache CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES (no output — container list is empty) Untagged: redis:7-alpine Deleted: sha256:4bed291aa5efb9f0d77b76ff7d4ab71eee410962965d052552db1fb80576431d
What just happened?
The container moved through its final two transitions — Stopped then Deleted. The empty docker ps -a output confirms the container is completely gone. The docker rmi output shows two lines: Untagged removes the name reference, and Deleted removes the actual image data from disk. The full lifecycle completed — from pull to deletion — with every phase accounted for.
Restart Policies — Automating the Lifecycle
In production, you rarely manage the lifecycle manually. Instead you set a restart policy on the container — an instruction to the Daemon on what to do when the container exits.
Restart policy options
no
Default. Never restart automatically. Good for one-off tasks and development containers.
always
Always restart regardless of exit code. Also restarts when the Docker Daemon itself restarts (e.g. after a server reboot).
on-failure
Only restart if the container exited with a non-zero exit code. Ideal for batch jobs that should retry on crash but stop when successful.
unless-stopped
Like always, but doesn't restart if you manually stopped the container before the Daemon restarted. The most common production choice.
docker run -d \
--name redis-cache \
--restart unless-stopped \
-p 6379:6379 \
redis:7-alpine
# --restart unless-stopped → if the container crashes or the server reboots,
# Docker automatically brings it back up — unless you explicitly stopped it yourself
f9a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2
What just happened?
The container started with a unless-stopped restart policy baked in. Now if Redis crashes — say, due to an out-of-memory error — the Daemon will automatically restart it without any human intervention. If the server reboots, Docker starts up and brings this container back automatically. The only time it won't restart is if you explicitly ran docker stop redis-cache — because that signals intentional shutdown, not a crash.
Teacher's Note
--restart unless-stopped is the policy I put on every production container that needs to stay alive — it survives crashes and reboots without becoming impossible to stop when you actually need to.
Practice Questions
1. The single command that combines pulling an image, creating a container, and starting it in one step is called what?
2. The restart policy that automatically restarts a container after a crash or server reboot — but respects a manual docker stop — is called what?
3. In docker ps -a output, a STATUS of "Exited (0)" means the container's main process exited with code what — indicating a clean shutdown?
Quiz
1. A container's main process finishes on its own with exit code 0. What is the container's state afterwards?
2. What is the difference between docker start and docker run when used on an existing stopped container?
3. A batch processing container should retry automatically if it crashes, but should not restart after completing successfully. Which restart policy fits this requirement?
Up Next · Lesson 10
First Docker Hands-On
Nine lessons of concepts — now it's time to put it all together in a real hands-on exercise with a live terminal you can use right in your browser.