DevOps & Kubernetes (50 Qs)•Part 1: Candid Experience, Container Internals & Docker (1 - 10)
How do you optimize Dockerfiles for minimum image size, security, and build layer caching in production?
Production Best Practices & Dockerfile Blueprint
To achieve sub-50MB production images with fast CI build times and minimal vulnerabilities, follow four core rules:
- Order layers from least frequent to most frequent change to maximize Docker cache hits.
- Use Multi-Stage Builds to completely discard build tools, compilers, and devDependencies from the final runtime image.
- Use Distroless or Minimal Alpine/Scratch images to reduce CVE vulnerability surface.
- Never run as root; specify a non-root system user.
dockerfile
# -------------------------------------------------------------------
# STAGE 1: Builder (Compiles TypeScript & installs dependencies)
# -------------------------------------------------------------------
FROM node:20-alpine AS builder
WORKDIR /app
# Step 1: Copy dependency definitions first (cached unless package.json changes)
COPY package.json package-lock.json ./
RUN npm ci --prefer-offline --no-audit
# Step 2: Copy source code and compile
COPY tsconfig.json ./
COPY src/ ./src
RUN npm run build && npm prune --production
# -------------------------------------------------------------------
# STAGE 2: Minimal Production Runtime (Distroless or Non-Root Alpine)
# -------------------------------------------------------------------
FROM gcr.io/distroless/nodejs20-debian12:nonroot AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV PORT=3000
# Copy only production node_modules and compiled output from builder
COPY --from=builder --chown=nonroot:nonroot /app/node_modules ./node_modules
COPY --from=builder --chown=nonroot:nonroot /app/dist ./dist
COPY --from=builder --chown=nonroot:nonroot /app/package.json ./package.json
# Run as nonroot user (UID 65532 built into distroless)
USER nonroot
EXPOSE 3000
CMD ["dist/main.js"]
Optimization Matrix
| Technique | Problem Solved | Impact |
|---|---|---|
npm ci vs npm install | Deterministic builds from lockfile | Prevents silent version drift |
| Multi-Stage Build | Leaves compilers (gcc, tsc, devDependencies) behind | Reduces image size from ~900MB to ~70MB |
.dockerignore | Prevents copying local node_modules, .git, .env | Avoids cache invalidation & secret leaks |
| Distroless Base | Eliminates shell (/bin/sh), package managers (apt, apk) | Attackers cannot execute reverse shells |