TLDR of the video: My Production Dockerfile Rules: How I Build Docker Images
Transcript from the author: My Production Dockerfile Rules: How I Build Docker Images
- Use minimal base images β containers are not full VMs; only include needed runtime deps.
- Prefer Alpine/slim/distroless/scratch when possible.
- Derive the version from your project, donβt guess (e.g., use
node:20-alpineifpackage.jsonsays Node 20).
-
Use multi-stage builds so build tools and source donβt end up in runtime image.
-
Structure Dockerfile for cache friendliness:
- Put rare-changing files (e.g., manifests) first.
- Copy code later so changes donβt bust earlier cache.
-
Combine related RUN commands to reduce layers.
-
Clean caches in the same RUN layer where theyβre created or you save nothing.
- Avoid
COPY . .β it brings in unwanted files, including secrets. - Be explicit: e.g.,
COPY src/ ./src/,COPY static/ ./static/.
- Install only production dependencies; e.g.,
npm ci --omit=dev. - Dev/test deps belong in build stage only.
- Never run as root β create and switch to a non-root user.
- Pin base image versions β avoid
:latestso builds are reproducible. - Prefer Official or Verified images; avoid random ones.
- No secrets in images β environment vars or build args are safer.
- No sudo in containers.
- Install only necessary packages (e.g., use
--no-install-recommendswhen using apt). - No debugging tools in production images β attackers love them.
- If debugging is needed, use ephemeral debug containers instead.
- Ensure runtime binaries are owned by root but executed by non-root so attackers canβt modify them.
- Always use the exec (JSON) form for
CMDso signals (e.g., SIGTERM) are delivered correctly.
- Sort multi-line arguments alphabetically (e.g., package lists) to reduce diffs and merge conflicts.
- Use WORKDIR instead of
RUN cd β¦; WORKDIR persists across instructions. - Comment non-obvious decisions, not the obvious commands.
- Add OCI labels like
org.opencontainers.image.source,version,descriptionfor better image management.