Writing a Dockerfile
Pulling other people's images is half the story. To ship notes-api itself you write a Dockerfile: a short recipe that turns your code into an image anyone can run. Written carelessly, every one-line change triggers a five-minute rebuild; written well, it rebuilds in seconds.
The rule
Order the Dockerfile from what changes rarely to what changes often.
Each instruction creates a layer, and Docker caches layers. On a rebuild it reuses every cached layer until it reaches the first instruction whose input changed; from there on, everything is rebuilt.
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER nobody
EXPOSE 8000
CMD ["python", "-m", "notes_api"]FROMpicks the base image. A slim base keeps the image small.WORKDIRsets the folder later instructions run in.COPY requirements.txtthenRUN pip install: dependencies change rarely, so this slow layer stays cached.COPY . .brings in your code, which changes on almost every build, so it comes after the install.USER nobodyavoids running the app as root.EXPOSEdocuments the port;CMDsays what the container runs.
A .dockerignore file keeps things out of the build: .git, .venv, local logs and above all .env files with secrets. Secrets belong in environment variables or a secret store at run time, never baked into an image, where anyone who pulls it can read them.
docker build -t notes-api:1.1 .
docker run -d -p 8080:8000 notes-api:1.1The shortcut
Read your Dockerfile top to bottom and ask of each line: "how often does this change?" The answers should go from "almost never" to "every commit". Any expensive step below a frequently changing COPY is a cache-buster.
The slow version
COPY . .sits first, thenRUN pip install. Every code change invalidates the copy layer.
Drills
Answer fast — trust the rule.
Why copy requirements.txt and install before copying the rest of the code?
Which instruction sets the command a container runs when it starts?
Where should a database password for the container come from?
What does .dockerignore do?
Remember
- Order the Dockerfile from what changes rarely to what changes often.
- Shortcut: ask "how often does this change?" of each line, top to bottom.
- Trap:
COPY . .before installing dependencies, and baking secrets into images.
