docker run
docker run creates and starts a container from an image. It matters because this is the command that turns a read-only image into an isolated process with its own filesystem view, network identity, environment, and lifecycle.
Most Docker workflows eventually become Compose files or orchestrator deployments, but docker run is still the clearest way to understand what a container really is. If you can read a docker run command, you can understand which image runs, what command starts, which ports are reachable, where data lives, and what happens when the process exits.
Overview: How docker run Works
An image is a read-only template made of stacked filesystem layers and configuration metadata. A container is an instance of that image: Docker mounts the image layers read-only, adds a thin writable layer for changes made by the container, applies isolation settings, and starts one main process. When that main process exits, the container stops, even if the image still exists locally.
docker run is a convenience command that combines two lower-level actions: docker create and docker start. First the Docker CLI sends your request to the Docker daemon. If the image is missing, the daemon pulls it from a registry. Then Docker creates container metadata, prepares the writable layer, connects the container to a network, applies options such as environment variables and mounts, and finally starts the configured process.
The process that runs comes from the image’s CMD and ENTRYPOINT unless you override it at the end of the command. For example, docker run alpine:3.20 echo hello starts a short-lived container whose process is echo hello. By contrast, docker run nginx:1.27-alpine starts Nginx in the foreground because that is the image’s default command.
On Linux, Docker uses kernel features such as namespaces and cgroups to isolate processes, networks, users, and resources. On Docker Desktop for macOS or Windows, Linux containers run inside a managed Linux VM, but the command-line experience is mostly the same. The important model is stable across platforms: the client asks the daemon to create a container, and the daemon manages the container’s process and storage.
Syntax
The general command form is:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
| Part or option | Meaning |
|---|---|
IMAGE |
The image to run, such as nginx:1.27-alpine or alpine:3.20. Use explicit tags instead of relying on latest. |
COMMAND and ARG... |
Optional override for the image’s default command. These become the container’s main process. |
--name |
Assign a human-readable container name. Names must be unique among existing containers. |
--rm |
Automatically remove the container metadata and writable layer when it exits. Useful for temporary commands. |
-d or --detach |
Run in the background and print the container ID. |
-it |
Allocate an interactive terminal. Common for shells and debugging sessions. |
-p HOST:CONTAINER |
Publish a container port on the host, such as -p 8080:80. This is what makes a container service reachable from the host. |
-e KEY=VALUE |
Set an environment variable inside the container. Do not put real secrets directly in examples, scripts, or image layers. |
-v SOURCE:TARGET |
Mount a named volume or host path into the container. Named volumes are managed by Docker; bind mounts point at a specific host path. |
--network |
Connect the container to a Docker network, such as bridge, host on Linux, or a user-created network. |
docker run has many more options, but these are the ones you will read and write constantly. Start with the image, decide whether the container should be temporary or long-running, then add only the runtime settings the process needs.
Examples
Example 1: Run a Short-Lived Command
docker run --rm alpine:3.20 echo "Hello from a container"
Output:
Hello from a container
Docker creates a container from alpine:3.20, starts echo as the main process, prints the message, and stops when echo exits. The --rm flag removes the stopped container automatically, so this is a clean pattern for one-off tools and quick checks.
Example 2: Start a Web Server in the Background
docker run -d --name web-demo -p 8080:80 nginx:1.27-alpine
docker ps --filter name=web-demo --format "{{.Names}} {{.Ports}}"
Output:
f1b7c3a2d4e5f60718293a4b5c6d7e8f90123456789abcdef0123456789abcd
web-demo 0.0.0.0:8080->80/tcp
The -d flag detaches so Nginx keeps running in the background. The --name flag lets you manage it as web-demo instead of copying a generated ID. The port mapping publishes container port 80 on host port 8080. This is different from EXPOSE in a Dockerfile: EXPOSE is metadata only, while -p actually opens a host port.
Example 3: Pass Configuration with Environment Variables
docker run --rm -e APP_MODE=development -e LOG_LEVEL=debug alpine:3.20 env
Output:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=7a2b4c6d8e90
APP_MODE=development
LOG_LEVEL=debug
Environment variables are runtime configuration. They are visible to the process inside the container and can be read by the application. Use them for non-secret settings such as mode, log level, and feature flags. For real secrets, prefer Docker secrets, your orchestrator’s secret store, or mounted secret files; do not bake them into images with ENV.
Example 4: Persist Data with a Named Volume
docker volume create notes-data
docker run --rm -v notes-data:/data alpine:3.20 sh -c "echo first-note > /data/notes.txt"
docker run --rm -v notes-data:/data alpine:3.20 cat /data/notes.txt
Output:
notes-data
first-note
The file survives because it is written to a named volume, not only to the container’s thin writable layer. When each temporary container exits, --rm deletes that container, but it does not delete the named volume. This distinction is essential for databases, uploads, and any data that must outlive a container replacement.
How It Works Step by Step
- The CLI parses the command and sends an API request to the Docker daemon using the active Docker context.
- The daemon checks whether the requested image exists locally. If not, it pulls the image manifest, config object, and missing read-only layers from the registry.
- Docker creates a container record with the image reference, name, environment variables, command override, port mappings, mounts, and resource settings.
- The storage driver mounts the image layers as a single read-only filesystem and adds a thin writable layer for this container.
- Docker attaches the container to its network. On the default bridge network, the container gets its own private IP address. Published ports create host-side forwarding rules to selected container ports.
- The daemon applies isolation and limit settings, including namespaces and cgroups on Linux, then starts the configured process as PID 1 inside the container.
- If the process keeps running, the container is running. If the process exits, the container stops. A detached container remains manageable with commands such as
docker logs,docker stop, anddocker rm. - If
--rmwas set, Docker removes the stopped container automatically. Images and named volumes remain unless you remove them separately.
This explains why a container is not a tiny virtual machine. It does not boot a full guest operating system for each run. It starts an isolated process using an image filesystem and Docker-managed runtime settings.
Common Mistakes
Forgetting That the Main Process Controls the Container
docker run -d --name quick-test alpine:3.20 echo done
This starts in detached mode, but echo done exits immediately, so the container stops immediately. Use docker ps -a when a container seems to disappear, and run a foreground service when you expect it to stay alive:
docker run -d --name web-demo-fixed -p 8081:80 nginx:1.27-alpine
Thinking EXPOSE Publishes a Port
docker run --name no-host-port nginx:1.27-alpine
The Nginx image documents port 80, but no host port is published here. The fix is to use -p when creating the container:
docker run --name host-port-demo -p 8080:80 nginx:1.27-alpine
Losing Data by Writing Only to the Container Layer
docker run --rm alpine:3.20 sh -c "echo important > /tmp/data.txt"
This writes into the temporary container’s writable layer. Because --rm removes that layer when the process exits, the file is gone. Mount a named volume for data that must survive:
docker run --rm -v app-data:/data alpine:3.20 sh -c "echo important > /data/data.txt"
Relying on latest for Repeatable Runs
docker run redis
This means redis:latest. The latest tag can move, so tomorrow’s run might use different image content. Prefer a tested tag:
docker run redis:7.2-alpine
Best Practices
- Use explicit image tags such as
nginx:1.27-alpine,redis:7.2-alpine, oralpine:3.20. - Use
--rmfor temporary commands, but avoid it for containers you need to inspect after failure. - Name long-running containers with
--nameso logs, stops, and removals are predictable. - Publish only the ports you need with
-p. Remember thatEXPOSEdoes not publish anything by itself. - Use named volumes for persistent application data and bind mounts mainly for local development source code.
- Keep secrets out of image layers and command history. Use secret stores or mounted files for sensitive values.
- Stop and remove old containers intentionally with
docker stopanddocker rm; deleting an image is a separate operation. - When a single command grows large, move the setup into a
docker composefile so the runtime configuration is versioned and readable.
Practice Exercises
- Run
alpine:3.20temporarily and print the operating system release file. Hint: override the image command withcat. - Start
nginx:1.27-alpineas a detached container namedpractice-weband publish it on host port8090. Expected end state:docker psshows a port mapping to container port80. - Create a named volume and use two short-lived Alpine containers to write and then read a file from it. Expected end state: the file remains even though both containers used
--rm.
Summary
docker runcreates a container from an image and starts its main process.- If the image is missing, Docker pulls it before creating the container.
- A container uses read-only image layers plus a thin writable layer for its own changes.
- The container stops when its main process exits.
-druns in the background,--rmcleans up after exit, and--namegives the container a stable name.-ppublishes ports;EXPOSEonly documents intended container ports.- Use volumes for data that must survive container removal.
