Toolmingo
Guides9 min read

Docker Cheat Sheet: Every Command You Actually Need

A complete Docker cheat sheet — images, containers, volumes, networks, Compose, Dockerfile, and debugging. Copy-ready commands for daily container work.

The commands you reach for every day — and the ones you search every time. This reference covers everything from basic container management to multi-service Compose workflows.

Quick reference

The 20 commands that cover 90% of daily Docker work.

Command What it does
docker run -it ubuntu bash Start container with interactive shell
docker run -d -p 8080:80 nginx Run in background, map port
docker ps List running containers
docker ps -a List all containers (including stopped)
docker stop <id> Stop a running container
docker rm <id> Remove a stopped container
docker images List local images
docker pull nginx Download image from registry
docker build -t myapp . Build image from Dockerfile
docker exec -it <id> bash Open shell inside running container
docker logs <id> View container output
docker logs -f <id> Follow live logs
docker inspect <id> Full container JSON metadata
docker cp file.txt <id>:/app/ Copy file into container
docker volume ls List volumes
docker network ls List networks
docker system prune Remove unused data
docker compose up -d Start all services in background
docker compose down Stop and remove containers
docker compose logs -f Follow logs for all services

Images

Pull, list, remove

docker pull node:20-alpine        # Download a specific tag
docker pull node:20-alpine --quiet # Suppress output

docker images                     # List all images
docker images -q                  # Image IDs only
docker image ls --filter dangling=true  # Dangling (untagged) images

docker rmi node:20-alpine         # Remove image
docker image prune                # Remove all dangling images
docker image prune -a             # Remove all unused images (careful!)

Build

docker build -t myapp .                     # Build with tag from current dir
docker build -t myapp:1.0 .                 # Tag with version
docker build -t myapp -f Dockerfile.prod .  # Use specific Dockerfile
docker build --no-cache -t myapp .          # Force rebuild all layers
docker build --build-arg NODE_ENV=prod .    # Pass build argument

Tag and push

docker tag myapp myregistry.io/myapp:1.0   # Tag for a registry
docker push myregistry.io/myapp:1.0        # Push to registry
docker login myregistry.io                 # Authenticate first

Save and load

docker save myapp | gzip > myapp.tar.gz    # Export image to file
docker load < myapp.tar.gz                 # Import from file

Containers

Run

docker run nginx                          # Run (foreground, pulls if needed)
docker run -d nginx                       # Run detached (background)
docker run -it ubuntu bash                # Interactive with pseudo-TTY
docker run --rm nginx                     # Auto-remove when stopped

docker run -p 8080:80 nginx               # Map host:container port
docker run -p 127.0.0.1:8080:80 nginx     # Bind to localhost only

docker run -e NODE_ENV=production node    # Set environment variable
docker run --env-file .env node           # Load vars from file

docker run -v /host/path:/container/path nginx   # Bind mount
docker run -v myvolume:/data postgres           # Named volume

docker run --name myapp nginx             # Assign a name
docker run --network mynet nginx          # Connect to network
docker run --restart=unless-stopped nginx # Restart policy

Inspect and debug

docker ps                         # Running containers
docker ps -a                      # All containers
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

docker logs myapp                 # All output
docker logs -f myapp              # Follow (live)
docker logs --tail 100 myapp      # Last 100 lines
docker logs --since 5m myapp      # Last 5 minutes

docker inspect myapp              # Full JSON metadata
docker inspect -f '{{.NetworkSettings.IPAddress}}' myapp  # Extract field

docker exec -it myapp bash        # Shell inside running container
docker exec myapp cat /etc/hosts  # Run one command
docker exec -u root myapp bash    # Run as specific user
docker top myapp                  # Processes inside container
docker stats                      # Live CPU/memory usage (all containers)
docker stats myapp                # Stats for one container

Lifecycle

docker stop myapp           # Graceful stop (SIGTERM then SIGKILL)
docker kill myapp           # Immediate stop (SIGKILL)
docker start myapp          # Start a stopped container
docker restart myapp        # Stop then start
docker pause myapp          # Freeze (suspend processes)
docker unpause myapp        # Resume

docker rm myapp             # Remove stopped container
docker rm -f myapp          # Force remove running container
docker rm $(docker ps -aq)  # Remove all stopped containers

docker rename myapp newname # Rename container
docker commit myapp myimage # Create image from container (avoid in prod)

Copy files

docker cp file.txt myapp:/app/file.txt   # Host → container
docker cp myapp:/app/logs/out.log ./     # Container → host

Volumes

docker volume create mydata        # Create named volume
docker volume ls                   # List volumes
docker volume inspect mydata       # Details (mount point, etc.)
docker volume rm mydata            # Remove volume
docker volume prune                # Remove unused volumes

# Run with volume
docker run -v mydata:/data postgres
docker run -v $(pwd):/app node:20  # Bind-mount current dir (dev)

Networks

docker network create mynet                   # Bridge network (default)
docker network create --driver host mynet     # Host network
docker network ls                             # List networks
docker network inspect mynet                  # Details
docker network rm mynet                       # Remove network

docker network connect mynet myapp            # Connect running container
docker network disconnect mynet myapp         # Disconnect

# Containers on same network reach each other by name
docker run --network mynet --name db postgres
docker run --network mynet myapp              # myapp can reach "db:5432"

Dockerfile reference

A minimal but production-ready Dockerfile for a Node.js app:

