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
- Installation & Version
- Docker Images
- Docker Containers
- Dockerfile Reference
- Docker Compose
- Networking
- Volumes & Data Persistence
- Docker Registry
- Cleaning & Maintenance
- Debugging & Logs
- Best Practices
- Common Pitfalls
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 π§
# Check Docker versiondocker --version# β Docker version 24.0.7
# Detailed version informationdocker 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 informationdocker info# Shows containers, images, storage driver, etc.
# Test Docker installationdocker run hello-world# Downloads and runs hello-world imagePlatform-Specific Installation π¦
# Ubuntu/Debiancurl -fsSL https://get.docker.com -o get-docker.shsudo 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 installationdocker run hello-worldVersion Management π
# Check Docker Engine versiondocker version --format '{{.Server.Version}}'# β 24.0.7
# Check Docker Compose versiondocker compose version --short# β v2.20.0
# Check Docker CLI versiondocker version --format '{{.Client.Version}}'# β 24.0.7
# View Docker system informationdocker system infoDocker Images
Basic Image Operations π₯
# List all imagesdocker imagesdocker image ls
# List images with filtersdocker images --filter "dangling=true" # Untagged imagesdocker images --filter "reference=nginx" # Specific imagedocker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
# Pull image from registrydocker pull nginxdocker pull nginx:1.25-alpine # Specific tagdocker pull nginx:latest # Latest tag (not recommended)
# Search Docker Hub for imagesdocker search postgresdocker search --limit 5 node # Limit results
# Remove imagedocker rmi nginx:latestdocker rmi image_iddocker rmi -f image_id # Force remove (even if in use)
# Remove multiple imagesdocker rmi image1 image2 image3docker rmi $(docker images -q) # Remove all images
# Remove unused imagesdocker image prune # Dangling images onlydocker image prune -a # All unused imagesdocker image prune -a --filter "until=24h" # Older than 24hBuilding Images ποΈ
# Build image from Dockerfiledocker build -t myapp:1.0 .docker build -t myapp:latest -t myapp:1.0 . # Multiple tags
# Build with specific Dockerfiledocker build -f Dockerfile.prod -t myapp:prod .
# Build with no cachedocker build --no-cache -t myapp:1.0 .
# Build with build argumentsdocker 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 outputdocker build --progress=plain -t myapp .docker build --progress=json -t myapp . # JSON output
# Tag an imagedocker tag myapp:1.0 username/myapp:1.0docker tag myapp:1.0 registry.example.com/myapp:1.0
# View image history/layersdocker history myapp:1.0docker history --no-trunc myapp:1.0 # Full command output
# Inspect image detailsdocker inspect nginxdocker inspect --format='{{.Config.Env}}' nginx # Specific fielddocker inspect --format='{{json .Config}}' nginx | jq # Pretty JSONImage Size Optimization π
# Compare image sizesdocker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
# Analyze image layersdocker history myapp:1.0 --human --format "{{.CreatedBy}}"
# Export image to tar filedocker save -o myapp.tar myapp:1.0docker save myapp:1.0 | gzip > myapp.tar.gz
# Load image from tar filedocker load -i myapp.tardocker load < myapp.tar.gz
# Image size comparison table| Base Image | Size | Use Case |
|---|---|---|
alpine:latest | ~5 MB | Minimal base, production |
node:20-alpine | ~170 MB | Node.js applications |
node:20 | ~1 GB | Node.js with full Debian |
ubuntu:22.04 | ~77 MB | General purpose Linux |
python:3.11-slim | ~125 MB | Python applications |
postgres:15-alpine | ~200 MB | PostgreSQL database |
nginx:alpine | ~40 MB | Web server |
Docker Containers
Running Containers π
# Run container in foregrounddocker run nginx
# Run in detached mode (background)docker run -d nginx
# Run with custom namedocker run -d --name my-nginx nginx
# Run with port mappingdocker run -d -p 8080:80 nginxdocker run -d -p 127.0.0.1:8080:80 nginx # Bind to specific interfacedocker run -d -p 8080:80/tcp nginx # Specify protocol
# Run with environment variablesdocker run -d -e MYSQL_ROOT_PASSWORD=secret mysqldocker run -d -e VAR1=value1 -e VAR2=value2 nginxdocker run -d --env-file .env nginx # From file
# Run with volume mountdocker run -d -v /host/path:/container/path nginxdocker run -d -v $(pwd):/app node:20docker run -d -v my-volume:/app/data nginx # Named volume
# Run interactively with TTYdocker run -it ubuntu bashdocker run -it --rm ubuntu bash # Auto-remove on exit
# Run with automatic removaldocker run --rm alpine echo "Hello World"
# Run with resource limitsdocker run -d --memory="512m" --cpus="1.5" nginxdocker run -d --memory-swap="1g" --cpus="2.0" nginx
# Run with restart policydocker run -d --restart=always nginxdocker run -d --restart=unless-stopped nginxdocker run -d --restart=on-failure:5 nginx # Max 5 restarts
# Run with networkdocker run -d --network my-network nginxdocker run -d --network host nginx # Use host network
# Run with read-only filesystemdocker run -d --read-only --tmpfs /tmp nginxContainer Management π
# List running containersdocker ps
# List all containers (including stopped)docker ps -a
# List containers with filtersdocker ps --filter "status=exited"docker ps --filter "name=nginx"docker ps --filter "ancestor=nginx:latest"
# List container IDs onlydocker ps -qdocker ps -aq # All containers
# Stop containerdocker stop container_namedocker stop container_iddocker stop $(docker ps -q) # Stop all running
# Stop with timeout (default 10s)docker stop -t 30 container_name # 30 second timeout
# Start stopped containerdocker start container_namedocker start container_id
# Restart containerdocker restart container_name
# Pause/Unpause containerdocker pause container_namedocker unpause container_name
# Remove containerdocker rm container_namedocker rm -f container_name # Force remove running containerdocker rm $(docker ps -aq) # Remove all containers
# Remove stopped containersdocker container prunedocker container prune -f # No confirmation promptContainer Interaction π
# Execute command in running containerdocker exec container_name ls /appdocker exec container_name cat /etc/hosts
# Open interactive shelldocker exec -it container_name bashdocker exec -it container_name sh # For Alpine-based imagesdocker exec -it container_name /bin/sh
# Execute as specific userdocker exec -it --user root container_name bashdocker exec -it --user 1000 container_name sh
# Copy files from container to hostdocker cp container_name:/path/to/file.txt ./local/path/docker cp container_name:/app/dist ./local/dist
# Copy files from host to containerdocker cp ./local/file.txt container_name:/path/to/docker cp ./local/folder container_name:/app/
# View container processesdocker top container_namedocker top container_name aux # With aux flags
# View real-time statsdocker statsdocker stats container_namedocker stats --no-stream # One-time snapshotdocker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# Inspect container detailsdocker inspect container_namedocker inspect --format='{{.State.Status}}' container_namedocker inspect --format='{{.NetworkSettings.IPAddress}}' container_namedocker inspect --format='{{json .Config}}' container_name | jq
# View container logsdocker logs container_namedocker logs -f container_name # Follow logsdocker logs --tail 100 container_name # Last 100 linesdocker logs --since 10m container_name # Last 10 minutesdocker logs --until 2023-01-01T00:00:00 container_name # Until timestampDockerfile Reference
Basic Dockerfile Structure π
# Specify base image (use specific tags, not 'latest')FROM node:20-alpine
# Set metadata labelsLABEL maintainer="dev@example.com"LABEL version="1.0"LABEL description="My application"
# Set working directoryWORKDIR /app
# Copy package files first (better layer caching)COPY package*.json ./
# Install dependenciesRUN npm ci --only=production
# Copy application codeCOPY . .
# Expose ports (documentation only, doesn't publish)EXPOSE 3000
# Set environment variablesENV NODE_ENV=productionENV 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: BuildFROM node:20 AS builder
WORKDIR /app
# Copy package filesCOPY package*.json ./RUN npm ci
# Copy source and buildCOPY . .RUN npm run build
# Stage 2: ProductionFROM node:20-alpine
# Install security updatesRUN apk upgrade --no-cache
WORKDIR /app
# Copy only necessary files from builderCOPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/package*.json ./
# Create non-root userRUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001
# Change ownershipRUN chown -R nodejs:nodejs /app
# Switch to non-root userUSER nodejs
# Expose portEXPOSE 3000
# Health checkHEALTHCHECK --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 applicationCMD ["node", "dist/server.js"]Dockerfile Instructions Reference π
| Instruction | Description | Example |
|---|---|---|
FROM | Base image | FROM ubuntu:22.04 |
RUN | Execute command (build-time) | RUN apt-get update && apt-get install -y curl |
CMD | Default command (runtime, can be overridden) | CMD ["nginx", "-g", "daemon off;"] |
ENTRYPOINT | Executable (runtime, not easily overridden) | ENTRYPOINT ["docker-entrypoint.sh"] |
COPY | Copy files (preferred) | COPY . /app |
ADD | Copy + extract archives | ADD files.tar.gz /app |
ENV | Set environment variable | ENV NODE_ENV=production |
ARG | Build-time variable | ARG VERSION=1.0 |
WORKDIR | Set working directory | WORKDIR /app |
EXPOSE | Document port | EXPOSE 8080 |
VOLUME | Mount point | VOLUME /data |
USER | Set user | USER nodejs |
LABEL | Metadata | LABEL version="1.0" |
HEALTHCHECK | Health check command | HEALTHCHECK CMD curl -f http://localhost/health |
Advanced Dockerfile Patterns π§
# Using build argumentsARG NODE_VERSION=20ARG BUILD_DATEFROM node:${NODE_VERSION}-alpine
# Multi-line RUN for better cachingRUN apk add --no-cache \ git \ curl \ python3 \ make \ g++ && \ npm install -g pm2 && \ apk del git
# Conditional execution with ARGARG BUILD_ENV=productionRUN if [ "$BUILD_ENV" = "development" ]; then \ npm install -g nodemon; \ fi
# Copy with exclusion patternsCOPY package*.json ./COPY src/ ./src/COPY public/ ./public/# Use .dockerignore for better exclusions
# Using ONBUILD for reusable imagesONBUILD COPY package*.json ./ONBUILD RUN npm installONBUILD COPY . .
# Combining CMD and ENTRYPOINTENTRYPOINT ["docker-entrypoint.sh"]CMD ["server"]# docker run myapp β docker-entrypoint.sh server# docker run myapp worker β docker-entrypoint.sh workerDocker 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: localDocker Compose Commands π οΈ
# Start services (foreground)docker compose up
# Start services in detached modedocker compose up -d
# Start specific servicesdocker compose up web api
# Build and startdocker compose up --build
# Build without cachedocker compose build --no-cache
# Stop servicesdocker compose down
# Stop and remove volumesdocker compose down -v
# Stop and remove everything (including images)docker compose down --rmi all
# View running servicesdocker compose ps
# View logsdocker compose logsdocker compose logs -f # Follow logsdocker compose logs api # Specific servicedocker compose logs --tail=100 api # Last 100 lines
# Execute command in servicedocker compose exec api bashdocker compose exec -u root api sh
# Restart servicesdocker compose restartdocker compose restart api # Specific service
# Scale servicesdocker compose up -d --scale api=3
# Validate compose filedocker compose configdocker compose config --services # List servicesdocker compose config --volumes # List volumes
# Pull imagesdocker compose pull
# View resource usagedocker compose topReal-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 π
# List networksdocker network ls
# Create a networkdocker network create my-networkdocker network create --driver bridge my-bridge-networkdocker network create --subnet=172.20.0.0/16 my-networkdocker network create --ip-range=172.20.240.0/20 my-network
# Inspect networkdocker network inspect my-networkdocker network inspect --format='{{.IPAM.Config}}' my-network
# Connect container to networkdocker network connect my-network container_name
# Disconnect container from networkdocker network disconnect my-network container_name
# Remove networkdocker network rm my-network
# Remove all unused networksdocker network prunedocker network prune -f # No confirmation
# List containers in networkdocker network inspect my-network --format='{{range .Containers}}{{.Name}} {{end}}'Network Drivers π‘
| Driver | Description | Use Case |
|---|---|---|
bridge | Default, isolated network | Single host containers |
host | Shares host networking | High performance, low isolation |
overlay | Multi-host networking | Docker Swarm clusters |
macvlan | Assigns MAC address | Legacy app integration |
none | No networking | Maximum isolation |
ipvlan | L3 mode networking | Network performance |
Container Communication Example π
# Create custom networkdocker network create app-network
# Run database on custom networkdocker 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 containerdocker exec my-app ping postgres-dbdocker exec my-app curl http://postgres-db:5432Port Mapping Examples π
# Map single portdocker run -d -p 8080:80 nginx
# Map to specific interfacedocker run -d -p 127.0.0.1:8080:80 nginx
# Map multiple portsdocker run -d -p 8080:80 -p 8443:443 nginx
# Map UDP portdocker run -d -p 53:53/udp dns-server
# Publish all exposed ports to random host portsdocker run -d -P nginx
# View port mappingsdocker port container_nameVolumes & Data Persistence
Volume Commands πΎ
# Create a volumedocker volume create my-volumedocker volume create --driver local my-volumedocker volume create --opt type=none --opt device=/path --opt o=bind my-volume
# List volumesdocker volume ls
# Inspect volumedocker volume inspect my-volumedocker volume inspect --format='{{.Mountpoint}}' my-volume
# Remove volumedocker volume rm my-volume
# Remove all unused volumesdocker volume prunedocker volume prune -f # No confirmation
# Backup volumedocker run --rm \ -v my-volume:/data \ -v $(pwd):/backup \ alpine tar czf /backup/backup.tar.gz -C /data .
# Restore volumedocker run --rm \ -v my-volume:/data \ -v $(pwd):/backup \ alpine tar xzf /backup/backup.tar.gz -C /dataVolume Types π¦
# 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 nginxdocker run -d -v $(pwd):/app node:20
# Anonymous volumedocker run -d -v /app/data nginx
# Read-only volumedocker run -d -v my-volume:/app/data:ro nginx
# Volume with specific optionsdocker 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 nginxVolume vs Bind Mount Comparison π
| Feature | Named Volume | Bind Mount |
|---|---|---|
| Location | Docker managed | Host 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 π
# Backup volume to tar filedocker 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 backupdocker run --rm \ -v my-volume:/data \ -v $(pwd):/backup \ alpine sh -c "cd /data && tar xzf /backup/backup.tar.gz"
# Copy volume contentsdocker run --rm \ -v source-volume:/source \ -v dest-volume:/dest \ alpine sh -c "cp -a /source/. /dest/"
# List volume contentsdocker run --rm -v my-volume:/data alpine ls -la /dataDocker Registry
Docker Hub π
# Login to Docker Hubdocker logindocker login -u username -p password # Not recommended (password in history)
# Tag image for Docker Hubdocker tag myapp:latest username/myapp:latestdocker tag myapp:latest username/myapp:1.0docker tag myapp:latest username/myapp:v1.0.0
# Push image to Docker Hubdocker push username/myapp:latestdocker push username/myapp:1.0
# Pull from Docker Hubdocker pull username/myapp:latestdocker pull username/myapp:1.0
# Logoutdocker logoutPrivate Registry π
# Run local registrydocker run -d -p 5000:5000 --name registry registry:2
# Run registry with authenticationdocker 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 registrydocker tag myapp:latest localhost:5000/myapp:latestdocker tag myapp:latest registry.example.com:5000/myapp:latest
# Push to private registrydocker push localhost:5000/myapp:latest
# Pull from private registrydocker pull localhost:5000/myapp:latest
# Login to private registrydocker login localhost:5000docker login registry.example.com:5000Image Tagging Best Practices π·οΈ
# Semantic versioningdocker tag myapp:latest myapp:1.0.0docker tag myapp:latest myapp:1.0docker tag myapp:latest myapp:1
# Git commit SHAdocker tag myapp:latest myapp:$(git rev-parse --short HEAD)
# Build numberdocker tag myapp:latest myapp:build-123
# Environment tagsdocker tag myapp:latest myapp:productiondocker tag myapp:latest myapp:stagingdocker tag myapp:latest myapp:developmentCleaning & Maintenance
Remove Commands π§Ή
# Remove all stopped containersdocker container prunedocker container prune -f # No confirmation
# Remove all unused imagesdocker image prunedocker image prune -a # Including tagged imagesdocker image prune -a --filter "until=24h" # Older than 24h
# Remove all unused volumesdocker volume prunedocker volume prune -f
# Remove all unused networksdocker network prunedocker network prune -f
# Remove everything (β οΈ DANGEROUS!)docker system prune # Containers, networks, images (dangling), build cachedocker system prune -a # Everything including tagged imagesdocker system prune -a --volumes # Including volumes
# View disk usagedocker system dfdocker system df -v # Detailed view
# Remove specific resourcesdocker 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 containersecho "Removing stopped containers..."docker container prune -f
# Remove dangling imagesecho "Removing dangling images..."docker image prune -f
# Remove unused volumes (be careful!)echo "Removing unused volumes..."docker volume prune -f
# Remove unused networksecho "Removing unused networks..."docker network prune -f
# Remove build cacheecho "Removing build cache..."docker builder prune -f
echo "β
Cleanup complete!"docker system dfMaintenance Best Practices β
# β
DO: Regular cleanupdocker system prune -a --volumes --filter "until=168h" # Weekly
# β
DO: Monitor disk usagedocker system df
# β
DO: Remove unused images periodicallydocker 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 tooDebugging & Logs
Viewing Logs π
# View container logsdocker logs container_name
# Follow logs in real-timedocker logs -f container_name
# Show last N linesdocker logs --tail 100 container_name
# Show logs since timestampdocker logs --since 2023-01-01T00:00:00 container_namedocker logs --since 10m container_name # Last 10 minutesdocker logs --since 1h container_name # Last hour
# Show logs until timestampdocker logs --until 2023-01-01T00:00:00 container_name
# Show logs with timestampsdocker logs -t container_name
# Docker Compose logsdocker compose logsdocker compose logs -f apidocker compose logs --tail=100 apiDebugging Commands π
# Check container processesdocker top container_namedocker top container_name aux
# View real-time resource usagedocker statsdocker stats container_namedocker stats --no-stream # One-time snapshotdocker stats --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# Inspect container (full JSON)docker inspect container_name
# Get specific value from inspectdocker inspect --format='{{.State.Status}}' container_namedocker inspect --format='{{.NetworkSettings.IPAddress}}' container_namedocker inspect --format='{{.Config.Env}}' container_namedocker inspect --format='{{json .Mounts}}' container_name | jq
# Check container changesdocker diff container_name# Shows: A (Added), D (Deleted), C (Changed)
# View port mappingsdocker port container_name
# Check health statusdocker inspect --format='{{.State.Health.Status}}' container_name
# View container eventsdocker eventsdocker events --filter container=container_nameTroubleshooting Common Issues π§
# Container immediately exits - check logsdocker logs container_name
# Container exits with code - check exit codedocker inspect --format='{{.State.ExitCode}}' container_name
# Permission issues - check userdocker exec container_name whoamidocker exec container_name iddocker exec container_name ls -la /path
# Network connectivity - test from inside containerdocker exec container_name ping google.comdocker exec container_name curl http://api:3000docker exec container_name nslookup api
# Volume mount issues - verify pathsdocker inspect -f '{{.Mounts}}' container_namedocker inspect -f '{{json .Mounts}}' container_name | jq
# Resource constraints - check limitsdocker inspect -f '{{.HostConfig.Memory}}' container_namedocker inspect -f '{{.HostConfig.CpuShares}}' container_namedocker stats container_name
# Check if container is runningdocker ps --filter "name=container_name"
# View container environment variablesdocker exec container_name env
# Check DNS resolutiondocker exec container_name cat /etc/resolv.confBest Practices
Dockerfile Best Practices β
# β
DO: Use specific tags, not "latest"FROM node:20.11-alpine
# β
DO: Use multi-stage builds for smaller imagesFROM node:20 AS builder# ... build stepsFROM node:20-alpine AS production# ... production steps
# β
DO: Minimize layers by combining RUN commandsRUN 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*.logdistcoverage.DS_Store
# β
DO: Run as non-root userRUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001USER nodejs
# β
DO: Copy package files separately for better cachingCOPY package*.json ./RUN npm ci --only=productionCOPY . .
# β
DO: Use COPY instead of ADD (unless extracting archives)COPY . /app
# β
DO: Set working directoryWORKDIR /app
# β
DO: Use ARG for build-time variablesARG NODE_VERSION=20FROM node:${NODE_VERSION}-alpine
# β
DO: Document exposed portsEXPOSE 3000
# β
DO: Use exec form of CMD/ENTRYPOINTCMD ["node", "server.js"]ENTRYPOINT ["docker-entrypoint.sh"]
# β
DO: Add health checksHEALTHCHECK --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 metadataLABEL maintainer="dev@example.com"LABEL version="1.0"LABEL description="My application"Common Mistakes to Avoid β
# β DON'T: Use "latest" tagFROM node:latest # Breaks reproducibility
# β DON'T: Run as root (security risk)# (No USER specified = runs as root)
# β DON'T: Install unnecessary packagesRUN 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 DockerfileENV API_KEY=secret123 # Never do this!ENV DB_PASSWORD=password # Use secrets management instead
# β DON'T: Use separate RUN commands unnecessarilyRUN apt-get updateRUN apt-get install -y package1RUN apt-get install -y package2# Combine these!
# β DON'T: Copy everything before installing dependenciesCOPY . .RUN npm install # Breaks layer caching
# β DON'T: Use shell form for CMDCMD node server.js # Won't handle signals properly
# β DON'T: Expose unnecessary portsEXPOSE 3000 8080 9000 # Only expose what's needed
# β DON'T: Leave build artifacts in final imageRUN npm run build# Remove source files after build in multi-stageSecurity 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 DockerfileFROM node:20-alpine AS builder
# Install security updatesRUN apk upgrade --no-cache
WORKDIR /app
# Copy package files for better layer cachingCOPY package*.json ./RUN npm ci && \ npm cache clean --force
# Copy source codeCOPY . .
# Build applicationRUN npm run build
# Production stageFROM node:20-alpine
# Install dumb-init for proper signal handlingRUN apk add --no-cache dumb-init
# Create non-root userRUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001
WORKDIR /app
# Copy built app from builderCOPY --from=builder --chown=nodejs:nodejs /app/dist ./distCOPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modulesCOPY --from=builder --chown=nodejs:nodejs /app/package*.json ./
# Switch to non-root userUSER nodejs
# Expose portEXPOSE 3000
# Health checkHEALTHCHECK --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 properlyENTRYPOINT ["dumb-init", "--"]
# Start applicationCMD ["node", "dist/server.js"]Common Pitfalls
Problem: Container exits immediately β οΈ
# β Problem: Container stops right after startingdocker run myapp
# β
Solution 1: Check logsdocker logs container_name
# β
Solution 2: Run interactively to debugdocker 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 codedocker inspect --format='{{.State.ExitCode}}' container_nameProblem: Port already in use β οΈ
# β Problem: "Bind for 0.0.0.0:8080 failed: port is already allocated"
# β
Solution 1: Check what's using the portsudo lsof -i :8080netstat -tulpn | grep 8080# macOS: lsof -i :8080
# β
Solution 2: Use different host portdocker run -p 8081:80 nginx
# β
Solution 3: Stop conflicting containerdocker ps | grep 8080docker stop conflicting_container
# β
Solution 4: Find and stop container using portdocker ps --filter "publish=8080"Problem: βNo space left on deviceβ β οΈ
# β Problem: Build fails with disk space error
# β
Solution: Clean up Docker resourcesdocker system prune -a --volumes
# Check space before and afterdocker system df
# Remove specific large imagesdocker images --format "{{.Repository}}:{{.Tag}} {{.Size}}" | sort -k2 -h
# Remove old imagesdocker image prune -a --filter "until=168h" # Older than 1 weekProblem: Build cache issues β οΈ
# β Problem: Changes not reflected in image
# β
Solution 1: Rebuild without cachedocker build --no-cache -t myapp .
# β
Solution 2: Docker Compose rebuilddocker compose build --no-cache
# β
Solution 3: Clear build cachedocker builder prune
# β
Solution 4: Invalidate specific cache stagedocker build --target builder --no-cache -t myapp:builder .Problem: Cannot connect to Docker daemon β οΈ
# β Problem: "Cannot connect to the Docker daemon at unix:///var/run/docker.sock"
# β
Solution 1: Start Docker servicesudo systemctl start docker # Linux# macOS/Windows: Start Docker Desktop
# β
Solution 2: Add user to docker groupsudo usermod -aG docker $USER# Then logout and login again
# β
Solution 3: Check Docker is runningsudo systemctl status docker # Linux# macOS: Check Docker Desktop is running
# β
Solution 4: Check socket permissionsls -la /var/run/docker.sockProblem: DNS resolution fails in container β οΈ
# β Problem: "Could not resolve host" inside container
# β
Solution 1: Specify DNS serversdocker 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 containerdocker exec container_name cat /etc/resolv.confProblem: Permission denied errors β οΈ
# β Problem: Permission denied when accessing volumes
# β
Solution 1: Fix file ownershipdocker run -v $(pwd):/app --user $(id -u):$(id -g) myapp
# β
Solution 2: Use named volumes instead of bind mountsdocker run -v my-volume:/app/data myapp
# β
Solution 3: Run as specific user in DockerfileUSER 1000
# β
Solution 4: Check volume permissionsdocker exec container_name ls -la /app/dataQuick Command Reference
| Task | Command |
|---|---|
| Build image | docker build -t name:tag . |
| Run container | docker run -d -p 8080:80 image |
| Stop container | docker stop container |
| View logs | docker logs -f container |
| Enter container | docker exec -it container bash |
| List containers | docker ps -a |
| List images | docker images |
| Remove container | docker rm container |
| Remove image | docker rmi image |
| Clean system | docker system prune -a |
| Compose up | docker compose up -d |
| Compose down | docker compose down |
| View stats | docker stats |
| Inspect | docker inspect container |
| Copy files | docker cp container:/path ./local |
| View port | docker port container |
| Check health | docker inspect --format='{{.State.Health.Status}}' container |
Additional Resources
- Official Documentation: https://docs.docker.com
- Docker Hub: https://hub.docker.com
- Best Practices Guide: https://docs.docker.com/develop/dev-best-practices
- Dockerfile Reference: https://docs.docker.com/engine/reference/builder
- Docker Compose Docs: https://docs.docker.com/compose
- Security Best Practices: https://docs.docker.com/engine/security