Docker Get Started (Hello World)
hello-world is Docker’s smallest useful first test: it proves your Docker client can talk to the daemon, pull an image, create a container, run a process, and show logs. The command looks tiny, but it exercises the same core path used by real applications. Once you understand what happens during this first run, Docker stops feeling like magic and starts feeling like a predictable tool.
Overview: How Hello World Works
The Docker command you type is the client. It does not run containers by itself. It sends API requests to the Docker daemon, which is the long-running service that manages images, containers, networks, volumes, and build cache. On Linux, the daemon normally uses the Linux kernel directly. On Docker Desktop for macOS and Windows, the daemon runs inside a managed Linux VM because Linux containers need Linux kernel features.
The command docker run --rm hello-world:latest asks Docker to run a container from the image named hello-world with the tag latest. An image is a read-only template made of one or more filesystem layers plus metadata such as the default command. A container is an instance of an image with a thin writable layer added on top and, while it is running, an isolated process. Removing a container does not remove the image. Removing an image may be blocked while a container still references it.
If the image is not already local, Docker contacts a registry, usually Docker Hub for unqualified names. The tag resolves to a registry manifest. That manifest describes which layer blobs and configuration object make up the image for your platform. Docker downloads only the missing layers, verifies their content, stores them locally, and then creates a container from that image.
The hello-world container runs one short program. That program prints a message to standard output and exits. Because the main process exits, the container stops. Because you used --rm, Docker removes the stopped container automatically. The image remains cached locally, so the next run usually skips the pull.
Syntax
The general form for the first-run command is:
docker run [OPTIONS] IMAGE [COMMAND] [ARGUMENTS]
| Part | Meaning |
|---|---|
docker |
The Docker CLI client installed on your machine. |
run |
Create a new container from an image and start its main process. |
[OPTIONS] |
Flags that change container behavior, such as cleanup, name, port publishing, environment variables, or mounts. |
IMAGE |
The image reference, usually name:tag, such as hello-world:latest or nginx:1.27-alpine. |
[COMMAND] [ARGUMENTS] |
An optional command that overrides the image’s default command. |
For this lesson, these options are the important ones:
| Option | Use |
|---|---|
--rm |
Automatically remove the container after it exits. Useful for one-shot commands and tests. |
--name get-started-web |
Give a container a predictable name instead of Docker’s random generated name. |
-d |
Run in detached mode, meaning the container stays in the background and Docker prints its ID. |
-p 8080:80 |
Publish host port 8080 to container port 80. This is what makes a container service reachable from the host. |
Examples
Example 1: Run Docker Hello World
docker run --rm hello-world:latest
Output:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
The first line appears only when the image is not already on your machine. Docker then pulls the image from the library/hello-world repository on Docker Hub, creates a container, runs the image’s default command, streams the output to your terminal, and removes the stopped container because of --rm. This verifies more than the CLI version; it verifies that the daemon, registry access, image storage, container creation, and log streaming all work.
Example 2: See What Remains After Hello World
docker image ls hello-world
docker ps -a --filter ancestor=hello-world:latest
Output:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 2 months ago 13.3kB
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
The image remains because Docker caches pulled images. That is why repeating docker run --rm hello-world:latest is faster. The container list is empty because --rm removed the container after it exited. If you omit --rm, Docker keeps the stopped container’s metadata and writable layer until you remove it.
Example 3: Run a Container That Stays Up
docker run -d --name get-started-web -p 8080:80 nginx:1.27-alpine
docker ps --filter name=get-started-web
docker logs get-started-web
docker stop get-started-web
docker rm get-started-web
Output:
4b6f7a8c9d01
CONTAINER ID IMAGE STATUS PORTS NAMES
4b6f7a8c9d01 nginx:1.27-alpine Up 4 seconds 0.0.0.0:8080->80/tcp get-started-web
/docker-entrypoint.sh: Configuration complete; ready for start up
get-started-web
get-started-web
This example moves from a one-shot test to a long-running service. The -d flag leaves Nginx running in the background, and -p 8080:80 publishes the container’s port 80 on your host’s port 8080. Visit http://localhost:8080 while it is running. The tag nginx:1.27-alpine is specific, which is better for reproducible learning and projects than relying on nginx:latest.
How It Works Step by Step
- The CLI parses
docker run --rm hello-world:latestand sends a request to the Docker daemon through the active Docker context. - The daemon checks the local image store. If
hello-world:latestis missing, Docker asks the registry for the tag’s manifest. - The registry returns metadata describing the image configuration and layer blobs for your platform. Docker downloads any missing content and stores it by digest.
- Docker creates container metadata: image, command, environment, mounts, network settings, and cleanup behavior.
- The image’s read-only layers are mounted together using Docker’s storage driver. Docker adds a thin writable layer for this one container.
- Docker creates process isolation using namespaces and resource accounting using control groups. On Docker Desktop, this happens inside the Linux VM.
- The container’s main process starts, writes text to stdout, and exits with a success code.
- The daemon records the exit, streams logs back to the client, and removes the stopped container because
--rmwas requested.
The Nginx example follows the same path, but the process does not exit immediately. Docker also configures port forwarding because of -p 8080:80. A Dockerfile’s EXPOSE instruction would only document the intended container port as metadata; it would not publish anything to the host. Publishing requires docker run -p or Compose ports:.
Common Mistakes
Checking Only the Client
docker --version
This proves the CLI is installed, but it does not prove containers can run. The daemon might be stopped or unreachable. Follow it with a daemon-backed command:
docker info
docker run --rm hello-world:latest
Forgetting Cleanup
docker run hello-world:latest
docker ps -a
Without --rm, the exited container remains in docker ps -a. That is useful when you want to inspect an exit state, but it clutters a beginner workstation during repeated tests. Use --rm for short-lived commands, or remove stopped containers explicitly with docker rm.
Assuming EXPOSE Publishes a Port
FROM nginx:1.27-alpine
EXPOSE 80
This Dockerfile metadata does not open localhost:80. The fix is to publish the port at runtime:
docker run --rm -p 8080:80 nginx:1.27-alpine
Treating latest as Stable
docker run -d --name get-started-web nginx:latest
The latest tag is a moving label. It is fine for Docker’s tiny smoke-test image in this lesson, but application examples and production work should use specific tags such as nginx:1.27-alpine.
Best Practices
- Use
docker run --rmfor one-shot test containers so exited containers do not accumulate. - Use
docker infoordocker runto verify the daemon, not onlydocker --version. - Use specific image tags for services and projects. Treat
latestas convenient but not reproducible. - Name containers you plan to inspect, stop, or remove with
--name. - Publish ports intentionally with
-p host:container. Do not rely onEXPOSEto publish ports. - Remember that images and containers are different objects. Clean up containers with
docker rmand images withdocker image rm. - Read container output with
docker logsfor detached services instead of rerunning commands blindly. - Use modern
docker composelater for multi-container applications; the olddocker-composecommand is legacy.
Practice Exercises
- Run
hello-world:latesttwice with--rm. Expected end state: the second run should not need to download the image layers again. - Run
hello-world:latestonce without--rm, find the stopped container withdocker ps -a, then remove it. Hint: use the container ID or generated name. - Start
nginx:1.27-alpinenamedpractice-get-startedon host port8090. Expected end state:http://localhost:8090shows the Nginx welcome page, and the container can be stopped and removed cleanly.
Summary
docker run --rm hello-world:latestis a complete smoke test for the Docker client, daemon, registry pull, container start, logging, and cleanup path.- An image is read-only layered content; a container is an instance of that image with a thin writable layer and a process.
- Docker pulls image layers from a registry only when they are missing locally.
- A container stops when its main process exits.
--rmremoves the stopped container, but the image remains cached. - Long-running containers such as Nginx need detached mode for background use and
-pto publish ports. EXPOSEdocuments ports;docker run -pactually publishes them.
