Docker Cheatsheet

Dockerfile

Use this Docker reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Instruction Reference

InstructionPurposeExample
FROMBase image (must be first)FROM node:22-alpine
RUNExecute command in a new layerRUN npm ci --omit=dev
CMDDefault command (overridable)CMD ["node", "server.js"]
ENTRYPOINTFixed executableENTRYPOINT ["python", "app.py"]
COPYCopy files from build contextCOPY package*.json ./
ADDLike COPY + auto-extract tarballs, URL fetchADD archive.tar.gz /data/
WORKDIRSet working directoryWORKDIR /app
ENVSet environment variableENV NODE_ENV=production
ARGBuild-time variableARG VERSION=1.0
EXPOSEDocument listening portEXPOSE 8080
VOLUMEDeclare a mount pointVOLUME ["/data"]
USERSwitch to user/UIDUSER node
LABELKey-value metadataLABEL version="1.0"
HEALTHCHECKContainer health probesee below
SHELLOverride default shellSHELL ["/bin/bash", "-o", "pipefail", "-c"]
STOPSIGNALSignal sent on docker stopSTOPSIGNAL SIGTERM
ONBUILDTrigger in child imagesONBUILD COPY . /app

Minimal Node.js Example

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
EXPOSE 3000
USER node
CMD ["node", "server.js"]

Minimal Python Example

FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
USER nobody
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

CMD vs ENTRYPOINT

# CMD alone — all arguments overridable at runtime
CMD ["node", "server.js"]

# ENTRYPOINT alone — fixed binary, no default args
ENTRYPOINT ["python", "app.py"]

# Together (recommended) — ENTRYPOINT is the executable, CMD are default args
ENTRYPOINT ["nginx", "-g"]
CMD ["daemon off;"]
# docker run img               -> nginx -g "daemon off;"
# docker run img daemon on;    -> nginx -g "daemon on;"

Always use exec form (["cmd", "arg"]) for CMD/ENTRYPOINT so signals are delivered directly to the process, not a shell.

ARG and ENV

ARG NODE_VERSION=22          # build-time only; not available at runtime
ENV PORT=3000                # available at runtime too
ENV APP_HOME=/app \
    LOG_LEVEL=info

# Use ARG to parameterise the base image
ARG BASE=node:22-alpine
FROM ${BASE}
docker build --build-arg NODE_VERSION=20 .

HEALTHCHECK

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD wget -qO- http://localhost:3000/health || exit 1

.dockerignore

node_modules
.git
.env*
dist
*.log
**/*.test.*

.dockerignore patterns follow .gitignore syntax. Always exclude node_modules, .git, and secrets before the first COPY . ..

Layer Caching Best Practices

# Copy dependency manifests FIRST so installs are cached
COPY package*.json ./
RUN npm ci

# Source changes only invalidate layers from here down
COPY . .

SHELL for Pipefail Safety

SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN curl -fsSL https://example.com | bash   # fails if curl fails

Labels (OCI standard)

LABEL org.opencontainers.image.source="https://github.com/org/repo" \
      org.opencontainers.image.version="1.2.3" \
      org.opencontainers.image.licenses="MIT"