Guia

Docker para Python em 2026: Guia Completo

Aprenda a configurar Docker para projetos Python em 2026: Dockerfile seguro, docker compose, healthcheck, usuário não-root, Redis, Postgres e deploy.

9 min de leitura

Introdução

Docker é uma ferramenta que permite empacotar sua aplicação Python junto com todas as dependências em um container isolado. Isso garante que o código funcione da mesma forma no seu computador, no servidor de produção, no CI e na máquina de qualquer colega de equipe.

Em 2026, Docker deixou de ser apenas uma habilidade de DevOps. Ele aparece em vagas Python de backend, dados, IA, QA, plataforma e automação porque facilita testes reproduzíveis, deploy previsível e integração com serviços como PostgreSQL, Redis, workers e observabilidade. Se você quer transformar um projeto de portfólio em algo próximo de produção, saber criar um Dockerfile limpo e um docker-compose.yml honesto é uma das formas mais rápidas de mostrar maturidade técnica.

Neste guia, vamos configurar Docker para projetos Python, criar Dockerfiles otimizados, usar Docker Compose para aplicações com múltiplos serviços e fechar com uma checklist de produção. Se você ainda está no começo, leia também ambientes virtuais em Python antes de containerizar; Docker não substitui organização de dependências, ele empacota essa organização.

Pré-requisitos

Instale o Docker Desktop no seu sistema operacional:

  • macOS: brew install --cask docker ou baixe em docker.com
  • Windows: baixe o Docker Desktop e habilite o WSL 2
  • Linux: instale via gerenciador de pacotes da sua distribuição

Verifique a instalação:

docker --version
docker compose version

Conceitos básicos

  • Imagem: template somente leitura que define o ambiente (sistema operacional, Python, dependências)
  • Container: instância em execução de uma imagem
  • Dockerfile: arquivo de instruções para construir uma imagem
  • docker-compose.yml: arquivo que define múltiplos containers e como eles se conectam
  • Volume: armazenamento persistente ou pasta montada no container
  • Rede: camada que permite um container acessar outro pelo nome do serviço

Uma boa regra mental: o Dockerfile descreve como construir a aplicação; o Compose descreve como rodar essa aplicação junto com dependências locais. Misturar as duas responsabilidades costuma gerar imagens frágeis e difíceis de publicar.

Primeiro Dockerfile para Python

Crie um projeto simples com uma aplicação Flask:

meu-projeto/
    app.py
    requirements.txt
    Dockerfile

O app.py:

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return {'mensagem': 'Olá do Docker!'}


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

O requirements.txt:

flask==3.1.0
gunicorn==23.0.0

Agora o Dockerfile:

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

Cada linha do Dockerfile é uma instrução:

  • FROM: define a imagem base (Python 3.12 na versão slim, mais leve)
  • WORKDIR: define o diretório de trabalho dentro do container
  • COPY requirements.txt .: copia apenas o requirements primeiro (otimiza cache)
  • RUN pip install: instala as dependências
  • COPY . .: copia o restante do código
  • EXPOSE: documenta a porta usada
  • CMD: comando executado quando o container inicia

Construindo e executando

# Construir a imagem
docker build -t meu-projeto .

# Executar o container
docker run -p 5000:5000 meu-projeto

Acesse http://localhost:5000 e verá a resposta JSON da aplicação.

O arquivo .dockerignore

Crie um .dockerignore para evitar copiar arquivos desnecessários:

venv/
__pycache__/
*.pyc
.git/
.env
*.md
.pytest_cache/

Isso reduz o tamanho da imagem e acelera o build.

Evite colocar *.md no .dockerignore se a aplicação usa arquivos Markdown em tempo de execução. Para APIs e aplicações web comuns, excluir documentação é seguro; para sites estáticos, geradores de conteúdo ou pipelines que leem Markdown, ajuste a lista.

Dockerfile seguro para FastAPI

O exemplo mínimo acima funciona, mas projetos reais precisam de alguns cuidados extras: não rodar como root, instalar dependências de forma previsível, expor logs imediatamente e preparar um endpoint de saúde.

Um exemplo para FastAPI:

api-pedidos/
    app/
        main.py
    requirements.txt
    Dockerfile
    .dockerignore

app/main.py:

from fastapi import FastAPI

app = FastAPI(title="API de pedidos")


@app.get("/saude")
def saude():
    return {"status": "ok"}


@app.get("/pedidos/{pedido_id}")
def buscar_pedido(pedido_id: int):
    return {"pedido_id": pedido_id, "status": "processando"}

requirements.txt:

fastapi==0.115.6
uvicorn[standard]==0.34.0

Dockerfile:

FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /app

RUN addgroup --system app && adduser --system --ingroup app app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY --chown=app:app . .

USER app

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/saude')"

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Pontos importantes desse Dockerfile:

  • PYTHONDONTWRITEBYTECODE=1 evita arquivos .pyc dentro do container.
  • PYTHONUNBUFFERED=1 faz os logs aparecerem em tempo real.
  • adduser cria um usuário sem privilégios para rodar a aplicação.
  • COPY requirements.txt antes do código melhora o cache de build.
  • HEALTHCHECK permite que Docker, CI e orquestradores detectem quando a API não responde.

Se a API usa FastAPI em produção, combine este guia com API com FastAPI, OpenTelemetry com Python e deploy de aplicação Python. Docker resolve empacotamento; observabilidade e deploy ainda precisam ser tratados explicitamente.

Docker Compose para múltiplos serviços

Aplicações reais geralmente precisam de banco de dados, cache e outros serviços. O docker-compose orquestra tudo isso.

Crie o docker-compose.yml:

services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/app
    environment:
      - DATABASE_URL=postgresql://usuario:senha@db:5432/meu_banco
      - REDIS_URL=redis://redis:6379/0
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_started

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: usuario
      POSTGRES_PASSWORD: senha
      POSTGRES_DB: meu_banco
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U usuario -d meu_banco"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:

Esse Compose é suficiente para desenvolver uma API com banco e cache local. Para filas e tarefas assíncronas, o mesmo Redis pode servir como broker de Celery em projetos simples; aprofunde em FastAPI Background Tasks, Celery e Redis e no verbete Celery.

Inicie todos os serviços:

docker compose up -d

Comandos úteis do docker-compose:

# Ver logs
docker compose logs -f web

# Parar tudo
docker compose down

# Reconstruir após mudanças no Dockerfile
docker compose up --build

# Executar comando dentro do container
docker compose exec web python manage.py migrate

Multi-stage build

Para imagens de produção menores, use multi-stage build:

# Estágio 1: Build
FROM python:3.12-slim AS builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# Estágio 2: Produção
FROM python:3.12-slim

WORKDIR /app
COPY --from=builder /install /usr/local
COPY . .

RUN useradd --create-home appuser
USER appuser

EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

Isso cria uma imagem final que contém apenas o necessário para rodar a aplicação, sem ferramentas de build.

Use multi-stage principalmente quando o projeto instala dependências nativas, compila assets ou precisa de ferramentas de build que não devem ficar na imagem final. Para aplicações pequenas com dependências puramente Python, um Dockerfile simples, bem cacheado e não-root já pode ser suficiente.

Dockerfile para Django

Para projetos Django, o Dockerfile precisa de alguns ajustes:

FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

WORKDIR /app

RUN apt-get update && apt-get install -y \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .
RUN python manage.py collectstatic --noinput

EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "config.wsgi:application"]

As variáveis de ambiente PYTHONDONTWRITEBYTECODE e PYTHONUNBUFFERED são boas práticas para containers Python. A primeira evita arquivos .pyc desnecessários e a segunda garante que os logs apareçam em tempo real.

Variáveis de ambiente e segredos

Nunca coloque senhas diretamente no Dockerfile ou docker-compose.yml. Use arquivos .env:

# .env (não commitar no git!)
DATABASE_URL=postgresql://usuario:senha@db:5432/meu_banco
SECRET_KEY=minha-chave-secreta
DEBUG=False

No docker-compose.yml:

services:
  web:
    build: .
    env_file:
      - .env

