Writing a Dockerfile for a web app
core Dockerfile instructions and layering.
FROM a base, set WORKDIR, install dependencies before app code for cache reuse, EXPOSE the port, CMD the start command.
copying everything before installing deps, or root.
WHAT THIS TESTS This checks practical Docker literacy: which instructions matter, what they do, and why instruction order affects build speed and image quality.
A GOOD ANSWER COVERS Start with FROM to pick a base image, preferring a slim, version-pinned image like python:3.12-slim rather than latest for reproducibility and a smaller surface. Use WORKDIR to set the working directory so later paths are clean. Then exploit layer caching: COPY only the dependency manifest, such as requirements.txt or package.json, and RUN the install before copying the rest of the code. Because Docker caches layers and invalidates from the first change, dependencies are reinstalled only when the manifest changes, not on every code edit, which speeds up builds dramatically. After that, COPY the application source. Use EXPOSE to document the port the app listens on, and finish with CMD or ENTRYPOINT to specify the process that runs when the container starts, for example gunicorn. Mention a .dockerignore to keep junk and secrets out of the build context, and creating and switching to a non-root USER for security.
COMMON WRONG ANSWERS Copying the whole project before installing dependencies, so any code change busts the dependency cache and every build reinstalls everything. Using FROM image:latest, making builds non-reproducible. Running as root. Bloating the image by starting from a full OS base or leaving build tools in the final image.
LIKELY FOLLOW-UPS What is the difference between CMD and ENTRYPOINT? How does layer caching decide what to rebuild? Why a slim or distroless base? How would a multi-stage build help? What goes in .dockerignore?
ONE CONCRETE EXAMPLE A Flask app Dockerfile: FROM python:3.12-slim, WORKDIR /app, COPY requirements.txt ., RUN pip install --no-cache-dir -r requirements.txt, COPY . ., EXPOSE 8000, then CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]. Editing app.py rebuilds only the final COPY and CMD layers because the cached dependency layer is untouched, so iteration is fast.
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.