Every developer’s first real Docker moment is running docker run hello-world, and there’s a reason that specific command has become a rite of passage — it exercises nearly the entire Docker pipeline in one shot: pulling an image, creating a container, running it, and printing proof that the whole system works end to end. I remember running it for the first time not fully understanding what had just happened, so this guide walks through not just the command itself but everything that happens behind it.
Prerequisites
- Docker installed on your machine (Docker Desktop on Mac/Windows, or Docker Engine on Linux)
- Verify installation:
docker --version
Docker version 27.3.1, build ce12230
- Verify the Docker daemon is running:
docker info
If this returns system details rather than a connection error, the daemon is up and ready.
Step 1: Run Hello World
docker run hello-world
Expected output the first time you run it:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:1408fec78703e60de6b7c8f8e9c8b0e9a3fe5c9f5e8b0e9a3fe5c9f5e8b0e9a
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs
the executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent
it to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
That block of text is itself printed by a tiny compiled binary inside the hello-world image — it’s genuinely explaining, in real time, the exact pipeline that just executed to produce it.
Step 2: Run It Again and Notice the Difference
docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
...
Notice there’s no “Pulling from library/hello-world” this time — Docker found the image already cached locally and skipped the download.
Step 3: Confirm the Image Was Pulled
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 14 months ago 13.3kB
Thirteen kilobytes — this is about as small as a Docker image gets, since it contains a single statically linked binary and nothing else.
Step 4: See the Container That Ran (and Exited)
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
e5f6a7b8c9d0 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago quirky_hopper
The container ran its single command (/hello), printed its message, and exited immediately with status code 0, meaning success. This is expected — hello-world isn’t a long-running service, so it’s supposed to finish right away.
Step 5: Clean Up
Since each run creates a new stopped container, running it several times leaves several stopped containers behind:
docker ps -a
CONTAINER ID IMAGE COMMAND STATUS NAMES
e5f6a7b8c9d0 hello-world "/hello" Exited (0) 2 minutes ago quirky_hopper
f6a7b8c9d0e1 hello-world "/hello" Exited (0) 5 minutes ago nostalgic_curie
Remove them:
docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
e5f6a7b8c9d0
f6a7b8c9d0e1
Total reclaimed space: 0B
Internal Working: What Actually Happens Step by Step
- Client request: the
dockerCLI sends a request to the Docker daemon (dockerd) via its REST API, usually over a local Unix socket (/var/run/docker.sock). - Image resolution: the daemon checks its local image store for
hello-world:latest. If absent, it contacts Docker Hub’s registry API, negotiates the correct image manifest for your CPU architecture, and downloads the image layer(s). - Layer storage: the downloaded layer is stored under Docker’s storage driver directory (commonly
/var/lib/docker/overlay2/on Linux). - Container creation:
containerd, working withrunc, prepares Linux namespaces (PID, mount, network, UTS, IPC) and cgroups for resource isolation, then creates a container filesystem by adding a thin writable layer on top of the image’s read-only layers. - Process execution:
runcexecutes the image’s configured command (/hello) inside those namespaces. - Output streaming: the container’s stdout is captured by Docker’s logging driver and streamed back through the daemon to the CLI, which prints it to your terminal.
- Exit and cleanup: once
/hellofinishes, the container’s main process ends, its state becomesExited, and the container itself remains on disk (though not running) until explicitly removed.
Networking Notes
hello-world doesn’t listen on any port or make any network connections once running — the only network activity involved is the initial image pull from Docker Hub over HTTPS. This makes it a genuinely safe first test even on networks with tight outbound restrictions, aside from that one registry pull.
Storage Notes
Because the image is so small and the container does nothing but print text and exit, there’s essentially no storage footprint beyond the 13.3kB image itself and a tiny per-container metadata directory that docker container prune clears out.
Security Considerations
- Pulling
hello-world(or any public image) means trusting Docker Hub’s content — for anything beyond a first test, verify image digests or use Docker Content Trust for signed images in production. - Running containers doesn’t require root privileges on the container side by default for this image, but the Docker daemon itself typically runs as root on Linux, which is worth knowing when reasoning about your host’s security boundaries.
Troubleshooting
“Cannot connect to the Docker daemon”
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
This means the Docker service itself isn’t running. On Linux:
sudo systemctl start docker
On Mac/Windows, start Docker Desktop.
“permission denied while trying to connect to the Docker daemon socket” On Linux, this means your user isn’t in the docker group:
sudo usermod -aG docker $USER
Then log out and back in for the group change to take effect.
Image pull fails with a network/TLS error Usually a proxy or firewall blocking access to registry-1.docker.io. Check outbound HTTPS access and any corporate proxy configuration in Docker’s daemon settings.
Monitoring
For this one-shot container there’s nothing ongoing to monitor, but it’s still worth checking exit codes when scripting against Docker for the first time:
docker run hello-world; echo "Exit code: $?"
Exit code: 0
Best Practices
- Use
hello-worldpurely as an installation sanity check, not as a template for real application containers. - Get comfortable with
docker ps -aearly — it’s the single most useful command for understanding what containers exist and their current state. - Learn
docker container pruneearly too, so leftover stopped containers from experimentation don’t accumulate unnoticed.
Summary
docker run hello-world looks trivial, but it silently exercises the entire Docker pipeline: client-daemon communication, registry image pulls, layer storage, namespace and cgroup setup, process execution, and log streaming. Understanding what happens behind those few lines of output makes every subsequent, more complex docker run command far less mysterious.
References
- Docker “Get started” guide: https://docs.docker.com/get-started/
- Docker Hub hello-world image: https://hub.docker.com/_/hello-world
- Docker Engine overview: https://docs.docker.com/engine/
- Docker run reference: https://docs.docker.com/reference/cli/docker/container/run/
