Day 2 – Multi-Stage Builds and Security
Today's Focus
Write multi-stage Dockerfiles to produce lean production images, and containerise your frontend and backend services.
Tasks
- Write a multi-stage Dockerfile for your TypeScript/Node.js backend from Week 4: Stage 1 (
FROM node:20 AS builder) installs all deps and runsnpm run build. Stage 2 (FROM node:20-alpine AS runtime) copies only the compileddist/and productionnode_modules. Measure the image size difference:docker images. - Write a Dockerfile for a simple static frontend (your HTML/JS from Week 2): use
FROM nginx:alpine, copy thedist/folder to/usr/share/nginx/html, and expose port 80. - For your backend, add a non-root user in the Dockerfile:
RUN addgroup -S app && adduser -S app -G app, thenUSER app. Rundocker exec <container> whoamito confirm. Explain why running as root in a container is a security risk. - Add a
.dockerignorefile to each service: excludenode_modules/,.git/,*.test.ts,coverage/, and.env. Build again and verify the context size shrinks (visible in thedocker buildoutput line "Sending build context..."). - Use
ARGandENVin your Dockerfile: defineARG NODE_ENV=productionandENV PORT=8080. Override the ARG at build time:docker build --build-arg NODE_ENV=development .. - Run both containers and confirm they start without errors. Check logs with
docker logs <container>and resource usage withdocker stats.