Running Containers with Docker: Practical Usage and Nuances
Containers decouple application execution from the underlying OS. With Docker, launching a container is a single command—but subtle flags and real-world side effects turn a simple docker run
into a useful tool for development, debugging, and production.
The Fundamental Command: docker run
Start here:
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
- IMAGE: e.g.,
alpine:3.18
,nginx:1.25.1
- OPTIONS: Control isolation, networking, resource allocation, etc.
- COMMAND/ARG...: Optionally override an image’s default entrypoint.
Quick test (Ubuntu 22.04, interactive shell):
docker run -it --rm ubuntu:22.04 bash
-it
: Interactive with TTY--rm
: Auto-remove the container on exit (avoids littered stopped containers)bash
: Opens Bash instead of Ubuntu’s defaultCMD
(often/bin/sh
)
Note: On first use, Docker will pull the specified image if it’s not present locally. Expect a delay and network activity.
Real-World Usage: Exposing Services and Managing State
Common web workloads demand port mapping. For example, running a disposable Nginx 1.25.1 web server bound to host port 8080:
docker run -d --name test-nginx -p 8080:80 nginx:1.25.1
Check logs or troubleshoot:
docker logs test-nginx
Stop and clean up:
docker rm -f test-nginx
Gotcha: Omitting the -d
flag runs containers in the foreground. Terminal session will block until the process exits.
Option Highlights (Summary Table)
Option | Description | Example |
---|---|---|
-d | Detached/background mode | -d |
-p host:cont | Host ⟶ Container port mapping | -p 8080:80 |
-v src:dst | Bind-mount host volume | -v $(pwd)/web:/usr/share/nginx/html:ro |
--name | Assign readable container name | --name myapp |
--rm | Remove container after exit | --rm |
-e KEY=VAL | Pass environment variable | -e ENV=prod |
-it | Interactive + TTY (shell sessions) | -it |
Some options can interact: using both --rm
and --name
is common for CI scripts running ephemeral containers.
Overriding ENTRYPOINT: Practical Example
Use Alpine to run an ad-hoc ping test, completely replacing its default command:
docker run --rm alpine:3.18 ping -c 2 1.1.1.1
Sample output:
PING 1.1.1.1 (1.1.1.1): 56 data bytes
64 bytes from 1.1.1.1: seq=0 ttl=61 time=13.200 ms
64 bytes from 1.1.1.1: seq=1 ttl=61 time=12.900 ms
--- 1.1.1.1 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
If Alpine lacks utilities (common minimal image constraint), install with apk add
.
Troubleshooting and Common Errors
Port Conflict
Launching two containers on the same host port:
docker: Error response from daemon: driver failed programming external connectivity...
...Bind for 0.0.0.0:8080 failed: port is already allocated.
Remediation: Use another port or stop/remove the conflicting container.
Image Not Found
Unable to find image 'nginx:latest' locally
docker: Error response from daemon: pull access denied for nginx, repository does not exist...
Root cause: Typo in image/tag or private registry access misconfigured.
Pro Tips
- Filter local containers:
docker ps -a --filter "status=exited"
- Prune unused images and containers:
docker system prune -f
- For debugging, consider dropping into the container with a shell:
docker exec -it <container_name> /bin/sh
or/bin/bash
- On Windows: Be aware of file system path differences in volume mounts.
Known issue: Running containers with -it
via SSH without proper terminal allocation (ssh -t
) may result in no interactive shell.
ASCII Sketch: Host to Container Port Mapping
+-------------------+
| Host port 8080 | <---+
+-------------------+ |
| -p 8080:80
+-------------------+ |
| Container port 80 | <---+
+-------------------+
Modern Docker (v24.x) introduces more granular resource liming (--cpus
, --memory
), but defaults are typically system-limited. Always validate with docker inspect
.
Side note: For persistent workloads, mount volumes for data durability. Stateless containers are disposable by design.
Summary:
Mastering docker run
—with intent, not guesswork—enables robust local dev, reproducible builds, and smooth CI/CD. The right flags turn a test container into a reliable building block.
For more advanced orchestration, see docker-compose
, Kubernetes deployments, or Helm charts.
If a container behaves unexpectedly, start by examining both Docker logs and container entrypoints/scripts for clues.