Bookmark this page. Use Ctrl+F (or Cmd+F on Mac) to find what you need. This cheat sheet covers Docker CLI commands, Dockerfile instructions, Docker Compose, volumes, networking, and production tips.

Last updated: March 2026

How Docker Works

┌──────────────┐    docker build    ┌──────────┐    docker run    ┌────────────┐
│  Dockerfile  │  ───────────────►  │  Image   │  ─────────────►  │ Container  │
│  (recipe)    │                    │ (template)│                  │ (running)  │
└──────────────┘                    └──────────┘                  └────────────┘
                                    docker push
                                    ┌────▼───────┐
                                    │  Registry  │
                                    │ (Docker Hub)│
                                    └────────────┘

Container Commands

CommandDescription
docker run <image>Create and start a container
docker run -d <image>Run in background (detached)
docker run -it <image> bashRun interactively with shell (sh for Alpine)
docker run -p 8080:80 <image>Map host port 8080 to container port 80
docker run --name myapp <image>Run with a custom name
docker run --rm <image>Automatically remove container when it stops
docker run -e KEY=value <image>Set environment variable
docker run -v /host:/container <image>Mount a volume
docker psList running containers
docker ps -aList all containers (including stopped)
docker stop <container>Stop a running container
docker start <container>Start a stopped container
docker restart <container>Restart a container
docker rm <container>Remove a stopped container
docker rm -f <container>Force remove (even if running)
docker exec -it <container> bashOpen a shell inside a running container
docker logs <container>View container logs
docker logs -f <container>Follow logs in real-time
docker inspect <container>Show detailed container info (JSON)
docker statsLive resource usage for all containers
docker cp <container>:/path ./localCopy file from container to host
docker cp ./local <container>:/pathCopy file from host to container
docker container pruneRemove all stopped containers
docker kill <container>Force stop a container (SIGKILL)

Image Commands

CommandDescription
docker imagesList all local images
docker pull <image>Download an image from registry
docker push <image>Upload an image to registry
docker build -t myapp .Build image from Dockerfile in current dir
docker build -t myapp:v1 .Build with a tag/version
docker tag <image> <new-tag>Add a tag to an image
docker rmi <image>Remove an image
docker image pruneRemove unused (dangling) images
docker system prune -aRemove all unused images, containers, networks (not volumes)
docker system prune -a --volumesRemove everything including volumes
docker history <image>Show image layers and sizes
docker loginLog in to Docker Hub (required before push)
docker logoutLog out from registry
docker save -o image.tar <image>Export image to tar file
docker load -i image.tarImport image from tar file

Dockerfile Reference

# Base image
FROM node:20-alpine

# Set working directory
WORKDIR /app

# Copy dependency files first (for caching)
COPY package.json package-lock.json ./

# Install dependencies
RUN npm ci --production

# Copy application code
COPY . .

# Expose a port (documentation only)
EXPOSE 3000

# Default command when container starts
CMD ["node", "server.js"]

Dockerfile Instructions

InstructionDescription
FROM <image>Base image (required, must be first)
WORKDIR /appSet working directory for subsequent commands
COPY <src> <dest>Copy files from host to image
ADD <src> <dest>Like COPY but can extract tar and fetch URLs
RUN <command>Execute command during build (creates a layer)
ENV KEY=valueSet environment variable
ARG KEY=valueBuild-time variable (not available at runtime)
EXPOSE <port>Document which port the app listens on
CMD ["executable", "arg"]Default command (can be overridden)
ENTRYPOINT ["executable"]Fixed command (CMD becomes arguments)
VOLUME /dataCreate a mount point for persistent data
USER <username>Switch to non-root user
`HEALTHCHECK CMD curl -f http://localhost/

CMD vs ENTRYPOINT

# CMD — default command, can be overridden
CMD ["python", "app.py"]
# docker run myapp              → runs python app.py
# docker run myapp bash         → runs bash (overrides CMD)

# ENTRYPOINT — fixed command, CMD becomes arguments
ENTRYPOINT ["python"]
CMD ["app.py"]
# docker run myapp              → runs python app.py
# docker run myapp test.py      → runs python test.py

Multi-Stage Build

# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Production (smaller image)
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Multi-stage builds produce smaller images — the final image only contains the production output, not the build tools.

Docker Compose

docker-compose.yml Example

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
    depends_on:
      - db
    volumes:
      - ./src:/app/src    # bind mount for development

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data    # named volume
    ports:
      - "5432:5432"

volumes:
  pgdata:    # named volume persists data

Compose Commands

CommandDescription
docker compose upStart all services
docker compose up -dStart in background (detached)
docker compose up --buildRebuild images and start
docker compose downStop and remove containers
docker compose down -vStop and remove containers + volumes
docker compose logsView logs for all services
docker compose logs -f appFollow logs for one service
docker compose psList running services
docker compose exec app bashOpen shell in a running service
docker compose buildBuild/rebuild images
docker compose pullPull latest images
docker compose restartRestart all services
docker compose stopStop without removing
docker compose watchAuto-sync file changes to containers (hot reload)

Volumes

TypeSyntaxUse case
Named volume-v mydata:/app/dataPersistent data (databases)
Bind mount-v ./src:/app/srcDevelopment (live code changes)
Anonymous volume-v /app/node_modulesTemporary data
docker volume create mydata        # Create a named volume
docker volume ls                   # List all volumes
docker volume inspect mydata       # Show volume details
docker volume rm mydata            # Remove a volume
docker volume prune                # Remove unused volumes

Networking

docker network create mynetwork    # Create a custom network
docker network ls                  # List networks
docker network inspect mynetwork   # Show network details
docker network rm mynetwork        # Remove a network

Containers on the same network can reach each other by service name:

# In docker-compose.yml, the app can connect to the database using:
# postgres://user:pass@db:5432/mydb
#                       ^^
#                service name = hostname
Network TypeDescription
bridgeDefault — containers can communicate via IP
hostContainer shares the host network (no port mapping)
noneNo networking

.dockerignore

node_modules
.git
.env
*.md
Dockerfile
docker-compose.yml
.DS_Store

Always add .dockerignore — it speeds up builds and prevents copying sensitive files.

Production Tips

TipWhy
Use specific image tags (node:20-alpine, not node:latest)Reproducible builds
Run as non-root user (USER node)Security
Use multi-stage buildsSmaller images
Use HEALTHCHECKAutomatic container recovery
Set restart: unless-stopped in ComposeAuto-restart on failure
Use .dockerignoreFaster builds, no secrets in image
Use docker scout cves <image>Scan for vulnerabilities
Copy dependency files first, then codeBetter layer caching
docker buildx build --platform linux/amd64,linux/arm64Multi-platform builds (ARM + x86)

Useful One-Liners

# Remove all stopped containers
docker container prune

# Remove all unused images, containers, networks, volumes
docker system prune -a --volumes

# Get container IP address
docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>

# Copy file from container to host
docker cp <container>:/app/file.txt ./file.txt

# View image size
docker images --format "{{.Repository}}:{{.Tag}} {{.Size}}"

Common Mistakes

  1. Not using .dockerignore — Without it, docker build copies everything (including node_modules, .git, .env) into the build context. This makes builds slow and can leak secrets into the image.

  2. Using latest tag in productionFROM node:latest means your build can break when the upstream image updates. Always pin a specific version: FROM node:20-alpine.

  3. Running as root — By default, containers run as root. If an attacker escapes the container, they have root on the host. Add USER node (or another non-root user) in your Dockerfile.