Running Containers
Every container starts with docker run, but the flags you choose determine how it behaves. This lesson focuses on the two fundamental modes -- interactive and detached -- and the options you will use most often in practice.
Interactive vs Detached
flowchart LR
subgraph interactive["Interactive (-it)"]
A["Terminal attached"] --> B["You type commands"]
B --> C["Exit ends container"]
end
subgraph detached["Detached (-d)"]
D["Runs in background"] --> E["Logs to docker logs"]
E --> F["Stays running after terminal closes"]
end
style interactive fill:#e3f2fd,stroke:#1565c0
style detached fill:#e8f5e9,stroke:#2e7d32
| Mode | Flags | Use Case |
|---|---|---|
| Interactive | -it | Debugging, exploring images, one-off scripts |
| Detached | -d | Services, databases, web servers |
Interactive Mode
Interactive mode attaches your terminal to the container. You get a shell prompt and can type commands directly:
# Start an Ubuntu container and drop into bash
docker run --rm -it ubuntu:22.04 bash
-ikeeps STDIN open so you can type input-tallocates a pseudo-TTY so you get a proper prompt--rmremoves the container automatically when you exit
Practical Examples
# Explore an image's filesystem
docker run --rm -it alpine:3.19 sh
# Run a Python script interactively
docker run --rm -it python:3.12 python3
# Test network tools inside a container
docker run --rm -it nicolaka/netshoot bash
# Start a Node.js REPL
docker run --rm -it node:20-alpine node
Use --rm with interactive containers. Without it, exited containers accumulate and waste disk space. Check with docker ps -a.
Detached Mode
Detached mode runs the container in the background. You get the container ID back immediately:
docker run -d --name web nginx:alpine
# Returns: a1b2c3d4e5f6...
The container keeps running after your terminal session ends. Use docker logs and docker exec to interact with it.
Practical Examples
# Run a web server on port 8080
docker run -d --name web -p 8080:80 nginx:alpine
# Run a PostgreSQL database
docker run -d \
--name db \
-e POSTGRES_PASSWORD=secret \
-p 5432:5432 \
postgres:16
# Run Redis as a cache
docker run -d --name cache -p 6379:6379 redis:7-alpine
Essential Run Options
| Option | Purpose | Example |
|---|---|---|
--name | Assign a memorable name | --name my-api |
-p / --publish | Map host port to container port | -p 8080:80 |
-v / --volume | Mount storage | -v data:/app/data |
-e / --env | Set environment variable | -e NODE_ENV=production |
--rm | Auto-remove on exit | --rm |
--restart | Restart policy | --restart unless-stopped |
-w / --workdir | Set working directory | -w /app |
--hostname | Set container hostname | --hostname api-server |
--network | Connect to a network | --network my-net |
--read-only | Make filesystem read-only | --read-only |
Combining Options: Real-World Patterns
Development Web Server
docker run -d \
--name dev-server \
--rm \
-p 3000:3000 \
-v "$(pwd)":/app \
-w /app \
node:20-alpine \
npm run dev
Production API Server
docker run -d \
--name api \
-p 8080:8080 \
--restart unless-stopped \
--memory=512m \
--cpus=1.0 \
-e NODE_ENV=production \
my-api:1.0.0
One-Off Job
docker run --rm \
-v "$(pwd)/output":/output \
my-report-generator:latest \
--format=pdf --output=/output/report.pdf
Container Naming Conventions
| Convention | Example | When to Use |
|---|---|---|
| Service name | web, api, db | Single-instance services |
| Project-service | myapp-web, myapp-db | Multiple projects on one host |
| Service-environment | api-staging, api-prod | Multiple environments |
Avoid using default random names (like quirky_einstein) in any script or production setup. Random names make debugging and automation impossible.
Port Mapping in Detail
# Map host port 8080 to container port 80
docker run -d -p 8080:80 nginx:alpine
# Bind to localhost only (not exposed to network)
docker run -d -p 127.0.0.1:8080:80 nginx:alpine
# Map multiple ports
docker run -d -p 8080:80 -p 8443:443 nginx:alpine
# Let Docker assign a random host port
docker run -d -p 80 nginx:alpine
docker port <container> # See assigned port
| Syntax | Meaning |
|---|---|
-p 8080:80 | Host 8080 → Container 80 (all interfaces) |
-p 127.0.0.1:8080:80 | Host 8080 → Container 80 (localhost only) |
-p 80 | Random host port → Container 80 |
-p 8080:80/udp | UDP port mapping |
Managing Running Containers
| Command | What It Does |
|---|---|
docker ps | List running containers |
docker ps -a | List all containers (including stopped) |
docker stop <name> | Gracefully stop a container |
docker start <name> | Start a stopped container |
docker restart <name> | Stop and start a container |
docker rm <name> | Remove a stopped container |
docker rm -f <name> | Force-remove (even if running) |
Bulk Operations
# Stop all running containers
docker stop $(docker ps -q)
# Remove all stopped containers
docker container prune
# Remove all containers (running and stopped)
docker rm -f $(docker ps -aq)
docker rm -f $(docker ps -aq) removes every container on the host, including databases with data. Use with extreme caution.
Key Takeaways
- Interactive mode (
-it) is for exploration and debugging; detached mode (-d) is for services. - Always use
--nameso you can reference containers predictably. - Use
--rmfor throwaway containers to prevent accumulation. - Bind ports to
127.0.0.1when the service should not be exposed to the network. - Combine
--restart unless-stoppedwith resource limits for production deployments.
What's Next
- Continue to Container Interaction to learn how to execute commands, attach, and copy files in running containers.