Uma imagem de aplicação Python que pesa 1.2 GB não é normal — é falta de multi-stage build.
O problema
Quando você instala compiladores, ferramentas de build e dependências de desenvolvimento na mesma imagem que vai para produção, tudo isso viaja junto.
A solução
# stage 1: build
FROM python:3.12-slim AS builder
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt
# stage 2: runtime
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]
O COPY --from=builder é a chave: só o que você copiar explicitamente sai do primeiro estágio.
Medindo o resultado
docker build -t app:antes -f Dockerfile.old .
docker build -t app:depois .
docker images | grep app
Em um projeto FastAPI real, isso derrubou a imagem de 1.1 GB para menos de 180 MB — deploy mais rápido, menos superfície de ataque, menos custo de registry.