Skip to main content

Docker Cheatsheet

Comprehensive quick reference for Docker commands, containerization, Dockerfile best practices, Docker Compose, networking, volumes, and production workflows. Essential guide for Docker 24+.

Table of Contents


Prerequisites

Docker Version: This cheatsheet targets Docker 24.0+ and Docker Compose v2.20+. Some commands may differ in older versions.

System Requirements:

  • Linux: Kernel 3.10+ (64-bit)
  • macOS: 10.15+ (Docker Desktop)
  • Windows: Windows 10/11 Pro, Enterprise, or Education (64-bit) with WSL 2

Prerequisites:

  • Basic command-line knowledge
  • Understanding of containerization concepts
  • Familiarity with Linux commands (for container operations)

Installation & Version

Installation Commands πŸ”§

Terminal window
# Check Docker version
docker --version
# β†’ Docker version 24.0.7
# Detailed version information
docker version
# Shows client and server versions
# Check Docker Compose version (v2 syntax)
docker compose version
# β†’ Docker Compose version v2.20.0
# Legacy Docker Compose (v1)
docker-compose --version
# Display system-wide Docker information
docker info
# Shows containers, images, storage driver, etc.
# Test Docker installation
docker run hello-world
# Downloads and runs hello-world image

Platform-Specific Installation πŸ“¦

Terminal window
# Ubuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Add user to docker group (avoid sudo)
sudo usermod -aG docker $USER
# Logout and login again for changes to take effect
# macOS (using Homebrew)
brew install --cask docker
# Windows (using Chocolatey)
choco install docker-desktop
# Verify installation
docker run hello-world

Version Management πŸ”„

Terminal window
# Check Docker Engine version
docker version --format '{{.Server.Version}}'
# β†’ 24.0.7
# Check Docker Compose version
docker compose version --short
# β†’ v2.20.0
# Check Docker CLI version
docker version --format '{{.Client.Version}}'
# β†’ 24.0.7
# View Docker system information
docker system info

Docker Images

Basic Image Operations πŸ“₯

Terminal window
# List all images
docker images
docker image ls
# List images with filters
docker images --filter "dangling=true" # Untagged images
docker images --filter "reference=nginx" # Specific image
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
# Pull image from registry
docker pull nginx
docker pull nginx:1.25-alpine # Specific tag
docker pull nginx:latest # Latest tag (not recommended)
# Search Docker Hub for images
docker search postgres
docker search --limit 5 node # Limit results
# Remove image
docker rmi nginx:latest
docker rmi image_id
docker rmi -f image_id # Force remove (even if in use)
# Remove multiple images
docker rmi image1 image2 image3
docker rmi $(docker images -q) # Remove all images
# Remove unused images
docker image prune # Dangling images only
docker image prune -a # All unused images
docker image prune -a --filter "until=24h" # Older than 24h

Building Images πŸ—οΈ

Terminal window
# Build image from Dockerfile
docker build -t myapp:1.0 .
docker build -t myapp:latest -t myapp:1.0 . # Multiple tags
# Build with specific Dockerfile
docker build -f Dockerfile.prod -t myapp:prod .
# Build with no cache
docker build --no-cache -t myapp:1.0 .
# Build with build arguments
docker build --build-arg NODE_VERSION=18 -t myapp .
docker build --build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') -t myapp .
# Build with target stage (multi-stage builds)
docker build --target builder -t myapp:builder .
# Build with progress output
docker build --progress=plain -t myapp .
docker build --progress=json -t myapp . # JSON output
# Tag an image
docker tag myapp:1.0 username/myapp:1.0
docker tag myapp:1.0 registry.example.com/myapp:1.0
# View image history/layers
docker history myapp:1.0
docker history --no-trunc myapp:1.0 # Full command output
# Inspect image details
docker inspect nginx
docker inspect --format='{{.Config.Env}}' nginx # Specific field
docker inspect --format='{{json .Config}}' nginx | jq # Pretty JSON

Image Size Optimization πŸ“Š

