Skip to content

Lab 2: Container Basics

Field Value
Tier 1 — Foundations
Estimated Time 30 minutes
Prerequisites Docker installed
Auto-Grade Yes

Scenario

Your team has inherited a legacy Node.js application that was hastily containerized by a contractor who left no documentation. The Dockerfile works, technically — it produces a running container — but it violates every best practice in the book.

The image is 1.2 GB (it should be under 200 MB). It runs as root. It copies node_modules into the image instead of running npm install inside the build. There is no .dockerignore, so the entire .git/ directory ends up in the image. The health check is missing, and the build takes 4 minutes because every code change invalidates the entire layer cache.

Your job is to refactor this Dockerfile into something production-worthy: multi-stage build, non-root user, proper layer caching, health check, and a .dockerignore that keeps the image lean.

Objectives

  • Create a multi-stage Dockerfile (builder + production stage)
  • Final image size is under 200 MB
  • Container runs as a non-root user (UID 1000+)
  • Layer caching works (changing app code does not reinstall dependencies)
  • .dockerignore excludes .git/, node_modules/, and *.md
  • Health check is defined in the Dockerfile
  • Container starts and responds on port 3000

Setup

./setup.sh

Creates a sample Node.js app with a broken Dockerfile under /tmp/lab-container-basics/.

Hints

Hint 1: Multi-stage builds Use `FROM node:20-alpine AS builder` for the build stage and `FROM node:20-alpine` for the production stage. Copy only the built artifacts from builder to production.
Hint 2: Layer caching for npm Copy `package.json` and `package-lock.json` first, run `npm ci`, then copy the rest of the source code. This way, dependency installation is cached unless lock files change.
Hint 3: Non-root user Add `RUN addgroup -S app && adduser -S app -G app` and then `USER app` before the CMD instruction.
Hint 4: Health check Add `HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1`
Hint 5: .dockerignore Create a `.dockerignore` file with `.git`, `node_modules`, `*.md`, `Dockerfile`, and `.dockerignore` itself.

Grading

./grade.sh

Solution

See the solution/ directory for the optimized Dockerfile and .dockerignore.