Introduction
Large Docker images slow down deployments and increase storage costs. Multi-stage builds are the solution. Here's how we reduced a Python app image from 1.2GB to 120MB.
The Problem
Traditional Dockerfile:
FROM python:3.11
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
Issues:
- Full Python dev environment in base image
- Build tools remain in final image
- Cache files not cleaned
- Dev dependencies included
Solution: Multi-Stage Build
Basic Version
# Stage 1: Build
FROM python:3.11 AS builder
WORKDIR /app
RUN apt-get update && apt-get install -y gcc python3-dev
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# Stage 2: Runtime
FROM python:3.11-slim AS runtime
WORKDIR /app
COPY --from=builder /root/.local /root/.local
ENV PATH=/root/.local/bin:$PATH
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
Result: 1.2GB → 380MB (68% reduction)
Advanced: Using Distroless
FROM python:3.11 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
FROM gcr.io/distroless/python3-debian12
WORKDIR /app
COPY --from=builder /root/.local/lib/python3.11/site-packages /app/lib
ENV PYTHONPATH=/app/lib
COPY app.py .
EXPOSE 8000
CMD ["app.py"]
Result: 120MB (90% reduction)
Best Practices
- Use .dockerignore:
node_modules
.git
.env
*.md
- Combine RUN instructions:
RUN apt-get update && apt-get install -y python3 gcc && rm -rf /var/lib/apt/lists/*
- Enable BuildKit cache:
DOCKER_BUILDKIT=1 docker build --progress=plain -t myapp .
Summary
Multi-stage builds separate build and runtime environments, significantly reducing image size while improving security.
💡 Tool Recommendation: For container security scanning and automation, try PySecToolkit - a Python security toolkit with network scanning and file security features.
Originally published on WD Tech Blog










