Lesson 02 Dockerfile Design
Theme:
Lesson 02 · Slide 1

Lesson 02 — Dockerfile Design

Multi-stage builds, image-size optimization, and Python-specific patterns.

Cloud & DevOps Module 1

Lesson 02 · Slide 2

Why image size matters

Aspect180 MB image90 MB image
Cold-start pull (CI runner)~5 s~2 s
Registry storage cost$$ × N tags$ × N tags
Surface area for CVEslargersmaller
K8s rolling-update timeslowerfaster
Lesson 02 · Slide 3

What’s in the 180 MB image

The compilers and headers are scaffolding. You wouldn’t ship scaffolding with the building.

Lesson 02 · Slide 4

The big idea: multi-stage builds

“Build in a heavy image with all the dev tools. Copy just the artefacts into a clean runtime image. Discard the heavy stage.”

Lesson 02 · Slide 5

Multi-stage Dockerfile — minimal example

# Stage 1: build
FROM python:3.11-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# Stage 2: runtime
FROM python:3.11-slim
COPY --from=builder /install /usr/local
WORKDIR /app
COPY app.py .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Lesson 02 · Slide 6

pip install --prefix vs virtualenv vs --target

MethodInstall pathUse when
--prefix=/install/install/lib/python3.X/site-packagesSimple API — copy prefix to /usr/local in runtime stage
--target=/install/install/... directlyDistroless / from-scratch images; add to PYTHONPATH
virtualenv/opt/venv/...Python version juggling, multi-env images

Recommendation for this course: --prefix for slim-based images, --target for distroless.

Lesson 02 · Slide 7

Cache mounts (BuildKit)

# syntax=docker/dockerfile:1.7
FROM python:3.11-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install --prefix=/install -r requirements.txt
Lesson 02 · Slide 8

Going further: uv

FROM python:3.11-slim AS builder
RUN pip install --no-cache-dir uv
WORKDIR /build
COPY requirements.txt .
RUN uv pip install --system --prefix=/install -r requirements.txt
Lesson 02 · Slide 9

What’s in python:3.11-slim — and why “slim” still isn’t slim

For most Python apps you don’t need apt at runtime. You need Python + your wheels.

Lesson 02 · Slide 10

Distroless: the next size tier

FROM python:3.11-slim AS builder
# ... build into /install ...

FROM gcr.io/distroless/python3-debian12
COPY --from=builder /install /usr/local
WORKDIR /app
COPY app.py .
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
Lesson 02 · Slide 11

.dockerignore is mandatory

__pycache__/
*.pyc
.venv/
.git/
.pytest_cache/
*.md
tests/
Lesson 02 · Slide 12

Layer ordering revisited

PositionCache costBest for
EarlyStable across many buildsBase image, system packages
MiddleRebuilds on dep changerequirements.txt + pip install
LateRebuilds on every code editCOPY app.py

Place instructions from least-frequently-changing to most-frequently-changing.

Lesson 02 · Slide 13

Pinning and reproducibility

A tag is a mutable pointer. A digest is content-addressed. Only digests guarantee reproducibility.

Lesson 02 · Slide 14

What lands in sample-app/ after this lesson

After Lesson 02: cloud-devops/sample-app/api/Dockerfile is multi-stage; final image < 100 MB; .dockerignore exists; cloud-devops/sample-app/worker/Dockerfile lands with the same shape.

Files changed

  • api/Dockerfile — multi-stage, cache mount, non-root user
  • api/.dockerignore — new

Files added

  • worker/Dockerfile
  • worker/.dockerignore
Lesson 02 · Slide 15

Recap & what’s next

Coming up: Lesson 03 — running api + worker side by side with docker-compose, and sharing config via env vars.
1 / ?