1 min read #devops
On this page

Docker Operations Manual

Docker is a Linux container runtime. Core concepts: image (read-only template), container (running instance of an image), volume (persistent storage), network (inter-container communication), compose (multi-container orchestration).

Containers

# List containers
docker ps                               # Running only
docker ps -a                            # All (including stopped)
docker ps -a --format '{{.ID}} {{.Names}} {{.Status}}'  # Custom columns
docker ps -q                            # Output only IDs (for scripts)

# Run
docker run -d --name myapp \
  -p 8080:80 \                          # host:8080 → container:80
  -v /data:/app/data \                  # host directory → container directory
  -v app_data:/app/storage \            # named volume → container directory
  -e DATABASE_URL=postgres://... \      # environment variable
  --restart unless-stopped \            # auto-restart policy
  --network mynet \                     # join specified network
  --memory 512m \                       # memory limit
  image:tag

# Restart policies:
#   no:              Do not auto-restart (default)
#   on-failure[:N]:  Restart if exit code is non-zero (optional: max N times)
#   unless-stopped:   Always restart unless manually stopped (also applies after dockerd restart)
#   always:           Always restart under any circumstances

# Lifecycle
docker stop myapp                       # SIGTERM → wait 10s → SIGKILL
docker stop -t 30 myapp                 # Wait 30s
docker kill myapp                       # Direct SIGKILL
docker restart myapp
docker rm myapp                         # Remove stopped container
docker rm -f myapp                      # Force remove (even if running)
docker container prune                  # Remove all stopped containers
docker container prune --filter "until=24h"  # Remove only those stopped more than 24h ago

# Debugging
docker logs myapp --tail 100 -f         # Logs (stdout/stderr)
docker logs myapp --since 5m            # Last 5 minutes
docker inspect myapp | jq '.[0].State'  # Full state (PID, ExitCode, Mounts, ...)
docker inspect myapp | jq '.[0].NetworkSettings.IPAddress'
docker exec -it myapp sh                # Enter container shell
docker exec myapp cat /etc/resolv.conf  # Single command execution
docker top myapp                        # Processes inside container (host perspective)
docker stats --no-stream                # CPU/Mem snapshot
docker cp myapp:/app/config.yml ./      # Copy file from container

# Commit current container state as a new image (for debugging, not standard deployment)
docker commit myapp myapp:debug

Images

docker images                            # Local images
docker images --format '{{.Repository}}:{{.Tag}} {{.Size}}'
docker pull alpine:3.20
docker tag alpine:3.20 myrepo/alpine:latest

docker rmi alpine:3.20                   # Remove (must have no containers referencing it)
docker image prune                       # Remove dangling (<none> tag) images
docker image prune -a                    # Remove all unused images
docker image prune -a --filter "until=7d"  # Keep images used in the last 7 days

# Transfer between machines (without registry)
docker save alpine:3.20 -o alpine.tar    # Export as tar
docker load -i alpine.tar                # Import
# Use case: When a machine behind a firewall cannot pull from Docker Hub, save on a machine that can, scp, then load

# View image layers
docker history alpine:3.20
docker image inspect alpine:3.20 | jq '.[0].RootFS.Layers'

Docker Compose

docker compose up -d                     # Start (detached)
docker compose up -d --build            # Rebuild and start
docker compose down                      # Stop and remove containers/networks
docker compose down -v                   # Also remove volumes (data loss!)
docker compose restart                   # Restart all containers
docker compose restart nginx             # Restart a single service
docker compose logs -f --tail=50
docker compose ps
docker compose exec app sh              # Enter service container
docker compose pull                      # Pull latest images

Networks

docker network ls
docker network inspect bridge            # Default bridge network

# Custom bridge network (recommended: containers can access each other by name)
docker network create --driver bridge mynet
# → Built-in DNS: container names automatically resolve to IPs
# Default bridge does not have this feature; only IP-based access is possible

docker network connect mynet myapp       # Join network at runtime
docker network disconnect mynet myapp

Volumes

docker volume ls
docker volume inspect app_data           # Mountpoint = actual host path
docker volume prune                      # Remove unused volumes (data loss!)

Cleanup

# One-click cleanup of all unused resources (use with caution!)
docker system prune -a --volumes
# -a: includes unused images
# --volumes: includes unused volumes

# Check disk usage
docker system df
docker system df -v                      # Size of each object

Troubleshooting

# Container keeps restarting
docker logs myapp --tail=50              # Check logs before exit
docker inspect myapp | jq '.[0].State'    # ExitCode + Error

# DNS resolution fails inside container
docker exec myapp cat /etc/resolv.conf
# → Check dockerd startup parameter --dns
# → Check host /etc/docker/daemon.json: { "dns": ["8.8.8.8"] }

# Port conflict
ss -tlnp | grep <port>

# docker.sock permissions
sudo usermod -aG docker $USER           # Use docker without sudo (requires re-login)