Terminal window
# Compare image sizes
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
# Analyze image layers
docker history myapp:1.0 --human --format "{{.CreatedBy}}"
# Export image to tar file
docker save -o myapp.tar myapp:1.0
docker save myapp:1.0 | gzip > myapp.tar.gz
# Load image from tar file
docker load -i myapp.tar
docker load < myapp.tar.gz
# Image size comparison table
Base ImageSizeUse Case
alpine:latest~5 MBMinimal base, production
node:20-alpine~170 MBNode.js applications
node:20~1 GBNode.js with full Debian
ubuntu:22.04~77 MBGeneral purpose Linux
python:3.11-slim~125 MBPython applications
postgres:15-alpine~200 MBPostgreSQL database
nginx:alpine~40 MBWeb server

Docker Containers

Running Containers πŸš€

Terminal window
# Run container in foreground
docker run nginx
# Run in detached mode (background)
docker run -d nginx
# Run with custom name
docker run -d --name my-nginx nginx
# Run with port mapping
docker run -d -p 8080:80 nginx
docker run -d -p 127.0.0.1:8080:80 nginx # Bind to specific interface
docker run -d -p 8080:80/tcp nginx # Specify protocol
# Run with environment variables
docker run -d -e MYSQL_ROOT_PASSWORD=secret mysql
docker run -d -e VAR1=value1 -e VAR2=value2 nginx
docker run -d --env-file .env nginx # From file
# Run with volume mount
docker run -d -v /host/path:/container/path nginx
docker run -d -v $(pwd):/app node:20
docker run -d -v my-volume:/app/data nginx # Named volume
# Run interactively with TTY
docker run -it ubuntu bash
docker run -it --rm ubuntu bash # Auto-remove on exit
# Run with automatic removal
docker run --rm alpine echo "Hello World"
# Run with resource limits
docker run -d --memory="512m" --cpus="1.5" nginx
docker run -d --memory-swap="1g" --cpus="2.0" nginx
# Run with restart policy
docker run -d --restart=always nginx
docker run -d --restart=unless-stopped nginx
docker run -d --restart=on-failure:5 nginx # Max 5 restarts
# Run with network
docker run -d --network my-network nginx
docker run -d --network host nginx # Use host network
# Run with read-only filesystem
docker run -d --read-only --tmpfs /tmp nginx

Container Management πŸ“‹

Terminal window
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# List containers with filters
docker ps --filter "status=exited"
docker ps --filter "name=nginx"
docker ps --filter "ancestor=nginx:latest"
# List container IDs only
docker ps -q
docker ps -aq # All containers
# Stop container
docker stop container_name
docker stop container_id
docker stop $(docker ps -q) # Stop all running
# Stop with timeout (default 10s)
docker stop -t 30 container_name # 30 second timeout
# Start stopped container
docker start container_name
docker start container_id
# Restart container
docker restart container_name
# Pause/Unpause container
docker pause container_name
docker unpause container_name
# Remove container
docker rm container_name
docker rm -f container_name # Force remove running container
docker rm $(docker ps -aq) # Remove all containers
# Remove stopped containers
docker container prune
docker container prune -f # No confirmation prompt

Container Interaction πŸ”

Terminal window
# Execute command in running container
docker exec container_name ls /app
docker exec container_name cat /etc/hosts
# Open interactive shell
docker exec -it container_name bash
docker exec -it container_name sh # For Alpine-based images
docker exec -it container_name /bin/sh
# Execute as specific user
docker exec -it --user root container_name bash
docker exec -it --user 1000 container_name sh
# Copy files from container to host
docker cp container_name:/path/to/file.txt ./local/path/
docker cp container_name:/app/dist ./local/dist
# Copy files from host to container
docker cp ./local/file.txt container_name:/path/to/
docker cp ./local/folder container_name:/app/
# View container processes
docker top container_name
docker top container_name aux # With aux flags
# View real-time stats
docker stats
docker stats container_name
docker stats --no-stream # One-time snapshot
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# Inspect container details
docker inspect container_name
docker inspect --format='{{.State.Status}}' container_name
docker inspect --format='{{.NetworkSettings.IPAddress}}' container_name
docker inspect --format='{{json .Config}}' container_name | jq
# View container logs
docker logs container_name
docker logs -f container_name # Follow logs
docker logs --tail 100 container_name # Last 100 lines
docker logs --since 10m container_name # Last 10 minutes
docker logs --until 2023-01-01T00:00:00 container_name # Until timestamp

