Containers & Kubernetes18 min

Docker — Commands & Compose Cheat Sheet

Complete Docker reference — images, containers, volumes, networks, Dockerfile best practices, docker compose, and registry commands.

Images

# Pull an image
docker pull nginx:latest
docker pull ubuntu:22.04

# List images
docker images
docker image ls

# Inspect image
docker image inspect nginx:latest

# Build from Dockerfile
docker build -t myapp:v1 .
docker build -t myapp:v1 -f Dockerfile.prod .
docker build --no-cache -t myapp:v1 .
docker build --build-arg ENV=prod -t myapp:v1 .

# Tag an image
docker tag myapp:v1 myregistry.io/myapp:v1
docker tag myapp:v1 myapp:latest

# Push to registry
docker push myregistry.io/myapp:v1

# Remove images
docker rmi nginx:latest
docker image prune               # Remove dangling images
docker image prune -a            # Remove all unused images

# Save/load image as tar
docker save myapp:v1 -o myapp.tar
docker load -i myapp.tar

# Export/import container filesystem
docker export container-id -o container.tar
docker import container.tar myapp:imported

Containers

# Run a container
docker run nginx                                # Foreground, attached
docker run -d nginx                             # Detached (background)
docker run -d -p 8080:80 nginx                  # Map host:container port
docker run -d -p 8080:80 --name webserver nginx # Named container
docker run -it ubuntu:22.04 /bin/bash          # Interactive shell
docker run --rm ubuntu echo "hello"             # Auto-remove after exit

# Common run flags
docker run \
  -d \                              # detached
  --name myapp \                    # container name
  -p 3000:3000 \                    # port mapping
  -e NODE_ENV=production \          # environment variable
  -v /host/path:/container/path \   # bind mount
  -v myvolume:/data \               # named volume
  --network my-network \            # attach to network
  --memory 512m \                   # memory limit
  --cpus 1.5 \                      # CPU limit
  --restart unless-stopped \        # restart policy
  myapp:v1

# Manage containers
docker ps                           # Running containers
docker ps -a                        # All containers
docker stop myapp                   # Graceful stop (SIGTERM, then SIGKILL)
docker kill myapp                   # Immediate kill (SIGKILL)
docker start myapp                  # Start stopped container
docker restart myapp
docker pause myapp                  # Freeze (SIGSTOP)
docker unpause myapp
docker rm myapp                     # Remove stopped container
docker rm -f myapp                  # Force remove running container
docker container prune              # Remove all stopped containers

# Logs
docker logs myapp                   # All logs
docker logs -f myapp                # Follow live
docker logs --tail 100 myapp        # Last 100 lines
docker logs --since 1h myapp        # Last hour

# Exec into container
docker exec -it myapp /bin/bash
docker exec -it myapp sh
docker exec myapp cat /etc/nginx/nginx.conf   # Non-interactive

# Inspect / stats
docker inspect myapp
docker stats                        # Live resource usage
docker stats --no-stream            # One-shot stats
docker top myapp                    # Processes inside container

# Copy files
docker cp myapp:/etc/nginx/nginx.conf ./nginx.conf
docker cp ./config.yaml myapp:/app/config.yaml

Volumes

# Named volumes (managed by Docker)
docker volume create mydata
docker volume ls
docker volume inspect mydata
docker volume rm mydata
docker volume prune               # Remove unused volumes

# Use named volume
docker run -d -v mydata:/var/lib/mysql mysql:8

# Bind mount (host directory)
docker run -d -v $(pwd)/data:/app/data myapp

# Read-only mount
docker run -d -v $(pwd)/config:/app/config:ro myapp

# tmpfs mount (in-memory, not persisted)
docker run -d --tmpfs /tmp:rw,size=256m myapp

Networks

# List networks
docker network ls

# Create network
docker network create my-net
docker network create --driver bridge my-net
docker network create --subnet 172.20.0.0/16 my-net

# Connect container to network
docker network connect my-net myapp
docker run -d --network my-net myapp

# Inspect network
docker network inspect my-net

# Disconnect
docker network disconnect my-net myapp

# Remove
docker network rm my-net
docker network prune              # Remove unused networks

# Containers on the same user-defined network can reach each other by name
docker run -d --name db --network my-net postgres
docker run -d --name app --network my-net -e DB_HOST=db myapp

Dockerfile Reference

# Minimal, production-ready Node.js example
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]

Key instructions:

FROM image[:tag]               # Base image
WORKDIR /path                  # Set working directory
COPY src dest                  # Copy from build context
ADD src dest                   # Like COPY but also extracts tar/URL
RUN command                    # Execute at build time (creates layer)
ENV KEY=value                  # Environment variable
ARG NAME=default               # Build-time argument
EXPOSE 8080                    # Document port (doesn't publish!)
VOLUME ["/data"]               # Declare volume mount point
USER username                  # Switch user for subsequent commands
ENTRYPOINT ["executable"]      # Container entrypoint (not overridden by args)
CMD ["arg1", "arg2"]           # Default command / args to ENTRYPOINT
HEALTHCHECK --interval=30s CMD curl -f http://localhost/ || exit 1
LABEL version="1.0" maintainer="ops@example.com"

Best practices:

  • Combine RUN commands to reduce layers
  • Put rarely-changing instructions (like COPY package.json) early for cache
  • Use multi-stage builds to minimize image size
  • Use non-root USER
  • Use .dockerignore to exclude node_modules, .git, secrets

Docker Compose

# docker-compose.yml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_URL=postgres://user:pass@db:5432/mydb
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./uploads:/app/uploads
    restart: unless-stopped
    networks:
      - app-net

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-net

volumes:
  pgdata:

networks:
  app-net:
    driver: bridge
# Compose commands
docker compose up -d              # Start in background
docker compose up --build -d      # Rebuild then start
docker compose down               # Stop + remove containers/networks
docker compose down -v            # Also remove volumes
docker compose ps                 # Status
docker compose logs -f            # Follow all logs
docker compose logs -f app        # Follow specific service
docker compose exec app sh        # Exec into service
docker compose pull               # Pull latest images
docker compose restart app        # Restart one service
docker compose scale app=3        # (v2 only: deprecated, use replicas)

Cleanup — Remove Everything Unused

docker system df                  # Disk usage summary
docker system prune               # Remove stopped containers, dangling images, unused networks
docker system prune -a --volumes  # Nuclear option: also volumes + all unused images