Docker Run Commands Explained
The most powerful and complex command in Docker, deconstructed. Understand every flag and build production-ready container configurations.
Flag-by-Flag Breakdown
-d (--detach)ModeRuns the container in the background (detached mode). Without this flag, your terminal is attached to the container's stdout/stderr, and closing the terminal stops the container. Use -d for servers and long-running processes.
-p (--publish)NetworkMaps a host port to a container port: HOST:CONTAINER. The example 8080:80 means traffic hitting localhost:8080 on your machine is forwarded to port 80 inside the container. You can also bind to specific interfaces: 127.0.0.1:8080:80.
-v (--volume)StorageMounts a host path or named volume into the container: HOST_PATH:CONTAINER_PATH. Bind mounts (with host paths) enable live code editing. Named volumes (like mydata:/app/data) are managed by Docker and persist across container recreation.
--nameIdentityAssigns a human-readable name to the container instead of a random one like "vigorous_beaver". Makes management easier: docker stop my-web instead of using container IDs. Names must be unique.
--restartResilienceControls automatic restart behavior. Options: no (default), on-failure (restart if exit code is non-zero), always (restart unconditionally), unless-stopped (like always, but not if you manually stopped it).
--memoryResourcesSets a hard memory limit. If the container exceeds this, the OOM killer terminates processes. Units: b, k, m, g. Pair with --memory-swap to also limit swap. Essential for production to prevent runaway processes.
-e (--env)ConfigSets environment variables inside the container. Use for configuration that changes between environments. Can use multiple -e flags or --env-file for many variables.
Mastering Docker Run: The Complete Reference
The docker run command is where containers come to life. It is the most complex Docker command because it configures the entire runtime environment: networking, storage, resource limits, security context, and more. Understanding its flags deeply enables you to solve deployment challenges, optimize performance, and debug issues effectively.
While Docker Compose is preferred for defining complex multi-container applications, understanding docker run directly is essential. Compose files are effectively declarations of run parameters, and knowing the underlying flags helps you read Compose files, troubleshoot issues, and handle scenarios where Compose is not available.
What Actually Happens When You Run
The docker run command is actually a combination of three distinct API operations. First, docker create sets up the container: it allocates a writable filesystem layer, configures networking, sets up the environment, and prepares the container for execution. Second, docker start launches the container's main process. Third, if running in attached mode (without -d), docker attach connects your terminal to the container's streams.
This explains some behaviors that might otherwise be confusing. For example, a container that exits immediately might have incorrect CMD/ENTRYPOINT configuration—it correctly created and started but the main process terminated instantly. Separating create and start can help diagnose such issues.
Networking in Depth
Port mapping with -p is fundamental but often misunderstood. The format is hostPort:containerPort or hostIP:hostPort:containerPort. When you specify -p 8080:80, Docker creates iptables rules to forward traffic from the host's port 8080 to the container's port 80.
Containers by default join the "bridge" network, which provides NAT-based connectivity. Containers can reach the internet through the host but are not directly accessible from outside unless ports are published. For container-to-container communication, create a custom bridge network: containers on the same network can reach each other by name.
The --network flag controls which network a container joins. Use --network host to use the host's network stack directly (no isolation, container uses host's IP), or --network none for complete isolation.
Volume Strategies
Docker provides three types of storage: bind mounts, named volumes, and tmpfs mounts. Understanding when to use each is crucial for data management.
Bind mounts (-v /host/path:/container/path) map a specific host directory into the container. They are perfect for development—mount your source code and changes appear immediately inside the container. However, they tightly couple your container to the host's filesystem layout.
Named volumes (-v mydata:/container/path) are managed by Docker. Docker creates the volume in its storage area and handles all the details. These are preferred for persistent data like databases because they work across different hosts and are easier to back up with Docker volume commands.
tmpfs mounts (--tmpfs /app/temp) store data in memory only—it disappears when the container stops. Use for sensitive data that should not persist to disk or for performance-critical temporary files.
Resource Constraints
By default, containers have unlimited access to host resources, which is dangerous in production. A runaway container can starve other containers or even the host. Always set resource limits for production deployments.
--memory sets a hard limit on RAM. If the container tries to use more, processes are killed by the OOM killer. --memory-reservation sets a soft limit—Docker tries to keep usage below this but allows bursting above it when needed.
--cpus limits CPU usage. --cpus 1.5 means the container can use at most 1.5 CPU cores. --cpu-shares provides relative weighting when containers compete for CPU.
--pids-limit limits the number of processes a container can create, preventing fork bombs. --ulimit sets various resource limits like open files and process count.
Environment and Configuration
Environment variables are the standard way to configure containerized applications. The -e flag sets individual variables: -e DATABASE_URL=postgres://.... For many variables, use --env-file .env to load from a file.
Sensitive data should not be passed as environment variables visible in docker inspect. Docker Secrets or external secret managers are more secure for production credentials.
--workdir sets the working directory inside the container, overriding the image's WORKDIR. --user specifies which user the container runs as—important for security, as running as root inside containers poses risks.
Interactive Mode and TTY
The -i (interactive) and -t (pseudo-TTY) flags are often used together as -it. -i keeps stdin open so you can type commands. -t allocates a pseudo-terminal, enabling features like colored output and terminal control sequences.
For running a shell, you need both: docker run -it ubuntu bash. For running a script that needs input but not a terminal, you might use just -i. For detached containers, you typically use neither.
Security Considerations
--read-only makes the container's filesystem read-only, preventing malicious or buggy code from modifying container files. Combine with tmpfs for directories that need to be writable.
--security-opt configures security modules like AppArmor and SELinux. --cap-drop ALL --cap-add NET_BIND_SERVICE drops all Linux capabilities except the specific ones needed, following the principle of least privilege.
Never use --privileged unless absolutely necessary—it gives the container nearly unlimited access to the host, defeating container isolation.
Common Patterns
One-off utility container: docker run --rm -v $(pwd):/app image command. The --rm automatically removes the container when it exits, -v mounts your current directory.
Background service: docker run -d --name myservice --restart unless-stopped -p 80:80 image. Detached, named, automatically restarts, port mapped.
Development container: docker run -it --rm -v $(pwd):/app -p 3000:3000 node:18 bash. Interactive, automatic cleanup, synchronized source code, exposed port.