Docker hello-world: Run Your First Container
With Docker installed (see Install Docker Desktop on Windows 11), it's time to run a container. The official hello-world image is the smallest possible test: it downloads in a second, prints a message and stops. But behind that one command Docker does a lot of work, and understanding it now makes every later command easier.
In this lab you'll follow the image download and the container execution step by step. The outputs come from a real run on Docker Engine 29.
Run the command
docker run hello-world
The output has two parts. The first eight lines come from Docker (downloading the image). Everything from "Hello from Docker!" comes from the program inside the container.
Part 1: the image download, line by line
| Line | What happened |
|---|---|
Unable to find image 'hello-world:latest' locally | The daemon looked in its local image store first. You wrote hello-world without a tag, so Docker used the default tag latest. It wasn't there yet. |
latest: Pulling from library/hello-world | The daemon contacted the default registry, Docker Hub. library/ is the namespace for Docker's official images, so the full name is docker.io/library/hello-world:latest. |
4f55086f7dd0: Pulling fs layer ... Pull complete | The image is made of layers. Each one is downloaded, checked and unpacked. hello-world has only one filesystem layer. |
Digest: sha256:c567b2... | A unique fingerprint of exactly this image version. The same digest always means exactly the same content. |
Status: Downloaded newer image | The image is now stored locally and won't be downloaded again. |
The image is now in your local list:
docker images
It's tiny: about 26 KB on disk. The U in the EXTRA column means the image is in use by at least one container (even a stopped one).
Part 2: the container execution
The message printed by the container describes the four steps itself, and they map exactly onto the Docker architecture:
- Client to daemon:
docker.exesent a "create and start a container" request to the Docker daemon through its REST API. - Daemon to registry: the image wasn't local, so the daemon pulled it from Docker Hub (part 1 above).
- Daemon creates and starts a container: it added a thin writable layer on top of the read-only image, set up isolation, and started the image's default command. For hello-world that command is a single small program called
/hello. - Output streamed back: the program wrote its text to standard output; the daemon streamed it to your client, which printed it in your terminal.
You can see the default command and size with docker image inspect:
docker image inspect hello-world --format "Os={{.Os}} Arch={{.Architecture}} Cmd={{.Config.Cmd}} Size={{.Size}}"
The whole image is one 20 KB program and nothing else: no shell, no operating system tools. That's enough because a container doesn't need a full OS; it uses the host's kernel.
Why the container stops immediately
Right after the message, the container is no longer running:
docker ps
The list is empty. A container lives only as long as its main process. /hello printed its text and exited, so the container stopped. It wasn't deleted, though. Add -a to see stopped containers too:
docker ps -a
Exited (0): the program ended with exit code 0, which means success.- Each
docker runcreates a new container from the same image, so two runs left two containers. - We didn't use
--name, so Docker generated random names such asnifty_ellis.
Run it a second time: no download
docker run hello-world
This time the output starts straight with "Hello from Docker!". There are no "Unable to find image" or "Pulling" lines, because the image is already stored locally. Only the first run of an image pays the download cost; containers start from the local copy afterwards.
Clean up automatically with --rm
To avoid collecting stopped containers, add --rm. Docker removes the container as soon as it exits:
docker run --rm hello-world
After this run, docker ps -a still showed only the same two containers: the --rm container was removed automatically. To remove the old ones and the image itself:
docker container prune # removes ALL stopped containers (asks for confirmation)
docker rm nifty_ellis eloquent_meninsky # or remove specific ones
docker rmi hello-world # remove the image (no container may use it)
Be careful with prune commands on a machine where you have other work: docker container prune removes every stopped container, not only the ones from this lab. Removing containers by name is safer.
What you learned
| Concept | Seen in this lab |
|---|---|
| Image lookup order | Local image store first, then the registry (Docker Hub) |
| Default tag | hello-world means hello-world:latest |
| Layers and digest | Images download in layers and are identified by a sha256 digest |
| docker run = pull (if needed) + create + start | The four steps in the hello-world message |
| Container lifetime | It stops when its main process exits |
| Stopped containers remain | docker ps -a; remove them with docker rm or --rm |
Interview questions
What does docker run do when the image isn't available locally?
It pulls the image from the configured registry (Docker Hub by default), then creates a container from it and starts it. If the image is local, no download happens.
Why does the hello-world container stop right after it runs?
A container runs only as long as its main process. The /hello program prints a message and exits with code 0, so the container moves to the Exited state.
What is the difference between docker ps and docker ps -a?
docker ps lists only running containers. docker ps -a lists all containers, including stopped (exited) ones.
Summary
docker run hello-worldchecks the local store, pulls from Docker Hub if needed, creates a container and starts it.- Pull output shows the image's layers and its sha256 digest.
- The container exits as soon as its program finishes; it stays in
docker ps -auntil removed. - Second runs reuse the local image;
--rmdeletes the container automatically when it exits.
Next lab: Run an Nginx container on port 8080, a container that keeps running and serves a website.