Dockerfile Reference

Basic Dockerfile Structure πŸ“„

# Specify base image (use specific tags, not 'latest')
FROM node:20-alpine
# Set metadata labels
LABEL maintainer="dev@example.com"
LABEL version="1.0"
LABEL description="My application"
# Set working directory
WORKDIR /app
# Copy package files first (better layer caching)
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy application code
COPY . .
# Expose ports (documentation only, doesn't publish)
EXPOSE 3000
# Set environment variables
ENV NODE_ENV=production
ENV PORT=3000
# Define volumes (optional, better to use docker run -v)
VOLUME ["/app/data"]
# Set default command (exec form preferred)
CMD ["node", "server.js"]

Multi-Stage Build Example 🎯

# Stage 1: Build
FROM node:20 AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm ci
# Copy source and build
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:20-alpine
# Install security updates
RUN apk upgrade --no-cache
WORKDIR /app
# Copy only necessary files from builder
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# Change ownership
RUN chown -R nodejs:nodejs /app
# Switch to non-root user
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Start application
CMD ["node", "dist/server.js"]

Dockerfile Instructions Reference πŸ“š

InstructionDescriptionExample
FROMBase imageFROM ubuntu:22.04
RUNExecute command (build-time)RUN apt-get update && apt-get install -y curl
CMDDefault command (runtime, can be overridden)CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINTExecutable (runtime, not easily overridden)ENTRYPOINT ["docker-entrypoint.sh"]
COPYCopy files (preferred)COPY . /app
ADDCopy + extract archivesADD files.tar.gz /app
ENVSet environment variableENV NODE_ENV=production
ARGBuild-time variableARG VERSION=1.0
WORKDIRSet working directoryWORKDIR /app
EXPOSEDocument portEXPOSE 8080
VOLUMEMount pointVOLUME /data
USERSet userUSER nodejs
LABELMetadataLABEL version="1.0"
HEALTHCHECKHealth check commandHEALTHCHECK CMD curl -f http://localhost/health

Advanced Dockerfile Patterns πŸ”§

# Using build arguments
ARG NODE_VERSION=20
ARG BUILD_DATE
FROM node:${NODE_VERSION}-alpine
# Multi-line RUN for better caching
RUN apk add --no-cache \
git \
curl \
python3 \
make \
g++ && \
npm install -g pm2 && \
apk del git
# Conditional execution with ARG
ARG BUILD_ENV=production
RUN if [ "$BUILD_ENV" = "development" ]; then \
npm install -g nodemon; \
fi
# Copy with exclusion patterns
COPY package*.json ./
COPY src/ ./src/
COPY public/ ./public/
# Use .dockerignore for better exclusions
# Using ONBUILD for reusable images
ONBUILD COPY package*.json ./
ONBUILD RUN npm install
ONBUILD COPY . .
# Combining CMD and ENTRYPOINT
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["server"]
# docker run myapp β†’ docker-entrypoint.sh server
# docker run myapp worker β†’ docker-entrypoint.sh worker

Docker Compose

Basic docker-compose.yml 🎼

version: "3.8"
services:
web:
image: nginx:alpine
container_name: my-nginx
ports:
- "8080:80"
- "8443:443"
volumes:
- ./html:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
networks:
- app-network
depends_on:
- api
environment:
- NGINX_HOST=localhost
- NGINX_PORT=80
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
api:
build:
context: ./api
dockerfile: Dockerfile
args:
NODE_VERSION: 20
container_name: my-api
ports:
- "3000:3000"
volumes:
- ./api:/app
- /app/node_modules
networks:
- app-network
depends_on:
db:
condition: service_healthy
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- NODE_ENV=development
env_file:
- .env
restart: on-failure
deploy:
resources:
limits:
cpus: "1.5"
memory: 512M
reservations:
cpus: "0.5"
memory: 256M
db:
image: postgres:15-alpine
container_name: my-db
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
restart: always
networks:
app-network:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
volumes:
postgres-data:
driver: local

Docker Compose Commands πŸ› οΈ

