The core commands

run, ps, stop, rm, images.

Beginner12 min · lesson 5 of 16
In plain terms
Managing containers is like managing appliances in a room: switch one on (run), glance at what’s currently on (ps), switch it off (stop), and haul the dead one out (rm). A handful of switches covers almost everything.

There is a box of frozen lasagna in your freezer. The box never changes. Heat one up, slide it onto a plate, and that hot plate of food is a copy you can eat, bin, and make again tomorrow from the same box. Docker splits the world the same way. The box is an image: a frozen template holding your app and everything it needs to run. Docker calls an image read-only, which means you can start copies from it but you can never change the thing itself. The hot plate is a container: one running copy started from that image. A single image can feed many containers at once, each one running separately from the others. Five commands cover nearly everything you will ever do with the two of them, and they are worth wearing into reflexes. So follow one container through its whole life, from the second it starts to the moment you sweep it away.

Start one up

The command that starts a container is docker run. Hand it an image name and Docker takes it from there. The first time you ask for an image your machine has never seen, Docker fetches it from a registry, which is an online store for images. The default store is Docker Hub. The output labels that step 'Pulling', because pull is Docker's word for downloading an image. In the command below, nginx:1.27 is an image name plus a tag. nginx is a small and very popular web server. The tag is the version label, so 1.27 pins that exact version. The -d flag stands for detached: run in the background and give your prompt back straight away so you can keep typing. The --name web part pins a name you will actually remember, instead of the random one Docker would otherwise invent. All of that work happens inside the Docker daemon, the background service (also called the Docker Engine) that does the pulling, creating and running. The command you type only carries the orders to it.

terminal
$ docker run -d --name web nginx:1.27
Unable to find image 'nginx:1.27' locally
1.27: Pulling from library/nginx
a2abf6c4d29d: Pull complete
e5c7b8f1a4c9: Pull complete
b0a2c3d4e5f6: Pull complete
1f2e3d4c5b6a: Pull complete
Digest: sha256:2ef4c8b1a09d7f6e5c4b3a2918f7e6d5c4b3a2918f7e6d5c4b3a2918f7e6d5
Status: Downloaded newer image for nginx:1.27
7f8e9d0a1b2c4e5f6a7b8c9d0e1f2a3b4c5d6e7f8091a2b3c4d5e6f70819a2b3
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f8e9d0a1b2c nginx:1.27 "/docker-entrypoint.…" 4 seconds ago Up 3 seconds 80/tcp web

Alive, stopped, gone

docker ps is your window onto what is alive right now. By default it lists running containers only, so your nginx shows up as Up. Two things catch people out here. First, a container that crashed or finished its work does not appear in plain docker ps at all. Add -a (short for all), and docker ps -a shows the stopped ones too, which is exactly how you track down a container that died half a second after it started. Second, stopping a container is a different act from deleting it. docker stop asks the app to shut down politely. It sends a signal, meaning a short built-in message from the operating system to a program, called SIGTERM (terminate). Then it waits about ten seconds for the app to finish what it was doing, and only then forces the matter with a harder signal called SIGKILL. So a stop that seems to hang for ten seconds is not broken. It is being patient. Once it returns, the container is still sitting there in the Exited state, holding on to its logs and its name, until you remove it with docker rm.

terminal
$ docker stop web
web
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f8e9d0a1b2c nginx:1.27 "/docker-entrypoint.…" 2 minutes ago Exited (0) 8 seconds ago web
$ docker rm web
web

Skip the stop and you will meet one of the most common beginner errors. Docker blocks the removal of a running container on purpose, so nothing ever yanks a live app out from under you. The message tells you the fix in plain words. Stop first, remove second.

terminal
$ docker run -d --name api nginx:1.27
c4d5e6f7a8b90c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d
$ docker rm api
Error response from daemon: cannot remove container "/api": container is running: stop the container before removing or force remove
$ docker stop api && docker rm api
api
api
The life of one container
1docker run
create + start from an image
2Up
running, shown by docker ps
3docker stop
SIGTERM, then the process ends
4Exited
stopped, shown by docker ps -a
5docker rm
container gone for good
docker start moves an Exited container back to Up without building a new one. rm works once a container has stopped, or with -f to force it.

What the STATUS column is telling you

The STATUS column repays a second look, because that is where you diagnose almost everything. Up 3 seconds means the container is running. Exited (0) means the program finished on its own with nothing wrong, the way a script ends once it has done its job. Exited (1), or any other non-zero number, means it crashed or hit a problem, and that number is your first clue about what went wrong. When somebody says a container 'won't start', nine times out of ten it started perfectly well and then exited within a second. Begin with docker ps -a and that exit code. Then run docker logs web, which prints whatever the container wrote out before it quit, and the rest of the story is usually right there.

The image outlives the container

