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)
-
.dockerignoreexcludes.git/,node_modules/, and*.md - Health check is defined in the Dockerfile
- Container starts and responds on port 3000
Setup¶
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¶
Solution¶
See the solution/ directory for the optimized Dockerfile and .dockerignore.