Terminal window
# Start services (foreground)
docker compose up
# Start services in detached mode
docker compose up -d
# Start specific services
docker compose up web api
# Build and start
docker compose up --build
# Build without cache
docker compose build --no-cache
# Stop services
docker compose down
# Stop and remove volumes
docker compose down -v
# Stop and remove everything (including images)
docker compose down --rmi all
# View running services
docker compose ps
# View logs
docker compose logs
docker compose logs -f # Follow logs
docker compose logs api # Specific service
docker compose logs --tail=100 api # Last 100 lines
# Execute command in service
docker compose exec api bash
docker compose exec -u root api sh
# Restart services
docker compose restart
docker compose restart api # Specific service
# Scale services
docker compose up -d --scale api=3
# Validate compose file
docker compose config
docker compose config --services # List services
docker compose config --volumes # List volumes
# Pull images
docker compose pull
# View resource usage
docker compose top

Real-World MERN Stack Example πŸ—οΈ

version: "3.8"
services:
# React Frontend
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
target: development
ports:
- "3000:3000"
volumes:
- ./frontend:/app
- /app/node_modules
environment:
- REACT_APP_API_URL=http://localhost:5000
- CHOKIDAR_USEPOLLING=true
depends_on:
- backend
networks:
- app-network
# Node.js Backend
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "5000:5000"
volumes:
- ./backend:/app
- /app/node_modules
environment:
- MONGO_URI=mongodb://mongo:27017/myapp
- JWT_SECRET=${JWT_SECRET}
- NODE_ENV=development
depends_on:
mongo:
condition: service_healthy
networks:
- app-network
# MongoDB
mongo:
image: mongo:7
ports:
- "27017:27017"
volumes:
- mongo-data:/data/db
- mongo-config:/data/configdb
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_PASSWORD}
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
# Nginx Reverse Proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
depends_on:
- frontend
- backend
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
mongo-data:
mongo-config:

Networking

Network Commands 🌐

Terminal window
# List networks
docker network ls
# Create a network
docker network create my-network
docker network create --driver bridge my-bridge-network
docker network create --subnet=172.20.0.0/16 my-network
docker network create --ip-range=172.20.240.0/20 my-network
# Inspect network
docker network inspect my-network
docker network inspect --format='{{.IPAM.Config}}' my-network
# Connect container to network
docker network connect my-network container_name
# Disconnect container from network
docker network disconnect my-network container_name
# Remove network
docker network rm my-network
# Remove all unused networks
docker network prune
docker network prune -f # No confirmation
# List containers in network
docker network inspect my-network --format='{{range .Containers}}{{.Name}} {{end}}'

Network Drivers πŸ“‘

DriverDescriptionUse Case
bridgeDefault, isolated networkSingle host containers
hostShares host networkingHigh performance, low isolation
overlayMulti-host networkingDocker Swarm clusters
macvlanAssigns MAC addressLegacy app integration
noneNo networkingMaximum isolation
ipvlanL3 mode networkingNetwork performance

Container Communication Example πŸ”—

Terminal window
# Create custom network
docker network create app-network
# Run database on custom network
docker run -d \
--name postgres-db \
--network app-network \
-e POSTGRES_PASSWORD=secret \
postgres:15-alpine
# Run app on same network (can access db via hostname "postgres-db")
docker run -d \
--name my-app \
--network app-network \
-e DATABASE_URL=postgresql://postgres:secret@postgres-db:5432/mydb \
my-app:latest
# Test connectivity from container
docker exec my-app ping postgres-db
docker exec my-app curl http://postgres-db:5432

Port Mapping Examples πŸ”Œ

Terminal window
# Map single port
docker run -d -p 8080:80 nginx
# Map to specific interface
docker run -d -p 127.0.0.1:8080:80 nginx
# Map multiple ports
docker run -d -p 8080:80 -p 8443:443 nginx
# Map UDP port
docker run -d -p 53:53/udp dns-server
# Publish all exposed ports to random host ports
docker run -d -P nginx
# View port mappings
docker port container_name

Volumes & Data Persistence

Volume Commands πŸ’Ύ

