Skip to main content
Dockerfile Python Assembling the instructions into a real, working Python app Dockerfile, where the key is the order of instructions.

A typical Python app

Why COPY requirements.txt before COPY . .? The layer cache rule is “when a layer changes, every layer after it rebuilds” (full mechanism in layer cache). Source code changes far more often than the dependency manifest. If you COPY . . then pip install, every .py edit forces the whole pip install to rerun (slow). Copying and installing the manifest separately means the pip install layer only rebuilds when requirements.txt actually changes. pip install --no-cache-dir keeps the downloaded wheels out of the image layer, shrinking it.

Shrinking with multi-stage

For a smaller image, use a multi-stage build: install dependencies into a venv in the builder stage, and have the final stage copy only the venv so build tools do not end up in the final image:
  • FROM ... AS builder names a build stage; COPY --from=builder copies its output.
  • --mount=type=cache,target=/root/.cache/pip persists the pip download cache across builds (not in an image layer), so rebuilds do not re-download.
  • The final image holds only the runtime and venv, no build tools, and is noticeably smaller.
When you need to compile native packages, add build tools in the builder stage; they do not reach the final image:

Next

Reference: docs.docker.com/guides/python/containerize, multi-stage builds