Docker Compose em produção: tutorial passo a passo para SaaS

03/11/2026  ·  Devskin

Docker Compose em produção: tutorial passo a passo para SaaS

O Docker Compose é a forma mais direta de descrever uma stack completa (aplicação, banco, cache e proxy) em um único arquivo versionado. Para um SaaS em estágio inicial ou uma ferramenta interna, ele entrega previsibilidade sem a complexidade operacional de um cluster. Neste tutorial, você monta uma stack pronta para produção em uma VM Linux, com boas práticas que evitam os erros mais comuns.

Quando o Docker Compose faz sentido (e quando não)

Antes de executar qualquer comando, entenda o trade-off. O Docker Compose roda em um único host. Isso simplifica o deploy e reduz custo, mas cria um ponto único de falha e limita a escala horizontal.

  • Faz sentido: MVPs, SaaS com poucas dezenas de clientes, ambientes de staging, serviços internos e workloads previsíveis.
  • Não faz sentido: requisitos de alta disponibilidade multi-nó, autoscaling ou deploys com zero downtime garantido. Nesses casos, avalie Kubernetes ou um orquestrador gerenciado.

Uma VM bem dimensionada com Docker Compose costuma ser um bom ponto de partida para controlar custos. Se você quer aprofundar essa lógica, leia Custo de cloud: como reduzir até 70% sem perder performance.

Passo 1: organize a estrutura do projeto

Mantenha tudo em um repositório de infraestrutura, separado do código da aplicação quando possível:

deploy/
  compose.yaml
  Caddyfile
  .env
  secrets/
    db_password.txt
  backups/

Adicione .env e secrets/ ao .gitignore. Versione apenas um arquivo .env.example com as chaves, sem valores sensíveis.

Passo 2: escreva o compose.yaml de produção

O arquivo abaixo define proxy reverso com TLS automático (Caddy), aplicação, PostgreSQL e Redis. Nas versões atuais do Compose, a chave version é obsoleta e pode ser omitida.

services:
  proxy:
    image: caddy:2
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
    depends_on:
      - app
    restart: unless-stopped

  app:
    image: registry.exemplo.com/meu-saas:1.4.2
    env_file: .env
    secrets:
      - db_password
    healthcheck:
      test: [CMD, wget, -qO-, http://localhost:3000/health]
      interval: 15s
      timeout: 3s
      retries: 5
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped

  db:
    image: postgres:16
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: [CMD-SHELL, pg_isready -U app -d app]
      interval: 10s
      retries: 5
    restart: unless-stopped

  cache:
    image: redis:7
    restart: unless-stopped

secrets:
  db_password:
    file: ./secrets/db_password.txt

volumes:
  pgdata:
  caddy_data:

Decisões que importam neste arquivo

  • Tags fixas: evite latest. Fixar a versão torna o deploy reproduzível e o rollback trivial.
  • Sem portas expostas no banco e no cache: apenas o proxy publica portas. Os demais serviços conversam pela rede interna criada pelo Compose.
  • Healthchecks com service_healthy: a aplicação só sobe depois que o Postgres aceita conexões. Isso evita crash loops na inicialização.
  • Volumes nomeados: os dados do banco sobrevivem à recriação dos containers.
  • Restart policy: unless-stopped religa os serviços após reboot da VM.

Se ainda está decidindo o banco da stack, veja o comparativo técnico entre PostgreSQL e MySQL.

Passo 3: configure segredos e rotação de logs

Use secrets em vez de colocar senhas diretamente em variáveis de ambiente. Com o Docker Compose, o segredo é montado como arquivo em /run/secrets, o que reduz o risco de vazamento via docker inspect ou dumps de ambiente. Lembre-se de que isso não substitui um cofre dedicado, como Vault ou o gerenciador de segredos do seu provedor.

Configure também a rotação de logs, porque o driver padrão pode crescer sem limite e encher o disco:

    logging:
      driver: json-file
      options:
        max-size: 10m
        max-file: "3"

Adicione esse bloco aos serviços de maior volume de log, como app e proxy.

Passo 4: faça o deploy e as atualizações

Na VM, com Docker Engine e o plugin Compose instalados, o fluxo básico é:

docker compose config        # valida o arquivo
docker compose pull          # baixa as novas imagens
docker compose up -d         # recria só o que mudou
docker compose ps            # confere o estado e a saúde

Para atualizar, altere a tag da imagem no compose.yaml, faça commit e repita pull e up -d. O rollback é o caminho inverso, voltando à tag anterior.

Um ponto de honestidade técnica: o up -d recria o container alterado, e isso gera uma breve interrupção. Para minimizar o impacto, mantenha migrações de banco retrocompatíveis e use healthchecks. Se precisar de zero downtime real, adote blue-green com dois conjuntos de serviços atrás do proxy ou migre para um orquestrador.

Quando o fluxo estiver estável, automatize-o no pipeline: o CI constrói e publica a imagem, e um job de deploy conecta via SSH e executa os comandos acima.

Passo 5: backup e monitoramento mínimo

Volume persistente não é backup. Agende um dump lógico do PostgreSQL via cron e envie o arquivo para um armazenamento externo:

docker compose exec -T db pg_dump -U app app | gzip > backups/app-$(date +%F).sql.gz

Teste a restauração periodicamente, pois um backup nunca restaurado é apenas uma hipótese. Para monitoramento, comece simples: acompanhe o resultado de docker compose ps, o uso de disco, CPU e memória da VM e o endpoint /health com um verificador externo de uptime. Só depois evolua para métricas e tracing completos.

Conclusão

Dominar o Docker Compose em produção significa tratar o arquivo como infraestrutura: tags fixas, healthchecks, segredos fora do repositório, logs controlados e backups testados. Ele não resolve alta disponibilidade, mas entrega uma base enxuta e auditável para validar o produto antes de investir em orquestração. Quando a carga e os requisitos de SLA crescerem, essa mesma descrição de serviços facilita a migração para uma plataforma maior.

Contato

Envie uma mensagem

Entre em contato