Terminal window
# Create a volume
docker volume create my-volume
docker volume create --driver local my-volume
docker volume create --opt type=none --opt device=/path --opt o=bind my-volume
# List volumes
docker volume ls
# Inspect volume
docker volume inspect my-volume
docker volume inspect --format='{{.Mountpoint}}' my-volume
# Remove volume
docker volume rm my-volume
# Remove all unused volumes
docker volume prune
docker volume prune -f # No confirmation
# Backup volume
docker run --rm \
-v my-volume:/data \
-v $(pwd):/backup \
alpine tar czf /backup/backup.tar.gz -C /data .
# Restore volume
docker run --rm \
-v my-volume:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/backup.tar.gz -C /data

Volume Types πŸ“¦

Terminal window
# Named volume (recommended for production)
docker run -d -v my-volume:/app/data nginx
# Bind mount (local development)
docker run -d -v /host/path:/container/path nginx
docker run -d -v $(pwd):/app node:20
# Anonymous volume
docker run -d -v /app/data nginx
# Read-only volume
docker run -d -v my-volume:/app/data:ro nginx
# Volume with specific options
docker run -d -v my-volume:/app/data:ro,noexec,nosuid nginx
# Tmpfs mount (in-memory)
docker run -d --tmpfs /tmp:rw,noexec,nosuid,size=100m nginx

Volume vs Bind Mount Comparison πŸ“Š

FeatureNamed VolumeBind Mount
LocationDocker managedHost path
Portabilityβœ… High❌ Low
Performanceβœ… Optimized⚠️ Variable
Backupβœ… Easy⚠️ Manual
Dev Use⚠️ Limitedβœ… Hot reload
Productionβœ… Recommended❌ Not recommended
Permissionsβœ… Managed by Docker⚠️ Host permissions

Volume Backup & Restore πŸ”„

Terminal window
# Backup volume to tar file
docker run --rm \
-v my-volume:/data \
-v $(pwd):/backup \
alpine tar czf /backup/backup-$(date +%Y%m%d).tar.gz -C /data .
# Restore volume from backup
docker run --rm \
-v my-volume:/data \
-v $(pwd):/backup \
alpine sh -c "cd /data && tar xzf /backup/backup.tar.gz"
# Copy volume contents
docker run --rm \
-v source-volume:/source \
-v dest-volume:/dest \
alpine sh -c "cp -a /source/. /dest/"
# List volume contents
docker run --rm -v my-volume:/data alpine ls -la /data

Docker Registry

Docker Hub πŸ“š

Terminal window
# Login to Docker Hub
docker login
docker login -u username -p password # Not recommended (password in history)
# Tag image for Docker Hub
docker tag myapp:latest username/myapp:latest
docker tag myapp:latest username/myapp:1.0
docker tag myapp:latest username/myapp:v1.0.0
# Push image to Docker Hub
docker push username/myapp:latest
docker push username/myapp:1.0
# Pull from Docker Hub
docker pull username/myapp:latest
docker pull username/myapp:1.0
# Logout
docker logout

Private Registry πŸ”’

Terminal window
# Run local registry
docker run -d -p 5000:5000 --name registry registry:2
# Run registry with authentication
docker run -d -p 5000:5000 \
--name registry \
-v $(pwd)/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
registry:2
# Tag for private registry
docker tag myapp:latest localhost:5000/myapp:latest
docker tag myapp:latest registry.example.com:5000/myapp:latest
# Push to private registry
docker push localhost:5000/myapp:latest
# Pull from private registry
docker pull localhost:5000/myapp:latest
# Login to private registry
docker login localhost:5000
docker login registry.example.com:5000

Image Tagging Best Practices 🏷️

Terminal window
# Semantic versioning
docker tag myapp:latest myapp:1.0.0
docker tag myapp:latest myapp:1.0
docker tag myapp:latest myapp:1
# Git commit SHA
docker tag myapp:latest myapp:$(git rev-parse --short HEAD)
# Build number
docker tag myapp:latest myapp:build-123
# Environment tags
docker tag myapp:latest myapp:production
docker tag myapp:latest myapp:staging
docker tag myapp:latest myapp:development

Cleaning & Maintenance

Remove Commands 🧹

