3/5
Writing Dockerfiles
+20 XP on completion
#Writing Dockerfiles
After this lesson you'll know:
- how to write a Dockerfile from scratch
- the layer principle and why order matters
- how to build and optimize images
#Your first Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
#The individual commands
| Command | Effect |
|---|---|
FROM | Base image (choose alpine — ~5MB instead of 300MB) |
WORKDIR | Sets the working directory |
COPY | Copies files from host into the image |
RUN | Executes commands during build |
EXPOSE | Documents the port (doesn't open it!) |
CMD | Default command when container starts |
#Build & Run
# Build
docker build -t my-app .
# Run
docker run -p 3000:3000 my-app
#Layer Caching — the superpower
Each Dockerfile instruction creates a layer. Docker caches layers — as long as the content doesn't change.
# WRONG — npm install runs on every change
COPY . .
RUN npm install
# RIGHT — npm install only when package.json changes
COPY package*.json ./
RUN npm install
COPY . .
This saves ~30 seconds on the tenth build. On large projects, minutes.
#.dockerignore — keep junk out of your image
Without .dockerignore, you send your entire project folder as build context to the Docker daemon. node_modules (hundreds of MB), .git (the entire history), .env (with secrets) — all of it gets sent.
# .dockerignore — in project root next to Dockerfile
node_modules
.git
.env
*.log
dist
.DS_Store
Effects:
- Faster builds — less data to send
- More secure — no secrets in build context
- Slimmer images — no junk in the final layer
Tip: After building, check docker build -t app . 2>&1 | head -20 — if the build context size is more than 10 MB, you forgot your ignore file.
#✋ Try it out
- Create a new directory, write a Dockerfile with
FROM alpine,CMD ["echo", "Hello Docker"], build withdocker build -t hello .and run it - Extend the Dockerfile: install curl with
RUN apk add curl, rebuild and start a shell (docker run -it hello sh) - Create a
.dockerignorewithnode_modulesand.git. Rebuild the image — is the build faster?
#📌 Summary
- FROM selects the base image, RUN executes build commands, CMD starts the container
- COPY order affects caching: first package.json, then the rest
- Alpine-based images are ~50x smaller than full Linux distributions
- Without .dockerignore,
node_modulesand.gitend up in your image — unnecessary megabytes
← → to navigate