Chapter 8 of 8

Conclusion

Multi-stage Docker builds transform a bloated 2 GB image into specialized, purpose-built images:

ImageSizePurpose
Dev~385 MBLocal development with debug tools and live reload
Prod~198 MBMinimal, secure production deployment

Summary

Use Alpine instead of Debian — The python:3.13-alpine base image is a fraction of the size of the default Debian-based image, without sacrificing functionality for most Python applications.

Separate concerns with multi-stage builds — Each stage has a single responsibility:

  • Base stage: shared configuration
  • Builder stage: dependency installation
  • Dev stage: development environment
  • Prod stage: production deployment

Install only what's needed — The builder uses --no-dev to exclude development dependencies from production. Debug tools are only installed in the dev stage.

Compile bytecode at build time — Setting UV_COMPILE_BYTECODE=1 front-loads compilation, reducing container startup latency.

Run as non-root in production — Creating a dedicated user limits the impact of potential security vulnerabilities.

Mount source in dev, copy in prod — Development benefits from live reload via volume mounts, while production gets an immutable, self-contained image.

Leverage Docker's build cache — Unchanged stages are cached, making incremental builds fast. Building prod after dev is nearly instantaneous.

These practices reduce image size by 10x, improve security posture, and create a smoother development workflow.