Terminal window
# Remove all stopped containers
docker container prune
docker container prune -f # No confirmation
# Remove all unused images
docker image prune
docker image prune -a # Including tagged images
docker image prune -a --filter "until=24h" # Older than 24h
# Remove all unused volumes
docker volume prune
docker volume prune -f
# Remove all unused networks
docker network prune
docker network prune -f
# Remove everything (⚠️ DANGEROUS!)
docker system prune # Containers, networks, images (dangling), build cache
docker system prune -a # Everything including tagged images
docker system prune -a --volumes # Including volumes
# View disk usage
docker system df
docker system df -v # Detailed view
# Remove specific resources
docker rm $(docker ps -aq --filter "status=exited")
docker rmi $(docker images -q --filter "dangling=true")

Scheduled Cleanup Script 🎯

#!/bin/bash
# save as docker-cleanup.sh
echo "🧹 Starting Docker cleanup..."
# Remove stopped containers
echo "Removing stopped containers..."
docker container prune -f
# Remove dangling images
echo "Removing dangling images..."
docker image prune -f
# Remove unused volumes (be careful!)
echo "Removing unused volumes..."
docker volume prune -f
# Remove unused networks
echo "Removing unused networks..."
docker network prune -f
# Remove build cache
echo "Removing build cache..."
docker builder prune -f
echo "βœ… Cleanup complete!"
docker system df

Maintenance Best Practices βœ…

Terminal window
# βœ… DO: Regular cleanup
docker system prune -a --volumes --filter "until=168h" # Weekly
# βœ… DO: Monitor disk usage
docker system df
# βœ… DO: Remove unused images periodically
docker image prune -a --filter "until=72h"
# βœ… DO: Use specific tags instead of 'latest'
# Prevents accumulation of untagged images
# ❌ DON'T: Remove volumes without backup
# docker volume prune removes ALL unused volumes
# ❌ DON'T: Use --all flag without checking
# docker system prune -a removes tagged images too

Debugging & Logs

Viewing Logs πŸ›

Terminal window
# View container logs
docker logs container_name
# Follow logs in real-time
docker logs -f container_name
# Show last N lines
docker logs --tail 100 container_name
# Show logs since timestamp
docker logs --since 2023-01-01T00:00:00 container_name
docker logs --since 10m container_name # Last 10 minutes
docker logs --since 1h container_name # Last hour
# Show logs until timestamp
docker logs --until 2023-01-01T00:00:00 container_name
# Show logs with timestamps
docker logs -t container_name
# Docker Compose logs
docker compose logs
docker compose logs -f api
docker compose logs --tail=100 api

Debugging Commands πŸ”

Terminal window
# Check container processes
docker top container_name
docker top container_name aux
# View real-time resource usage
docker stats
docker stats container_name
docker stats --no-stream # One-time snapshot
docker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# Inspect container (full JSON)
docker inspect container_name
# Get specific value from inspect
docker inspect --format='{{.State.Status}}' container_name
docker inspect --format='{{.NetworkSettings.IPAddress}}' container_name
docker inspect --format='{{.Config.Env}}' container_name
docker inspect --format='{{json .Mounts}}' container_name | jq
# Check container changes
docker diff container_name
# Shows: A (Added), D (Deleted), C (Changed)
# View port mappings
docker port container_name
# Check health status
docker inspect --format='{{.State.Health.Status}}' container_name
# View container events
docker events
docker events --filter container=container_name

Troubleshooting Common Issues πŸ”§

Terminal window
# Container immediately exits - check logs
docker logs container_name
# Container exits with code - check exit code
docker inspect --format='{{.State.ExitCode}}' container_name
# Permission issues - check user
docker exec container_name whoami
docker exec container_name id
docker exec container_name ls -la /path
# Network connectivity - test from inside container
docker exec container_name ping google.com
docker exec container_name curl http://api:3000
docker exec container_name nslookup api
# Volume mount issues - verify paths
docker inspect -f '{{.Mounts}}' container_name
docker inspect -f '{{json .Mounts}}' container_name | jq
# Resource constraints - check limits
docker inspect -f '{{.HostConfig.Memory}}' container_name
docker inspect -f '{{.HostConfig.CpuShares}}' container_name
docker stats container_name
# Check if container is running
docker ps --filter "name=container_name"
# View container environment variables
docker exec container_name env
# Check DNS resolution
docker exec container_name cat /etc/resolv.conf

