Now that you understand images, it's time to work with containers. In this article, we'll cover all the essential operations for running and managing Docker containers.
Running Your First Container
The docker run command creates and starts a new container from an image:
# Basic syntax
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# Run nginx
docker run nginx
# Run with a custom command
docker run alpine echo "Hello, Docker!"
Common Run Options
| Option | Description | Example |
|---|---|---|
-d |
Run in detached mode (background) | docker run -d nginx |
-p |
Map ports (host:container) | docker run -p 8080:80 nginx |
--name |
Assign a name | docker run --name web nginx |
-e |
Set environment variables | docker run -e DEBUG=true app |
-v |
Mount volumes | docker run -v /data:/app/data app |
--rm |
Remove container when it exits | docker run --rm alpine echo "hi" |
-it |
Interactive with TTY | docker run -it alpine sh |
Practical Examples
# Run a web server in the background, accessible on port 8080
docker run -d -p 8080:80 --name my-nginx nginx
# Run an interactive shell
docker run -it --name my-alpine alpine sh
# Run with environment variables
docker run -d -e MYSQL_ROOT_PASSWORD=secret --name my-mysql mysql:8
# Run with automatic cleanup
docker run --rm alpine cat /etc/os-release
Container Lifecycle
Understanding the container lifecycle is essential for effective management:
stateDiagram-v2
[*] --> Created: docker create
Created --> Running: docker start
Running --> Paused: docker pause
Paused --> Running: docker unpause
Running --> Stopped: docker stop
Stopped --> Running: docker start
Running --> Stopped: docker kill
Stopped --> Deleted: docker rm
Deleted --> [*]
Lifecycle Commands
# Create without starting
docker create --name my-container nginx
# Start a created or stopped container
docker start my-container
# Stop a running container (graceful)
docker stop my-container
# Kill a container (immediate)
docker kill my-container
# Restart a container
docker restart my-container
# Pause/unpause
docker pause my-container
docker unpause my-container
# Remove a stopped container
docker rm my-container
# Force remove a running container
docker rm -f my-container
Listing Containers
View Running Containers
# List running containers
docker ps
# Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 nginx "/docker-entrypoint.…" 10 minutes ago Up 10 minutes 0.0.0.0:8080->80/tcp my-nginx
View All Containers
# List all containers (including stopped)
docker ps -a
# Show only container IDs
docker ps -q
# Show latest created container
docker ps -l
# Filter containers
docker ps -f "status=exited"
docker ps -f "name=my-"
# Custom format output
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
Understanding Status
| Status | Description |
|---|---|
Created |
Container created but never started |
Up X minutes |
Container is running |
Exited (0) |
Container stopped successfully |
Exited (1) |
Container stopped with error |
Paused |
Container is paused |
Restarting |
Container is restarting |
Container Logs
Logs are essential for debugging and monitoring:
# View all logs
docker logs my-nginx
# Follow logs in real-time
docker logs -f my-nginx
# Show last N lines
docker logs --tail 100 my-nginx
# Show logs with timestamps
docker logs -t my-nginx
# Show logs since a specific time
docker logs --since 2025-01-18T10:00:00 my-nginx
docker logs --since 30m my-nginx
# Combine options
docker logs -f --tail 50 -t my-nginx
Logging Drivers
Docker supports different logging drivers:
# Run with a specific logging driver
docker run -d --log-driver json-file --log-opt max-size=10m nginx
# Check the logging driver
docker inspect --format='{{.HostConfig.LogConfig.Type}}' my-nginx
| Driver | Description |
|---|---|
json-file |
Default, stores logs as JSON |
syslog |
Writes to syslog |
journald |
Writes to systemd journal |
fluentd |
Sends to Fluentd |
awslogs |
Sends to AWS CloudWatch |
none |
Disables logging |
Executing Commands in Containers
The docker exec command runs commands in a running container:
# Execute a single command
docker exec my-nginx cat /etc/nginx/nginx.conf
# Start an interactive shell
docker exec -it my-nginx bash
docker exec -it my-nginx sh # For Alpine-based images
# Execute as a specific user
docker exec -u root my-nginx whoami
# Set environment variables for the command
docker exec -e MY_VAR=value my-nginx env
# Set working directory
docker exec -w /var/log my-nginx ls
Common Use Cases
# Check process list
docker exec my-nginx ps aux
# View environment variables
docker exec my-nginx env
# Debug network issues
docker exec my-nginx curl localhost
# Access database CLI
docker exec -it my-mysql mysql -u root -p
# Install debugging tools (temporary)
docker exec my-nginx apt-get update && apt-get install -y curl
Inspecting Containers
Get detailed information about containers:
# Full inspection (JSON output)
docker inspect my-nginx
# Get specific fields
docker inspect --format='{{.State.Status}}' my-nginx
docker inspect --format='{{.NetworkSettings.IPAddress}}' my-nginx
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-nginx
# Get environment variables
docker inspect --format='{{json .Config.Env}}' my-nginx | jq
# Get mounted volumes
docker inspect --format='{{json .Mounts}}' my-nginx | jq
Useful Inspect Queries
| Query | Output |
|---|---|
{{.State.Status}} |
Running status |
{{.State.StartedAt}} |
Start time |
{{.NetworkSettings.IPAddress}} |
Container IP |
{{.Config.Env}} |
Environment variables |
{{.HostConfig.Memory}} |
Memory limit |
{{.Mounts}} |
Volume mounts |
Viewing Container Processes
# View processes inside a container
docker top my-nginx
# Output:
UID PID PPID C STIME TTY TIME CMD
root 1234 1233 0 10:00 ? 00:00:00 nginx: master process
nginx 1235 1234 0 10:00 ? 00:00:00 nginx: worker process
Resource Usage Statistics
# View real-time resource usage
docker stats
# View stats for specific containers
docker stats my-nginx my-mysql
# View stats without streaming
docker stats --no-stream
# Custom format
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
abc123def456 my-nginx 0.00% 2.5MiB / 7.77GiB 0.03% 1.2kB / 1.1kB 0B / 0B
Copying Files
Copy files between containers and the host:
# Copy from container to host
docker cp my-nginx:/etc/nginx/nginx.conf ./nginx.conf
# Copy from host to container
docker cp ./custom.conf my-nginx:/etc/nginx/conf.d/
# Copy entire directories
docker cp my-nginx:/var/log/nginx/ ./logs/
# Copy to/from stopped containers (works too!)
docker cp stopped-container:/data ./backup/
Container Restart Policies
Configure automatic restart behavior:
# Always restart
docker run -d --restart always nginx
# Restart on failure only
docker run -d --restart on-failure nginx
# Restart on failure with max attempts
docker run -d --restart on-failure:5 nginx
# Restart unless manually stopped
docker run -d --restart unless-stopped nginx
| Policy | Description |
|---|---|
no |
Never restart (default) |
always |
Always restart |
on-failure |
Restart only on non-zero exit |
on-failure:N |
Restart on failure, max N times |
unless-stopped |
Like always, but respects manual stops |
Update Restart Policy
# Update policy for existing container
docker update --restart unless-stopped my-nginx
Attaching to Containers
# Attach to a running container's main process
docker attach my-nginx
# Detach without stopping: Ctrl+P, Ctrl+Q
Note: attach connects to the main process (PID 1). Use exec for a new shell.
Renaming Containers
docker rename old-name new-name
Bulk Operations
# Stop all running containers
docker stop $(docker ps -q)
# Remove all stopped containers
docker rm $(docker ps -aq -f "status=exited")
# Remove all containers (careful!)
docker rm -f $(docker ps -aq)
# System prune (remove unused data)
docker system prune
# Remove everything unused
docker system prune -a --volumes
Debugging with Docker Debug
For minimal images without shells:
# Start a debug session (Docker Desktop feature)
docker debug my-nginx
# Or use a debug container
docker run -it --rm --pid=container:my-nginx \
--net=container:my-nginx \
nicolaka/netshoot
Best Practices
1. Always Name Your Containers
# Good
docker run -d --name redis-cache redis
# Avoid auto-generated names
docker run -d redis # Gets random name like "eager_pike"
2. Use Restart Policies in Production
docker run -d --restart unless-stopped --name web nginx
3. Set Resource Limits
docker run -d \
--memory=512m \
--cpus=0.5 \
--name limited-app \
myapp
4. Clean Up Regularly
# Remove exited containers
docker container prune
# Remove with confirmation
docker container prune -f
Quick Reference Table
| Operation | Command |
|---|---|
| Run container | docker run -d --name NAME IMAGE |
| List running | docker ps |
| List all | docker ps -a |
| Stop container | docker stop NAME |
| Start container | docker start NAME |
| Restart | docker restart NAME |
| View logs | docker logs -f NAME |
| Execute command | docker exec -it NAME sh |
| Inspect | docker inspect NAME |
| View stats | docker stats NAME |
| Copy files | docker cp NAME:/path ./local |
| Remove | docker rm NAME |
Key Takeaways
-dfor background - Run containers detached for services-itfor interactive - Use for shells and debugging--rmfor temporary - Auto-cleanup for one-off commands- Use
exec, notattach-execstarts a new process,attachconnects to PID 1 - Set restart policies - Ensure services recover from failures
- Monitor with logs and stats - Essential for debugging and performance
Next Steps
In the next article, we'll learn how to create custom images using Dockerfiles - defining your own containers from scratch.
References
- Docker Deep Dive, 5th Edition - Nigel Poulton
- The Ultimate Docker Container Book, 3rd Edition - Dr. Gabriel N. Schenker
- Docker CLI Reference