Dockerizando Python
Contêineres Python de produção usam imagens base slim, builds multi-stage, usuários não-root e dependências fixadas via uv ou pip - produzindo imagens pequenas e reproduzíveis para ECS, Kubernetes ou Fly.
Receita
FROM python:3.14-slim AS builder
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN pip install uv && uv sync --frozen --no-dev
FROM python:3.14-slim
WORKDIR /app
COPY --from=builder /app/.venv /app/.venv
COPY app ./app
ENV PATH="/app/.venv/bin:$PATH"
USER 1000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]Quando usar isso:
- Deploy de FastAPI/Django/Flask para qualquer plataforma de contêiner
- Builds reproduzíveis a partir de lockfiles em CI
- Isolar dependências do Python do host
- Escalabilidade horizontal com imagens idênticas por réplica
Exemplo de Trabalho
Dockerfile multi-stage com uv, usuário não-root e padrões amigáveis à saúde.
# syntax=docker/dockerfile:1
FROM python:3.14-slim-bookworm AS builder
WORKDIR /build
RUN pip install --no-cache-dir uv==0.6.0
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-install-project --no-dev
FROM python:3.14-slim-bookworm AS runtime
WORKDIR /app
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PATH="/app/.venv/bin:$PATH"
RUN useradd --create-home --uid 1000 appuser
COPY --from=builder /build/.venv /app/.venv
COPY app ./app
USER appuser
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"
CMD ["gunicorn", "-w", "2", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000", "app.main:app"]docker build -t myapp:local .
docker run --rm -p 8000:8000 -e LOG_LEVEL=info myapp:localO que isso demonstra:
- Estágio builder instala dependências; runtime copia apenas
.venv PYTHONUNBUFFEREDgarante que os logs sejam descarregados prontamenteappusernão-root reduz o impacto de escape do contêinerHEALTHCHECKcomplementa as sondas do orquestrador
Mergulho Profundo
Táticas de Tamanho de Imagem
| Técnica | Economia |
|---|---|
Base slim | Camada de SO menor |
| Multi-stage | Sem ferramentas de build na imagem final |
.dockerignore | Ignorar .venv, tests, .git |
| Sem cache pip | --no-cache-dir |
Essenciais do .dockerignore
.git
.venv
__pycache__
.pytest_cache
tests/
Notas Python
# Fixar digest para segurança da cadeia de suprimentos
FROM python:3.14-slim-bookworm@sha256:... AS runtimeArmadilhas
- Copiar o repositório inteiro antes da instalação de dependências - cache é invalidado a cada commit. Correção: copiar lockfiles primeiro,
RUN uv sync, depois copiar o código do app. - Executar como root - impacto de escape do contêiner. Correção:
USERnão-root com apenas diretórios necessários graváveis. - Dependências de desenvolvimento na imagem de produção - inchaço e superfície de ataque. Correção:
sync --no-dev. - Vincular 127.0.0.1 no CMD - inacessível de fora do contêiner. Correção:
0.0.0.0. - Segredos em ENV ou camadas - visíveis no histórico da imagem. Correção: injetar em tempo de execução a partir do armazenamento de segredos.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| AWS Lambda container | Baixa operação e picos | Conexões de longa duração |
| PaaS buildpacks | MVP mais rápido | Necessidade de controle total do Dockerfile |
| Imagens Nix/conda | Fixação de pilha científica | API web simples |
FAQs
uv vs pip no Docker?
uv é mais rápido e nativo de lockfile - recomendado para projetos Python 3.14 com pins de manifesto.
Preciso de gunicorn no contêiner?
Uvicorn sozinho funciona para serviços pequenos; Gunicorn gerencia múltiplos workers em um contêiner.
Como executo migrações?
Contêiner de inicialização separado ou job - não no mesmo CMD do servidor web, a menos que sequenciado cuidadosamente.
Onde vão os arquivos estáticos?
Coletar na build (django collectstatic) na imagem ou fazer upload para S3/CDN no deploy.
Como depuro localmente?
docker compose com montagem de volume apenas para desenvolvimento - a imagem de produção não deve montar o código-fonte sobre a imagem.
Imagens ARM vs AMD?
Construir multi-arquitetura com buildx ao implantar em Graviton ou Apple Silicon dev correspondendo à produção.
Como escaneio imagens?
CI executa Trivy/Grype no push; corrija a imagem base regularmente.
E sobre distroless?
Possível com venv copiado - depuração mais difícil; slim Debian é um padrão pragmático.
Como passo a configuração?
Variáveis de ambiente em tempo de execução e segredos - não embutidos nas camadas da imagem.
Qual o tamanho das imagens?
Acompanhe o tamanho em CI; investigue quando a imagem da API web exceder algumas centenas de MB sem dependências de ML.
Relacionados
- Noções Básicas de Implantação - Modelos WSGI/ASGI
- Gunicorn & Uvicorn - CMD do worker
- Configuração e Segredos em Produção - ambiente de tempo de execução
- Pipelines de CI/CD - construir e enviar imagens
- Melhores Práticas de Implantação - checklist de contêiner
Versões da Stack: Esta página foi escrita para Python 3.14.0 (3.14 estável, 3.13 em manutenção), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.