Removing a container clears the running copy. The image it came from is still on disk, ready to start the next one. That is usually what you want, and it is also why disk space creeps up on you. Containers come and go while images quietly stack up. docker images lists every image you have pulled or built, with its size beside it. docker rmi removes one by name (rmi is short for remove image). docker system df prints how much disk Docker is eating in total, and the RECLAIMABLE column tells you how much of that you could win back. When you want it back, the prune family, such as docker system prune, sweeps out everything that is not currently in use. A laptop that has been running Docker for a month can be carrying tens of gigabytes of forgotten images without ever mentioning it.

terminal
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.27 3b6f2a1c8d90 3 weeks ago 192MB
$ docker rmi nginx:1.27
Untagged: nginx:1.27
Untagged: nginx@sha256:2ef4c8b1a09d...
Deleted: sha256:3b6f2a1c8d90...
Deleted: sha256:9a0b1c2d3e4f...
$ docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 2 0 384MB 384MB (100%)
Containers 0 0 0B 0B
Local Volumes 1 0 41MB 41MB (100%)
Build Cache 12 0 120MB 120MB
run builds a new container every single time
run does not restart the container you already have. It creates a brand-new one from the image. Type docker run --name web ... a second time and it fails with 'The container name "/web" is already in use', because the first one is still on disk. To wake a stopped container back up, reach for docker start web instead. Save docker run for when you genuinely want a fresh copy, and you will not end up with a yard full of half-forgotten containers.

The daily rhythm is short. Run it, list it, stop it, remove it, and glance at your images now and then. The flags come with practice; the lifecycle is the part you want in your hands. What makes it worth drilling is that the same loop fits every image you will ever touch, whether that is nginx, a database like Postgres, or the image you build yourself later in this course. The commands do not change shape.

Names are worth the extra typing. Leave off --name and Docker invents something like eager_lovelace, an adjective and a surname glued together, which is charming until you have to type it twice without a mistake. Name a container whenever you plan to stop it by hand or open a shell inside it. For a one-shot experiment, add --rm instead and the container deletes itself the moment it exits, so there is nothing left to tidy. Keep the named ones around while you are learning logs and inspect, because every command you try needs something to point at.

Images stay behind once their containers are gone, which is good for speed and bad for disk if you keep pulling. Two habits pay for themselves. Learn docker images early so you can see what is actually sitting there. And know that docker rmi refuses to delete an image while any container still references it, including a stopped one you forgot about. If a removal is refused, the fix is the order: take the container out first, then the image.

Read before you delete. Exited (1) means the process failed, and the only account of why lives in that container's logs. Remove the container and the evidence goes with it. Restarting blindly gets you nowhere either, because the second attempt fails in exactly the same way as the first. Check the status, read the logs, then clean up.

Try this

Start a container that does one tiny thing and exits. Watch it vanish from docker ps, find it again with -a, remove it, then confirm the image is still sitting on disk.

terminal
docker run --name brief alpine:3.20 echo "hi from alpine"
docker ps
docker ps -a --filter name=brief
docker rm brief
docker images alpine
output
hi from alpine
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aaaaaaaaaaaa alpine:3.20 "echo ..." 10 seconds ago Exited (0) 9 seconds ago brief
brief
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine 3.20 ........ weeks ago 7.33MB

Takeaway

Carry one idea out of here: a container that stopped has not disappeared, and an image whose container you deleted has not disappeared either. docker ps -a finds the first, docker images finds the second, and rm and rmi are the only two commands that make either of them truly go away.

Quick check
01A minute ago you started a container. Now docker ps prints an empty list. What is most likely going on?
Incorrect — Docker never deletes a container on its own unless you passed --rm. Otherwise it stays on disk, though not always in the default listing.
Correct — Yes. ps hides anything that is no longer running. docker ps -a brings it back, usually as Exited with a code hinting at why it quit.
Incorrect — A missing image makes docker run fail loudly with an error. It would not succeed quietly and then leave ps empty.
Incorrect — A permissions problem prints a clear error about reaching the Docker daemon. It does not hand you a successful but empty list.
02You run docker stop web and the prompt seems to hang for roughly ten seconds before it comes back. What is docker stop doing in that gap?
Incorrect — No. stop never pulls anything. It is signalling the running process to finish.
Correct — SIGTERM goes first, the app gets roughly ten seconds to wrap up, and the harder SIGKILL follows only if it is still running.
Incorrect — No. stop leaves the container, its layer and its logs alone. Only docker rm deletes them.
Incorrect — No. stop asks you nothing. The pause is the grace period before a forced kill.
03You started a container with docker run -d --name web nginx:1.27, stopped it later, and now you want it running again. You retype docker run -d --name web nginx:1.27 and get 'The container name "/web" is already in use'. What is the right move?
Incorrect — The image is not what clashed. The stopped container called web is still on disk.
Incorrect — docker run has no overwrite flag. You either remove the old container or start it again.
Correct — docker run always creates a new container, the old web still exists, and docker start reuses it.
Incorrect — The collision is on the container name, not the image name, so renaming the image changes nothing.

Related