O .env local deve ficar no .gitignore. Em produção, prefira o gerenciador de segredos da plataforma: variáveis do Cloudflare, Render, Railway, Fly.io, Kubernetes Secret, Docker Swarm secret ou cofre interno. O ponto essencial é não gravar segredo em imagem, repositório, log ou exemplo público.

Testes, dados e CI dentro do container

Docker também ajuda a validar que o projeto roda fora da sua máquina. Um fluxo comum de CI é construir a imagem, subir dependências e rodar testes:

docker compose build
docker compose run --rm web pytest
docker compose run --rm web python -m pip check

Para projetos de dados, rode uma amostra do pipeline dentro do container para garantir que versões de Pandas, conectores e bibliotecas nativas estão corretas. Se a dor principal é qualidade de entrada, leia Pandera com Python e conecte validação de dados ao build: um pipeline que só funciona no notebook ainda não é reproduzível.

Em APIs, rode pelo menos testes unitários, teste de healthcheck e uma chamada HTTP local. Exemplo:

docker compose up -d
curl -fsS http://localhost:8000/saude
docker compose logs --no-color web
docker compose down

Esse tipo de evidência aparece bem em README de portfólio: mostra que você pensou em instalação, teste, logs e operação, não apenas na feature principal.

Boas práticas

  • Use imagens slim para reduzir tamanho sem herdar as surpresas de compatibilidade do Alpine
  • Copie requirements.txt antes do código para aproveitar o cache de layers
  • Crie um usuário não-root para rodar a aplicação
  • Defina PYTHONDONTWRITEBYTECODE=1 e PYTHONUNBUFFERED=1
  • Use .dockerignore para excluir arquivos desnecessários
  • Fixe versões das dependências no requirements.txt
  • Use health checks no docker-compose para verificar se os serviços estão saudáveis
  • Não coloque .env, chaves ou dumps de produção na imagem
  • Separe Compose local de configuração real de produção
  • Registre logs em stdout/stderr para facilitar coleta por Docker, CI e plataformas de deploy
  • Documente comandos de build, teste e execução no README

Erros comuns em Docker com Python

Alguns problemas se repetem em projetos de iniciantes e testes técnicos:

ErroConsequênciaComo corrigir
Copiar o projeto inteiro antes do pip installqualquer mudança invalida o cachecopie requirements.txt primeiro
Rodar como rootrisco maior se a aplicação for exploradacrie appuser e use USER appuser
Usar volume em produção como no desenvolvimentocódigo local sobrescreve a imagemlimite volumes ao Compose local
Esquecer healthcheckfalhas viram timeout misteriosocrie /saude e teste com curl ou Python
Guardar segredo no Dockerfilevazamento no repositório ou registryuse variáveis e cofre de segredos
Não testar o container no CIdeploy quebra fora da máquina localrode docker compose run --rm web pytest

Docker no portfólio e em vagas Python

Para vagas júnior e pleno, Docker costuma aparecer como diferencial prático: a pessoa avaliadora consegue clonar o repositório, rodar um comando e ver o projeto funcionando. Isso vale para APIs, automações, pipelines de dados, web scraping, bots internos e aplicações Django.

Um bom README de projeto Python com Docker deve incluir:

  • objetivo do projeto;
  • tecnologias usadas;
  • comando para copiar .env.example;
  • docker compose up --build;
  • URL local para testar;
  • comando de testes;
  • explicação curta de Postgres, Redis, filas ou serviços externos;
  • observações de deploy.

Se você está montando evidência para carreira, conecte este guia com projetos de portfólio Python, teste técnico Python e vagas Python. Docker não substitui código limpo, testes e domínio do problema, mas reduz fricção para quem avalia seu trabalho.

Conclusão

Docker simplifica o desenvolvimento e deploy de aplicações Python, eliminando problemas de “funciona na minha máquina”. Com Dockerfiles otimizados, Docker Compose, healthchecks, usuário não-root e testes rodando no container, você pode configurar ambientes complexos com poucos comandos e entregar projetos mais fáceis de revisar.

Docker também é amplamente usado com outras linguagens de backend. Veja conteúdos de Go no golang.com.br para comparar como binários estáticos mudam a estratégia de imagem em serviços compilados.