tezvyn:

Walk me through a production-ready Dockerfile for a web app

AI-drafted, machine-checkedSource: docs.docker.combeginner

Tests multi-stage builds, layer caching, and security hardening. A strong answer covers a pinned slim FROM, multi-stage separation of build and runtime, ordered COPY for cache, and a non-root USER.

WHAT THIS TESTS: The interviewer wants to know if you understand that a Dockerfile is not just a script that installs an app, but a build artifact that controls image size, build speed, security posture, and cache efficiency. At the senior level they care about production trade-offs, not just syntax.

A GOOD ANSWER COVERS: First, choose a minimal base image such as distroless, alpine, or a language-specific slim variant, and pin it with a digest or specific tag rather than latest. Second, use multi-stage builds: one stage compiles code or installs build dependencies, then a second stage copies only the runtime artifacts, which keeps compilers and dev tools out of the final image. Third, order COPY instructions from least likely to change to most likely to change so that layer caching is maximized; for example, copy dependency lock files before source code so that npm install or pip install is cached until the lock file changes. Fourth, run the application as a non-root USER and avoid running unnecessary services. Fifth, clean up package manager caches and temporary files in the same RUN layer where they are created to avoid bloating the image. Sixth, use a .dockerignore file to prevent sending build context garbage into the daemon.

COMMON WRONG ANSWERS: A red flag is using FROM ubuntu:latest or FROM node without a pinned version, which destroys reproducibility. Another is putting secrets into ENV or ARG instructions because those values are visible in the image history. Some candidates forget multi-stage builds and ship entire GCC or build toolchains into production, inflating the attack surface. Running as root without explanation is also a signal that production hardening was not considered.

LIKELY FOLLOW-UPS: The interviewer might ask how you would handle secrets at build time without baking them into layers, how you would debug a distroless container since it lacks a shell, or how you would structure the build to take advantage of BuildKit cache mounts. They might also ask about health checks, signal handling with PID 1, or why you would choose alpine over distroless.

ONE CONCRETE EXAMPLE: For a Node.js application, you might use node:20-slim as the builder stage, copy package-lock.json, run npm ci, copy the source, then run npm run build. In the second stage, use node:20-alpine or gcr.io/distroless/nodejs20-debian12, copy the built dist folder and node_modules from the builder, set USER 1000, expose port 3000, and run the server. This drops the image from hundreds of megabytes to roughly fifty to eighty megabytes and removes the npm CLI from production.

Read the original → docs.docker.com

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.