# syntax=docker/dockerfile:1
FROM node:20-alpine AS base
WORKDIR /app

# Dependencies layer (cached unless package.json changes)
FROM base AS deps
COPY package*.json ./
RUN npm ci --omit=dev

# Build layer
FROM base AS build
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production layer (smallest final image)
FROM base AS prod
ENV NODE_ENV=production
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
EXPOSE 3000
USER node
CMD ["node", "dist/index.js"]

Key Dockerfile instructions:

Instruction Purpose
FROM image:tag Base image
WORKDIR /path Set working directory
COPY src dest Copy files from build context
ADD src dest Copy + auto-extract archives
RUN command Execute during build (creates layer)
ENV KEY=value Set environment variable
ARG KEY=default Build-time variable
EXPOSE port Document port (informational only)
USER name Switch user (don't run as root)
CMD ["exe", "arg"] Default command (overridable)
ENTRYPOINT ["exe"] Fixed executable
VOLUME /path Declare mount point
HEALTHCHECK CMD curl -f http://localhost/ Container health check

.dockerignore

node_modules
.git
.env
*.log
dist
coverage

Docker Compose

docker-compose.yml for a typical web app:

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

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

volumes:
  pgdata:

Compose commands

docker compose up                  # Start (foreground)
docker compose up -d               # Start detached
docker compose up --build          # Rebuild images before starting
docker compose up --force-recreate # Recreate containers even if unchanged

docker compose down                # Stop and remove containers + networks
docker compose down -v             # Also remove named volumes

docker compose ps                  # Status of services
docker compose logs                # All service logs
docker compose logs -f app         # Follow one service
docker compose exec app bash       # Shell into running service

docker compose build               # Build images
docker compose pull                # Pull latest images

docker compose restart app         # Restart one service
docker compose stop app            # Stop one service
docker compose run --rm app sh     # One-off command (new container)

# Scale (use only for stateless services)
docker compose up -d --scale app=3

Environment files

# .env (auto-loaded by Compose)
POSTGRES_PASSWORD=secret
TAG=1.0.0

# Reference in docker-compose.yml
image: myapp:${TAG}

Cleanup

Docker accumulates disk usage quickly. Safe cleanup commands:

docker system df                   # Show disk usage breakdown
docker system prune                # Remove stopped containers + dangling images + unused networks
docker system prune -a             # Also remove images not used by any container
docker system prune -a --volumes   # Also remove unused volumes (DATA LOSS possible)

docker container prune             # Remove stopped containers only
docker image prune                 # Remove dangling images only
docker image prune -a              # Remove all unused images
docker volume prune                # Remove unused volumes
docker network prune               # Remove unused networks

6 common mistakes

1. Running as root
Default user in many images is root. Always add USER node (or similar non-root user) in production Dockerfiles. An attacker who escapes the container has root on the host.

2. Copying .env or secrets into the image
Every COPY . . that runs before adding .dockerignore may bake secrets into image layers. Add .env to .dockerignore and pass secrets at runtime via --env-file or your secret manager.

3. Not pinning image tags
FROM node:latest silently breaks when Node releases a new major version. Always pin: FROM node:20.18-alpine3.20. Use Dependabot or Renovate to get update PRs.

4. One giant RUN layer vs. many small ones
The Docker layer cache works per-instruction. Put things that change often (application code) in later layers. Put things that change rarely (OS packages, dependencies) in early layers. This dramatically speeds up rebuilds.

5. Storing data inside the container
Containers are ephemeral. Any file written inside a container without a volume mount is lost on docker rm. Always mount volumes for databases, uploads, and any persistent data.

6. Exposing ports without binding to localhost
-p 5432:5432 binds on 0.0.0.0 — your database is now reachable from the internet if your firewall allows it. Use -p 127.0.0.1:5432:5432 for services that only need to be accessible locally.

6 frequently asked questions

What is the difference between CMD and ENTRYPOINT?
ENTRYPOINT sets the executable; CMD sets the default arguments. docker run myimage custom-arg replaces CMD but not ENTRYPOINT. Use ENTRYPOINT ["node"] + CMD ["server.js"] so you can override the script without overriding the runtime.

What is the difference between COPY and ADD?
Prefer COPY — it only copies files. ADD additionally auto-extracts .tar archives and can fetch URLs, which makes builds less predictable. Use ADD only when you explicitly need the extract behaviour.

How do I see what's inside an image without running it?
docker run --rm -it myimage sh starts a throwaway shell. To inspect the layers: docker history myimage. To export the entire filesystem: docker export $(docker create myimage) | tar -t | head -50.

What is the difference between a volume and a bind mount?
A volume is managed by Docker (/var/lib/docker/volumes/) — portable, easy to back up, works on all OSes. A bind mount maps a specific host path into the container — useful in development where you want hot-reload from your local files. Use volumes in production.

How do I pass secrets to a container without baking them into the image?
For single containers: docker run --env-file .env myimage. For Compose: use the secrets: block (Docker Swarm) or reference a .env file that stays out of version control. For Kubernetes: use Secrets objects mounted as files.

How do I make my Docker build faster?
Order Dockerfile instructions from least-to-most-frequently-changed. Copy package.json and run npm ci before COPY . . so the dependency layer is cached unless packages change. Use multi-stage builds to keep the final image small. Use --cache-from in CI to reuse layers from previous builds.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools