Docker Cheatsheet
Docker packages your application and its dependencies into a portable container image. These are the commands and patterns you will use on every cloud project.
Image Commands#
| Command | What it does |
|---|---|
docker pull nginx:1.25 | Download an image from a registry |
docker build -t my-app:1.0 . | Build an image from a Dockerfile in the current directory |
docker push myrepo/my-app:1.0 | Push an image to a registry |
docker tag my-app:1.0 myrepo/my-app:1.0 | Add a new tag to an existing image |
docker images | List local images |
docker rmi my-app:1.0 | Delete a local image |
docker inspect my-app:1.0 | Show low-level JSON metadata for an image |
docker history my-app:1.0 | Show the layers that make up an image |
Container Lifecycle Commands#
| Command | What it does |
|---|---|
docker run my-app:1.0 | Create and start a new container |
docker start <name> | Start a stopped container |
docker stop <name> | Gracefully stop a running container (SIGTERM → SIGKILL) |
docker restart <name> | Stop and start a container |
docker rm <name> | Delete a stopped container |
docker ps | List running containers |
docker ps -a | List all containers including stopped ones |
docker exec -it <name> /bin/sh | Open an interactive shell in a running container |
docker logs <name> | Print container stdout/stderr |
docker logs -f <name> | Stream live logs |
docker inspect <name> | Show low-level JSON metadata for a container |
docker stats | Live CPU, memory, and network usage for all containers |
docker cp <name>:/app/file.txt ./file.txt | Copy a file out of a container |
Key docker run Flags#
docker run \
-d \ # detach (run in background)
-p 8080:80 \ # map host port 8080 to container port 80
-v /host/data:/app/data \ # bind mount a host directory
--name my-container \ # give the container a name
-e DB_HOST=localhost \ # set an environment variable
--env-file .env \ # load env vars from a file
--network my-network \ # attach to a named network
--rm \ # auto-delete container when it stops
-it \ # interactive + allocate a TTY
my-app:1.0
Dockerfile Instructions#
# Base image — always use a specific version tag
FROM node:20-alpine
# Set the working directory inside the container
WORKDIR /app
# Copy dependency files first (improves layer caching)
COPY package*.json ./
# Run commands during the build
RUN npm ci --only=production
# Copy the rest of the source code
COPY . .
# Declare the port the app listens on (documentation only — doesn't publish it)
EXPOSE 3000
# Set environment variables available at runtime
ENV NODE_ENV=production
# The default command to run when the container starts
# Use ENTRYPOINT + CMD together for flexibility
ENTRYPOINT ["node"]
CMD ["server.js"]
CMD sets the default command but can be overridden at docker run. ENTRYPOINT sets the executable and is harder to override (requires --entrypoint flag). For most apps, use both: ENTRYPOINT ["node"] and CMD ["server.js"].
Multi-Stage Build#
Multi-stage builds produce small final images by keeping build tools out of the runtime image.
# Stage 1: build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: runtime image (much smaller)
FROM node:20-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
The final image only contains what was copied in the runtime stage. The build tools from node:20 are discarded.
Docker Compose#
Minimal docker-compose.yml with two services#
version: "3.9"
services:
web:
build: .
ports:
- "8080:3000"
environment:
- NODE_ENV=production
- DB_HOST=db
depends_on:
- db
volumes:
- ./uploads:/app/uploads
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
Docker Compose Commands#
docker compose up -d # start all services in the background
docker compose down # stop and remove containers and networks
docker compose down -v # also delete named volumes
docker compose logs -f web # stream logs from the web service
docker compose ps # list running services
docker compose exec web sh # open a shell in the running web container
docker compose build # rebuild images without starting
docker compose pull # pull the latest versions of images
Network Commands#
docker network ls # list all networks
docker network create my-network # create a bridge network
docker network inspect my-network # show containers and config for a network
docker network connect my-network <container> # attach a running container to a network
docker network disconnect my-network <container>
Containers on the same named network can reach each other by container name. The default bridge network does not support DNS resolution by name.
Volume Commands#
docker volume ls # list named volumes
docker volume create my-volume # create a named volume
docker volume inspect my-volume # show mount point and metadata
docker volume prune # delete all unused volumes (irreversible)
Named volumes (managed by Docker) outlive containers. Bind mounts (a host path) are useful in development but create host-dependency for production.
System Cleanup#
docker system prune # remove stopped containers, dangling images, unused networks
docker system prune -a # also remove images not used by any container
docker image prune # remove dangling images (untagged)
docker image prune -a # remove all unused images
docker container prune # remove all stopped containers
docker volume prune # remove all unused volumes
Run docker system df first to see how much space Docker is using before pruning.
Common Mistakes#
Not using .dockerignore. Without it, COPY . . will include node_modules, .git, .env, and other large or sensitive directories. Create a .dockerignore at the same level as your Dockerfile.
Running as root. By default, containers run as root. Add a USER instruction to drop to a non-root user before the CMD:
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
Large layer count from repeated RUN instructions. Each RUN creates a new layer. Chain related commands with && and clean up in the same layer:
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
Not tagging image versions. Using :latest in production makes rollbacks hard. Tag images with a version number or git commit SHA.
Copying source before installing dependencies. This busts the npm/pip cache on every source code change. Copy dependency files first, run install, then copy source.