Best Practices

Dockerfile Best Practices βœ…

# βœ… DO: Use specific tags, not "latest"
FROM node:20.11-alpine
# βœ… DO: Use multi-stage builds for smaller images
FROM node:20 AS builder
# ... build steps
FROM node:20-alpine AS production
# ... production steps
# βœ… DO: Minimize layers by combining RUN commands
RUN apk add --no-cache git curl && \
npm install -g pm2 && \
apk del git && \
rm -rf /var/cache/apk/*
# βœ… DO: Use .dockerignore
# Create .dockerignore with:
node_modules
.git
.env
*.log
dist
coverage
.DS_Store
# βœ… DO: Run as non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
USER nodejs
# βœ… DO: Copy package files separately for better caching
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# βœ… DO: Use COPY instead of ADD (unless extracting archives)
COPY . /app
# βœ… DO: Set working directory
WORKDIR /app
# βœ… DO: Use ARG for build-time variables
ARG NODE_VERSION=20
FROM node:${NODE_VERSION}-alpine
# βœ… DO: Document exposed ports
EXPOSE 3000
# βœ… DO: Use exec form of CMD/ENTRYPOINT
CMD ["node", "server.js"]
ENTRYPOINT ["docker-entrypoint.sh"]
# βœ… DO: Add health checks
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# βœ… DO: Use LABEL for metadata
LABEL maintainer="dev@example.com"
LABEL version="1.0"
LABEL description="My application"

Common Mistakes to Avoid ❌

# ❌ DON'T: Use "latest" tag
FROM node:latest # Breaks reproducibility
# ❌ DON'T: Run as root (security risk)
# (No USER specified = runs as root)
# ❌ DON'T: Install unnecessary packages
RUN apt-get install -y vim emacs nano git curl wget
# ❌ DON'T: Forget .dockerignore
# Results in huge images with node_modules, .git, etc.
# ❌ DON'T: Put secrets in Dockerfile
ENV API_KEY=secret123 # Never do this!
ENV DB_PASSWORD=password # Use secrets management instead
# ❌ DON'T: Use separate RUN commands unnecessarily
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
# Combine these!
# ❌ DON'T: Copy everything before installing dependencies
COPY . .
RUN npm install # Breaks layer caching
# ❌ DON'T: Use shell form for CMD
CMD node server.js # Won't handle signals properly
# ❌ DON'T: Expose unnecessary ports
EXPOSE 3000 8080 9000 # Only expose what's needed
# ❌ DON'T: Leave build artifacts in final image
RUN npm run build
# Remove source files after build in multi-stage

Security Best Practices πŸ”’

⚠️ Security Checklist:

  • Never store secrets in images or Dockerfiles
  • Always run as non-root user
  • Use official images from trusted sources
  • Scan images for vulnerabilities: docker scan myapp:latest
  • Keep images updated with security patches
  • Use read-only filesystems when possible: --read-only
  • Limit resources: --memory, --cpus
  • Use secrets management: Docker secrets or environment variables from files
  • Minimize attack surface: Use Alpine or distroless images
  • Use multi-stage builds to exclude build tools from final image

Production-Ready Example πŸš€

# Production-ready Node.js Dockerfile
FROM node:20-alpine AS builder
# Install security updates
RUN apk upgrade --no-cache
WORKDIR /app
# Copy package files for better layer caching
COPY package*.json ./
RUN npm ci && \
npm cache clean --force
# Copy source code
COPY . .
# Build application
RUN npm run build
# Production stage
FROM node:20-alpine
# Install dumb-init for proper signal handling
RUN apk add --no-cache dumb-init
# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# Copy built app from builder
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
# Switch to non-root user
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Use dumb-init to handle signals properly
ENTRYPOINT ["dumb-init", "--"]
# Start application
CMD ["node", "dist/server.js"]

Common Pitfalls

Problem: Container exits immediately ⚠️

Terminal window
# ❌ Problem: Container stops right after starting
docker run myapp
# βœ… Solution 1: Check logs
docker logs container_name
# βœ… Solution 2: Run interactively to debug
docker run -it myapp bash
# βœ… Solution 3: Ensure app runs in foreground
# In Dockerfile, use: CMD ["node", "server.js"]
# NOT: CMD node server.js && tail -f /dev/null
# βœ… Solution 4: Check exit code
docker inspect --format='{{.State.ExitCode}}' container_name

Problem: Port already in use ⚠️

Terminal window
# ❌ Problem: "Bind for 0.0.0.0:8080 failed: port is already allocated"
# βœ… Solution 1: Check what's using the port
sudo lsof -i :8080
netstat -tulpn | grep 8080
# macOS: lsof -i :8080
# βœ… Solution 2: Use different host port
docker run -p 8081:80 nginx
# βœ… Solution 3: Stop conflicting container
docker ps | grep 8080
docker stop conflicting_container
# βœ… Solution 4: Find and stop container using port
docker ps --filter "publish=8080"

Problem: β€œNo space left on device” ⚠️

Terminal window
# ❌ Problem: Build fails with disk space error
# βœ… Solution: Clean up Docker resources
docker system prune -a --volumes
# Check space before and after
docker system df
# Remove specific large images
docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}" | sort -k2 -h
# Remove old images
docker image prune -a --filter "until=168h" # Older than 1 week

Problem: Build cache issues ⚠️

Terminal window
# ❌ Problem: Changes not reflected in image
# βœ… Solution 1: Rebuild without cache
docker build --no-cache -t myapp .
# βœ… Solution 2: Docker Compose rebuild
docker compose build --no-cache
# βœ… Solution 3: Clear build cache
docker builder prune
# βœ… Solution 4: Invalidate specific cache stage
docker build --target builder --no-cache -t myapp:builder .

Problem: Cannot connect to Docker daemon ⚠️

Terminal window
# ❌ Problem: "Cannot connect to the Docker daemon at unix:///var/run/docker.sock"
# βœ… Solution 1: Start Docker service
sudo systemctl start docker # Linux
# macOS/Windows: Start Docker Desktop
# βœ… Solution 2: Add user to docker group
sudo usermod -aG docker $USER
# Then logout and login again
# βœ… Solution 3: Check Docker is running
sudo systemctl status docker # Linux
# macOS: Check Docker Desktop is running
# βœ… Solution 4: Check socket permissions
ls -la /var/run/docker.sock

Problem: DNS resolution fails in container ⚠️

Terminal window
# ❌ Problem: "Could not resolve host" inside container
# βœ… Solution 1: Specify DNS servers
docker run --dns 8.8.8.8 --dns 8.8.4.4 myapp
# βœ… Solution 2: Docker Compose DNS configuration
# In docker-compose.yml:
services:
app:
dns:
- 8.8.8.8
- 8.8.4.4
# βœ… Solution 3: Use host network (not recommended)
docker run --network host myapp
# βœ… Solution 4: Check DNS config in container
docker exec container_name cat /etc/resolv.conf

Problem: Permission denied errors ⚠️

Terminal window
# ❌ Problem: Permission denied when accessing volumes
# βœ… Solution 1: Fix file ownership
docker run -v $(pwd):/app --user $(id -u):$(id -g) myapp
# βœ… Solution 2: Use named volumes instead of bind mounts
docker run -v my-volume:/app/data myapp
# βœ… Solution 3: Run as specific user in Dockerfile
USER 1000
# βœ… Solution 4: Check volume permissions
docker exec container_name ls -la /app/data

Quick Command Reference

TaskCommand
Build imagedocker build -t name:tag .
Run containerdocker run -d -p 8080:80 image
Stop containerdocker stop container
View logsdocker logs -f container
Enter containerdocker exec -it container bash
List containersdocker ps -a
List imagesdocker images
Remove containerdocker rm container
Remove imagedocker rmi image
Clean systemdocker system prune -a
Compose updocker compose up -d
Compose downdocker compose down
View statsdocker stats
Inspectdocker inspect container
Copy filesdocker cp container:/path ./local
View portdocker port container
Check healthdocker inspect --format='{{.State.Health.Status}}' container

Additional Resources