Skip to content
advanced Phase 10 · Docker Optimization

Image Size Optimization

Reduce image size with distroless, alpine, and layer optimization.

1h
0 problems
Topic Progress 0%

Where Image Size Comes From

Where Image Size Comes From

An image is a stack of layers; each instruction adds one. Size concentrates in the base OS, installed packages, and copied artifacts:

docker history app:1.4 --human   # size attributed per layer

Two fixes dominate. First, COPY respects .dockerignore — excluding .git, node_modules, and test fixtures stops them from entering a layer at all. Second, order instructions so volatile files come last: package manifests, then install, then source. Base choice matters too — a full node:20 carries toolchains you never run in production, while node:20-slim or -alpine trims that immediately.

Multi-Stage and Distroless

Multi-Stage and Distroless

Compile in one stage, ship only the artifact:

FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=build /app/dist ./dist
CMD ["dist/server.js"]

Distroless images contain the runtime and its certificates but no shell, package manager, or userland — smaller attack surface, and docker exec debugging is impossible by design (use docker debug or a sidecar when needed). Alpine is the pragmatic middle: small and musl-based, but glibc-linked binaries need compatibility shims and native modules must compile against musl.

Pitfalls and Interview Angles

Pitfalls and Interview Angles

Copying node_modules or __pycache__. Host artifacts bloat layers and often mismatch the image architecture — install inside the build stage only.

Missing runtime deps in distroless. tzdata, ca-certificates, and timezone config are absent or minimal; test TLS and Intl behavior in the target image, not the build stage.

No measurement. docker system df -v and dive show layer-by-layer waste; add a size check to CI so a 400 MB regression fails the build.

Interview: give your base-image decision ladder, walk a multi-stage Dockerfile, and name one debugging cost of distroless you accept in exchange for the size.

Quiz

1. What is the main purpose of .dockerignore?

Question 1 options

2. What do you lose with a distroless runtime image?

Question 2 options

3. Why can host-copied node_modules break an image?

Question 3 options

Flashcards

Question

Layer attribution

Answer

docker history --human shows which instruction added how many megabytes.

Question

Multi-stage build

Answer

Toolchain in builder stage; final stage copies only artifacts via COPY --from.

Question

Distroless

Answer

Runtime-only base: no shell or package manager, smaller surface, harder to debug.

Question

Alpine tradeoff

Answer

Small musl-based image; glibc binaries and native modules need rebuilds or shims.

Question

.dockerignore

Answer

Keeps .git, node_modules, fixtures out of the build context entirely.

Revision Notes

Key Takeaways

  • 1. Measure first with docker history and dive, then cut
  • 2. Multi-stage plus a lean base removes most weight
  • 3. Install dependencies inside the image, never copy host artifacts

Interview Tips

  • • Walk your Dockerfile and attribute megabytes per layer
  • • Defend base choice (slim vs alpine vs distroless) against a debugging objection

Cheat Sheet

history/dive to measure; .dockerignore first; multi-stage COPY --from=build; slim/alpine/distroless ladder; install deps in-image; CI size budget.

Continue Learning

Before You Start

  • No prerequisites listed.