Suggest an editImprove this articleRefine the answer for “How to run a container from a Docker image?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**`docker run`** creates and starts a container from an image in one step. Six flags cover almost every real-world case: `-d` (detached), `--name`, `-p` (publish port), `-v` (mount), `-e` (env var), `--rm` (auto-cleanup). ```bash docker run -d \ --name web \ -p 8080:80 \ -v webdata:/usr/share/nginx/html \ -e NGINX_HOST=example.com \ --restart=unless-stopped \ nginx:1.27-alpine ``` **Key:** `docker run` = `docker create` + `docker start`. Image goes last; everything before it is flags. Anything after the image name overrides the image's `CMD`.Shown above the full answer for quick recall.Answer (EN)Image**`docker run`** is the most-used command in the entire Docker CLI. It pulls the image if needed, creates a container, and starts it — all in one shot. Knowing the half-dozen flags that show up in every production command is most of what "using Docker" actually is. ## Theory ### TL;DR - Anatomy: `docker run [FLAGS] IMAGE[:TAG] [COMMAND] [ARGS...]` - Image goes between flags and any command override. Everything after the image replaces the image's `CMD`. - Six flags cover 90% of cases: `-d`, `--name`, `-p`, `-v`, `-e`, `--rm`. - `docker run` = `docker pull` (if missing) + `docker create` + `docker start`. Three operations in one command. - Use `--rm` for one-off commands (auto-cleanup on exit). Use `-d` + `--restart` for long-lived services. ### Quick example ```bash # Minimum: pull and run $ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world Digest: sha256:9f8e7d6c... Status: Downloaded newer image for hello-world:latest Hello from Docker! ``` The daemon noticed the image was missing, pulled it from Docker Hub, then ran it. One command, three operations. ### The six flags you will use every day #### `-d` / `--detach` — run in the background ```bash docker run -d nginx:1.27-alpine # Returns immediately with the container ID; container keeps running. ``` Without `-d`, the CLI streams logs and exits when the container does. With `-d`, you get back to your shell instantly. #### `--name` — give it a memorable name ```bash docker run -d --name web nginx:1.27-alpine # Now you can do: docker stop web, docker logs web, etc. # Without --name, Docker assigns a random name like "sleepy_einstein". ``` #### `-p` / `--publish` — expose ports ```bash # Format: HOST_PORT:CONTAINER_PORT docker run -d -p 8080:80 nginx:1.27-alpine # Container's port 80 is reachable at http://localhost:8080 # Bind to specific host interface docker run -d -p 127.0.0.1:8080:80 nginx:1.27-alpine # Only loopback, not the public network # Random host port (auto-assigned) docker run -d -p 80 nginx:1.27-alpine # Run docker port <name> to find the host port that was picked ``` Without `-p`, the container is isolated on its own network — reachable from other containers on the same network, but not from the host. #### `-v` / `--volume` — mount storage ```bash # Named volume docker run -d -v pgdata:/var/lib/postgresql/data postgres:16 # Bind mount (specific host path) docker run -d -v /home/me/site:/usr/share/nginx/html nginx:1.27-alpine # Read-only mount docker run -d -v ./conf:/etc/myapp:ro myapp ``` Use named volumes for persistent state, bind mounts for live-reload dev or specific host paths. #### `-e` / `--env` — set environment variables ```bash # Single var docker run -e POSTGRES_PASSWORD=devpass postgres:16 # Pass through from your shell docker run -e API_KEY postgres:16 # From a file docker run --env-file .env postgres:16 ``` Do NOT pass secrets via `-e` in production — they show up in `docker inspect`, image history, and process listings. Use Swarm secrets, BuildKit secret mounts, or external secret managers. #### `--rm` — auto-cleanup on exit ```bash # One-off command, container vanishes when done docker run --rm -it alpine sh # When you exit the shell, the container is removed (no orphan). ``` Makes ad-hoc commands feel like running local scripts. Without `--rm`, every exited container piles up until you `docker rm` them. ### Long-lived service flags ```bash --restart=no # default: do not restart --restart=on-failure # restart only if exit code != 0 --restart=always # restart always (even on docker daemon restart) --restart=unless-stopped # like 'always', but respects manual docker stop ``` For production services, `--restart=unless-stopped` is the usual choice. ### Putting it all together: a realistic command ```bash docker run -d \ --name api \ --restart=unless-stopped \ -p 3000:3000 \ -v api_uploads:/app/uploads \ -v ./api/.env:/app/.env:ro \ -e NODE_ENV=production \ --memory=512m \ --cpus=0.5 \ --health-cmd='curl -f http://localhost:3000/health' \ --health-interval=30s \ myapp:1.0 ``` This is essentially what a production single-host deploy looks like before you graduate to Compose, Swarm, or Kubernetes. ### Overriding the image's `CMD` Anything after the image name replaces the image's default command: ```bash # Image's default CMD (probably the service) docker run nginx:1.27-alpine # Override CMD with a one-off command docker run nginx:1.27-alpine sh -c 'nginx -V' # Runs nginx -V then exits, instead of starting the daemon. # Drop into a shell for debugging docker run -it nginx:1.27-alpine sh ``` If the image has an `ENTRYPOINT`, your trailing args become its arguments instead. Use `--entrypoint /bin/sh` to fully override an entrypoint when debugging. ### Common mistakes **Forgetting `-d` for a service** ```bash $ docker run nginx:1.27-alpine # Terminal hangs streaming nginx logs. # Ctrl+C stops the container too. ``` For anything other than a one-off command, you usually want `-d`. **Wrong port direction in `-p`** ```bash # WRONG: thinks 80 is on the host, 8080 in container docker run -p 80:8080 nginx:1.27-alpine # Nothing serves on container port 8080; you get connection refused on host:80. # RIGHT: HOST:CONTAINER docker run -p 8080:80 nginx:1.27-alpine ``` The order is host first, container second. Common gotcha. **Putting flags after the image name** ```bash # WRONG: -p is treated as an argument to nginx docker run nginx:1.27-alpine -p 8080:80 # RIGHT: flags before image docker run -p 8080:80 nginx:1.27-alpine ``` Docker stops parsing flags at the image name. Anything after is the command for the container, not for `docker run`. **Running interactive without `-it`** ```bash # WRONG: shell exits immediately because there is no TTY docker run alpine sh # RIGHT: -i keeps stdin open, -t allocates a TTY docker run -it alpine sh ``` `-it` (or `-i -t`) is the magic incantation for interactive sessions. ### Real-world usage - **Local development:** `docker run --rm -it -v $PWD:/work node:22 npm test` — disposable container, mounts current dir, runs tests, vanishes. - **Staging/single-host deploy:** the long `docker run -d --name api --restart=unless-stopped ...` form, often wrapped in a shell script or Compose file. - **CI/CD:** `docker run --rm myapp:test npm run test` produces an exit code that the CI uses for pass/fail. - **One-off DB migrations:** `docker run --rm --network mynet -e DATABASE_URL=... migrator:1.0` runs and disappears. ### Follow-up questions **Q:** What is the difference between `docker run` and `docker create`? **A:** `create` allocates the container but does not start it; you have to `docker start` after. `run` does both. `create` is useful when you want to set up the container and start it later, or look at its config (`docker inspect`) before starting. **Q:** How do I run a command in an existing container instead of starting a new one? **A:** `docker exec`. `docker run` always creates a new container; `docker exec` runs a command in a running one. For a shell into an existing container: `docker exec -it <name> sh`. **Q:** Why is my interactive `docker run -it` exiting immediately? **A:** Probably because the image's `ENTRYPOINT` or `CMD` is not a shell. Try `docker run -it --entrypoint sh <image>` to force a shell. Or check the image's docs for the right command to run. **Q:** Can I run a container without giving it a name? **A:** Yes — Docker generates a random one (`musing_einstein`, `crazy_curie`). Fine for one-off `--rm` commands. For anything you will reference later (logs, exec, stop), `--name` saves you typing. **Q:** (Senior) Why might you avoid `docker run` in production and use Compose or Kubernetes instead? **A:** A long `docker run` command is imperative state living in someone's terminal history. Compose makes it declarative (in `compose.yaml`), version-controllable, and reproducible. Kubernetes goes further (multi-host, self-healing, rolling updates). For a single throwaway service, `docker run` is fine. For anything you will redeploy, declarative beats imperative. ## Examples ### Local one-off: run a quick test ```bash $ docker run --rm -it \ -v $PWD:/work \ -w /work \ node:22-alpine \ npm test # Tests run inside the container, output streams to your terminal, # container removed when done. Your laptop stays clean. ``` `--rm`, `-it`, `-v $PWD:/work`, `-w /work`: the four flags that make a container behave like a local script. ### Production-style web service ```bash $ docker run -d \ --name web \ --restart=unless-stopped \ -p 80:80 -p 443:443 \ -v web_certs:/etc/nginx/certs \ -v ./nginx.conf:/etc/nginx/nginx.conf:ro \ --memory=256m \ nginx:1.27-alpine $ docker ps --filter name=web CONTAINER ID IMAGE STATUS PORTS NAMES f7c2a9e1b8d4 nginx:1.27-alpine Up 3 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp web ``` Detached, named, restart-on-reboot, two ports published, certs in a named volume, config bind-mounted read-only, memory cap. ### Override the image's CMD for debugging ```bash # Image's default CMD starts postgres. We want a shell. $ docker run --rm -it postgres:16 bash # Or skip the entrypoint entirely $ docker run --rm -it --entrypoint sh postgres:16 ``` Useful when an image's startup is failing and you need to poke around inside.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.