Preamble
Shipping Python services in Docker is standard; shipping them well means separating build-time compilers and dev headers from runtime layers. Multi-stage builds copy only artifacts the process needs—smaller pulls, fewer CVEs in production images, faster deploys.
Pattern
Stage 1 (builder)
Install build deps, compile wheels, run poetry export / pip wheel as appropriate.
Stage 2 (runtime)
Slim base, non-root user, copy virtualenv or site-packages + app code only.
Order COPY so dependency layers cache when requirements.txt is unchanged.
Pinning and trust
Pin base images by digest when reproducibility matters. Scan images in CI; treat critical CVEs like failing tests unless explicitly risk-accepted.
Operations payoff
Smaller images mean faster cold starts and cheaper registries. They also mean kubectl exec debugging matches what developers run locally—when it does not, you chase phantom bugs.
Conclusion
Containers are architecture: they shape how you reproduce incidents.