DOCKCourse

Docker in Production

Lessons8modules
Total80mfull study
Quick7mtrailer
Projects8docker labs

hello-docker · your first optimised container with multi-stage builds and BuildKit

Build a single-service Dockerfile that shrinks from a bloated 900 MB base image to under 50 MB using multi-stage builds, a distroless or alpine runtime stage, and a non-root USER directive enforced by BuildKit.

snap/smoke-test-2:hello
Stack
docker-engine@29.4.0buildkit@0.29.0node@22-alpinenginx@1.27-alpinedocker-buildx@0.33.0
Real-world use

Every production frontend and API team applies the multi-stage build pattern to separate the heavy build-time toolchain from the lean runtime image. Without it, a Node or Python application ships its entire compiler, package manager, and dev dependencies into production, inflating attack surface and registry storage costs. Teams at companies of all sizes use a builder stage to compile or bundle assets and a minimal alpine or distroless runtime stage to serve them, routinely cutting image sizes from hundreds of megabytes to tens of megabytes. Running the final container as a non-root user is a baseline security control required by most enterprise security policies and enforced by Kubernetes admission controllers in production clusters.

Portfolio value

A hiring manager reviewing this project immediately sees that the engineer understands the full image build lifecycle, not just how to write a working Dockerfile. Demonstrating a before-and-after size reduction with a documented multi-stage strategy signals familiarity with BuildKit layer caching, stage naming, COPY --from mechanics, and the principle of least privilege via USER. These are the exact skills listed in Docker Mastery (Bret Fisher, 318K+ students), the Coursera Docker roadmap, and the roadmap.sh Docker path as non-negotiable for anyone shipping containers to production. It also establishes a clean, reusable Dockerfile template that every subsequent portfolio project can extend.

Builds on lessons
Lesson 1Lesson 2Lesson 3Lesson 4
Build plan
  1. Write a naive single-stage Dockerfile using a full node:22 base image and measure its size with docker image ls to establish the bloated baseline.
  2. Refactor the Dockerfile into a two-stage build: a named builder stage that installs dependencies and compiles or bundles the application, and a minimal nginx:1.27-alpine or node:22-alpine runtime stage that copies only the compiled output.
  3. Add a non-root USER directive to the runtime stage, verify the running container process is unprivileged with docker exec, and document the security rationale in a README.
  4. Enable BuildKit via DOCKER_BUILDKIT=1 or docker buildx build, add a .dockerignore file to exclude node_modules and local config, and confirm layer cache reuse on a second build by observing CACHED log lines.
  5. Compare final image size against the baseline, tag the optimised image with a descriptive label using LABEL and --tag, and write a short README section explaining each Dockerfile instruction and the size reduction achieved.