Deploy de Docker em produção: do compose ao cluster com alta disponibilidade

Docker Compose resolve o dev. Em produção basta até um servidor sem SLA. Acima disso, você precisa de cluster real. Trajetória honesta dos quatro estágios de maturidade.

Equipe HeroCtl··15 min

O fluxo é familiar pra qualquer dev que cresceu nos últimos cinco anos. Você escreve um docker-compose.yml com três serviços, roda docker compose up na sua máquina, funciona. Sobe num VPS de staging, funciona. Move pra produção apontando o DNS, e funciona — até a primeira sexta-feira às cinco da tarde em que para de funcionar.

O ponto exato em que "funciona em produção" deixa de ser verdade depende muito menos de qual ferramenta você escolheu, e muito mais de qual estágio de maturidade o seu produto atingiu. Esse post mapeia os quatro estágios pelos quais quase todo time passa, mostra os sinais práticos de que você precisa subir o degrau, e deixa explícito quando você ainda não precisa.

Não é um post anti-compose, nem um post pró-cluster. É um post sobre quando cada coisa cabe.

Por que o Docker Compose foi tão bem em desenvolvimento

Antes de falar sobre os estágios, vale entender o que o Compose foi desenhado pra ser. Ele resolve um problema muito específico e resolve bem: orquestrar múltiplos contêineres na mesma máquina, declarando dependências, redes, volumes e variáveis de ambiente num único arquivo legível.

As premissas embutidas nesse desenho são as premissas de quem está desenvolvendo:

  • Uma máquina só. A sua.
  • Um usuário só. Você.
  • Restart manual. Quando dá problema, você abre o terminal e digita.
  • Dados efêmeros. Se o banco zerar, você roda o seed de novo.
  • Ninguém depende disso ficar de pé. Se cair às três da manhã, o mundo continua.

Em produção, todas as cinco premissas se invertem:

  • N máquinas. Você não está mais sozinho.
  • N usuários. Eles não te conhecem.
  • Restart automático é exigência mínima. Ninguém vai acordar você às quatro da manhã. Idealmente, ninguém vai acordar ninguém.
  • Os dados importam. Perder o banco vira incidente reportável.
  • Alguém dorme com isso ativo. Possivelmente um cliente, possivelmente um contrato com multa.

O Docker Compose continua funcionando fora das premissas originais. Ele faz funcionar — só faz mal. Os atalhos que parecem inocentes em desenvolvimento (rede compartilhada entre serviços, volume montado direto no host, log saindo no terminal) viram pegadinhas quando o ambiente muda de "uma máquina onde eu sei tudo o que está rodando" pra "três máquinas onde algo precisa estar rodando vinte e quatro horas por dia".

Os quatro estágios a seguir mostram a curva natural de quem leva o mesmo docker-compose.yml desde o hobby até o SaaS com SLA contratual.

Estágio 1: Compose em um único VPS

O ponto de entrada mais honesto do Docker em produção. Um VPS barato, um arquivo docker-compose.yml, e docker compose up -d resolvendo a vida.

Setup mínimo viável:

  • 1 VPS com 1–2 vCPUs e 2 GB de RAM (custa cerca de R$30 por mês em provedor brasileiro decente).
  • Docker e Docker Compose instalados via script oficial.
  • Todos os serviços com restart: always no compose.
  • Volumes nomeados pra dados (não bind mounts apontando pra /opt/app/data).
  • Um cron diário rodando pg_dump e mandando pro S3 ou pra um Backblaze B2.

Pra quem isso funciona:

Hobby projects, MVPs validando product-market fit, ferramentas internas pro time, painéis administrativos privados, blogs pessoais. Qualquer aplicação onde a frase "se ficar fora cinco minutos, ninguém morre" é literalmente verdadeira.

Riscos que você está aceitando explicitamente:

  • O VPS cai (manutenção do provedor, pico de noisy neighbor, hardware) e o seu serviço cai junto. Não tem fail-over.
  • O disco morre, e se você não estiver fazendo backup, perdeu os dados. Os SSDs de provedor cloud falham menos do que os do data center antigo, mas falham. Acontece.
  • Cada deploy tem uma janela de cerca de 30 segundos entre docker compose down e docker compose up em que o serviço fica fora.
  • Você é o sysadmin. Patch de kernel, atualização de Docker, rotação de log, monitoramento de disco — tudo na sua mão.

Limites práticos:

Aguenta confortavelmente 1 a 3 aplicações pequenas, tráfego na casa de 100 requisições por segundo, e tolerância de 5 a 30 minutos de downtime mensal. Se algum desses números for forçado pra cima, você está abusando do estágio.

O backup que ninguém faz e devia fazer:

# /etc/cron.daily/db-backup
docker exec postgres pg_dump -U app app \
  | gzip \
  | aws s3 cp - s3://meu-bucket/backups/$(date +%F).sql.gz

Sem isso, você não está em produção. Está em "desenvolvimento exposto na internet". A diferença entre um e outro é exatamente este cron.

Estágio 2: Compose com auto-update e roteador na frente

A primeira evolução natural. Você ainda tem um VPS, mas agora ele tem dois andares: um roteador que termina TLS e distribui as requisições, e os contêineres da aplicação atrás dele.

Setup:

  • 1 VPS um pouco mais robusto (2–4 vCPUs, 4–8 GB), girando em torno de R$50 a R$80 por mês.
  • Mesma stack do estágio anterior, mais um reverse proxy (Caddy ou um Traefik standalone) terminando TLS automaticamente via Let's Encrypt.
  • Watchtower (ou equivalente) puxando imagens novas do registro periodicamente.
  • Pipeline simples no GitHub Actions ou GitLab CI que builda a imagem, manda pro registro, e deixa o Watchtower descobrir.
  • Backup automatizado igual ao estágio 1, agora com retenção mais longa.

Pra quem funciona:

Indie hackers com 2 a 5 aplicações pequenas, primeiro cliente pago num produto SaaS lateral, agência hospedando sites para clientes sem SLA contratual, ferramentas internas que cresceram além da fase "três pessoas usam".

O que melhorou em relação ao estágio 1:

Deploy ficou seamless do ponto de vista do desenvolvedor. Você dá git push, o CI builda e publica, e dois minutos depois a versão nova está no ar sem você ter feito SSH em servidor nenhum. TLS automático resolve uma dor que costumava consumir uma tarde por trimestre. Múltiplas aplicações compartilham o mesmo certificado wildcard via roteador.

O que ainda dói:

Watchtower puxa qualquer imagem nova sem pensar duas vezes. Não há rolling deploy — durante o swap, a aplicação fica indisponível por algo entre 10 e 30 segundos. Não há health check de verdade antes de promover a versão nova; se você publicou uma imagem quebrada, o serviço fica fora até você notar e revertir manualmente. E o ponto único de falha continua: o VPS que cai derruba tudo.

Limites práticos:

5 a 10 aplicações no mesmo servidor, tráfego de até 500 requisições por segundo (depende muito do tipo de carga), tolerância de 5 a 15 minutos de downtime mensal. Se você começou a perder noite de sono porque o Watchtower atualizou algo às três da manhã e quebrou, você passou do estágio.

Estágio 3: Multi-server com Docker Swarm

Aqui a conversa muda. Você sai de "uma máquina robusta" pra "três máquinas se virando juntas". O Docker Swarm é o degrau natural pra quem já está confortável com Compose: o arquivo é praticamente o mesmo, o vocabulário é o mesmo, e o salto conceitual é menor do que pular direto pro Kubernetes.

Setup:

  • 3 ou mais VPS de tamanho médio. Três é o mínimo prático pra que o cluster sobreviva à perda de uma máquina.
  • docker swarm init no primeiro nó, docker swarm join nos outros dois.
  • Stack file (docker stack deploy -c stack.yml meuapp) em vez de docker-compose up.
  • Roteador integrado ao cluster (o Traefik tem modo Swarm nativo) escutando os eventos do daemon e rebalanceando automaticamente.
  • Logs e métricas centralizados? Você monta por fora. Não vem na caixa.

Pra quem funciona:

SaaS B2B com primeiro contrato exigindo "best-effort 99%", time já tem um dev confortável com terminal e disposto a aprender, aplicação cresceu além do que cabe num VPS único sem dor.

A elefante na sala:

O Docker Swarm está em modo de manutenção desde 2019. A Docker Inc. não investe ativamente em features novas. Bugs críticos ainda são corrigidos, mas o ecossistema de plugins estagnou, e a evolução do scheduler praticamente parou. Funciona — milhares de empresas rodam Swarm em produção sem problemas hoje. Mas você está apostando numa tecnologia cuja trajetória de investimento foi cortada há mais de cinco anos.

A versão honesta disso: se você adota Swarm em 2026, está adotando com a expectativa de eventualmente migrar pra outra coisa. Não é um problema imediato — é um problema que aparece quando você precisar de algo que o Swarm nunca vai ganhar.

Limites práticos:

3 a 30 servidores, tráfego na casa de 5 mil requisições por segundo agregadas, tolerância de 5 a 30 segundos de failover quando uma máquina cai. Acima disso, ou você complementa com peças externas (observability stack, autoscaler manual, DNS GSLB), ou você sobe pro próximo degrau.

Onde mais dói no dia a dia:

A overlay network sob carga alta tem edge cases conhecidos, principalmente em redes de provedor cloud com MTU não-padrão. Recovery após split-brain em alguns cenários precisa de intervenção manual — o cluster não se recompõe sozinho em 100% dos casos. E qualquer coisa que envolva observabilidade detalhada (métricas persistidas, logs estruturados, tracing distribuído) você monta separado, mantendo dois ou três produtos a mais.

Estágio 4: Cluster com plano de controle replicado

O degrau onde "produção" começa a ter o mesmo significado que tem em empresas de plataforma maduras. Você não está mais rodando um orquestrador legado em manutenção, nem dependendo de um único servidor pra continuidade.

Setup:

  • 3 a 5 servidores na configuração mínima, com o plano de controle replicado entre os três primeiros. Os demais entram como agentes.
  • Eleição automática de coordenador. Se o atual cair, em poucos segundos outro assume e o cluster continua aceitando deploys e atendendo tráfego.
  • Roteador integrado, certificados automáticos, health check antes de promover versão nova, rolling deploy com janelas configuráveis.
  • Métricas e logs como serviços internos do próprio cluster — você não monta cinco produtos pra ter observabilidade básica.
  • Submissão de jobs via CLI, API ou painel web. O cluster decide em qual servidor cada réplica vai rodar.

Pra quem funciona:

SaaS com SLA contratual de 99,9%, multi-tenant com requisitos formais de isolamento, time de plataforma de 1 a 3 pessoas, contratos B2B em que uptime é parte do SOW, qualquer empresa em que "ficar fora vinte minutos" gera reembolso.

Riscos que mudam de natureza:

A complexidade não some — ela muda de forma. Em vez de você operar três VPS na mão, você opera um cluster que resolve a maior parte dos problemas sozinho mas tem mais peças. Curva de aprendizado pra quem nunca operou cluster antes existe e é real. E é genuinamente overkill se você nunca vai além do estágio 2: três servidores rodando um app de hobby é desperdício.

Números concretos pra calibrar:

Um cluster pequeno bem configurado roda confortavelmente em 4 servidores totalizando 5 vCPUs e 10 GB de RAM, com o plano de controle ocupando entre 200 e 400 MB por servidor. A eleição de coordenador, quando o atual cai, leva cerca de 7 segundos até o cluster voltar a aceitar deploys. Comparativamente, a configuração equivalente no Kubernetes começa em centenas de linhas de manifesto pra um app "hello world" — e o HeroCtl resolve a mesma coisa em cerca de 50.

Limites práticos:

3 a 500 servidores. Acima disso, o ecossistema do Kubernetes gerenciado tem ferramentas que cluster pequeno não precisa: federação multi-região, scheduler avançado pra workloads heterogêneos, biblioteca profunda de operadores especializados pra databases stateful. Não é que cluster pequeno não escale — é que acima de 500 nós você está num mercado em que outras ferramentas têm cinco anos de vantagem.

Os quatro estágios lado a lado

CritérioEstágio 1 (compose 1 VPS)Estágio 2 (compose + auto-update)Estágio 3 (Docker Swarm)Estágio 4 (cluster replicado)
Custo mensal mínimo (BR, 2026)R$30R$50R$150 (3 VPS)R$200 (4 VPS)
Complexidade operacionalMínimaBaixaMédiaMédia-alta
Tempo até primeiro deploy15 minutos1 hora1 dia1 dia
Alta disponibilidade realNãoNãoSim, com ressalvasSim
Escala máxima realista1–3 apps5–10 apps30 servidores500 servidores
Deploys sem downtimeNãoQuaseSimSim
TLS automáticoManual ou pluginSim, embutidoSim, via roteadorSim, embutido
Observabilidade na caixaNãoNãoNãoSim
Time mínimo pra operar1 dev (parcial)1 dev (parcial)1 dev (dedicado)1 dev (parcial) ou 2 (parciais)
Faixa de aplicação idealHobby, MVPIndie hacker, primeiro clienteSaaS B2B early-stageSaaS com SLA, multi-tenant

A coluna que costuma surpreender é a de "time mínimo pra operar". O estágio 4 com ferramenta certa não exige mais gente do que o estágio 3 — exige gente que pensa diferente. O salto cognitivo é maior do que o salto operacional.

Os sinais de que é hora de subir o degrau

Subir antes de precisar é desperdício; ficar abaixo do necessário é dor. Os sinais práticos de cada transição:

Estágio 1 → Estágio 2. Você descobriu que precisa rodar mais de uma aplicação no mesmo VPS, deploys manuais começaram a ficar tensos (medo de derrubar produção às nove da noite de uma sexta), apareceu o primeiro cliente pago e ele tem expectativas — mesmo que não escritas — de que você não vá sumir por trinta minutos no meio do dia útil.

Estágio 2 → Estágio 3. Um cliente pediu SLA pela primeira vez, mesmo que informalmente ("quanto tempo no máximo isso pode ficar fora?"). Ou o VPS único caiu uma vez e você aprendeu na pele que precisava de redundância. Ou o time cresceu pra três ou mais pessoas e você não quer mais ser a única que sabe fazer deploy. Ou você está pagando R$300 por mês num VPS gigante quando três VPS médios resolveriam o mesmo com fail-over.

Estágio 3 → Estágio 4. Contrato B2B exige uptime medível e auditável (palavras como "99.9%" e "janela de manutenção" começaram a aparecer em proposta comercial). Compliance pediu auditoria detalhada e você precisa mostrar trilha de quem fez o quê. Ou — o sinal mais comum hoje — você está cansado dos patches do Swarm e quer uma ferramenta com roadmap claro pelos próximos cinco anos.

O sinal universal de "subiu cedo demais". Você está gastando mais tempo configurando infraestrutura do que escrevendo features de produto. Volta um degrau. Sério. A infra existe pra suportar o produto, não o contrário, e a maior parte das startups que morrem cedo morrem porque construíram plataforma sem cliente em vez de cliente sem plataforma.

A trajetória que não funciona

Três armadilhas comuns em que times caem ao tentar acelerar o salto:

Pular do compose direto pra Kubernetes. A tentação é genuína: "se vou ter que migrar uma vez, melhor migrar pra ferramenta líder de mercado e nunca mais". A realidade é mais cruel. Seis meses depois você ainda está lutando com manifestos de 300 linhas, operadores especializados, operadores de operadores, e gastando metade do tempo de engenharia em problemas que sequer existiam quando você rodava docker compose up. Enquanto isso, o concorrente mais simples shipou doze features. K8s vale a pena num momento muito específico — quando você já sabe que vai escalar pra 50+ servidores, tem time pra operar, e os problemas que ele resolve são problemas que você de fato tem. Antes disso, é capital queimado.

Ficar no compose por orgulho. O outro extremo. "DevOps complicado é overkill, eu não preciso, sempre rodei tudo num VPS e nunca tive problema". A realidade chega na primeira sexta-feira às cinco da tarde em que o disco do VPS morre, o backup do mês passado tem três semanas, e você descobre simultaneamente que (a) precisava de HA e (b) precisava de procedimento de recuperação testado. Os dois aprendizados num único final de semana são caros.

Comprar a stack porque está hype. Service mesh, observability stack completa com cinco produtos, GitOps com dois repositórios e três pipelines, autoscaler com policies sofisticadas — pra uma aplicação de três contêineres servindo 200 usuários ativos. Você está construindo plataforma sem ter usuário pra plataforma. A mesma energia investida em features do produto teria gerado dez vezes mais retorno. Se você está num estágio anterior, não importa quão bonita a ferramenta do estágio seguinte seja.

Detalhes técnicos que valem em qualquer estágio

Algumas decisões valem desde o estágio 1 e seguem valendo no estágio 4. Vale gastar três parágrafos nelas porque cada uma já causou dor em produção pra muita gente.

Restart policies. No Compose, restart: always é o caminho certo pra quem quer que o contêiner volte sozinho depois de qualquer falha. on-failure é mais econômico mas vai te morder quando o processo der exit 0 por engano. No Swarm, restart_policy.condition: any faz papel similar. Em qualquer estágio, pensar na política de restart é parte de pensar no design da aplicação — não é detalhe.

Health checks. Toda aplicação que aceita HTTP precisa expor um endpoint /healthz retornando 200 quando está saudável. Sem isso, nenhum orquestrador acima do estágio 1 consegue distinguir "contêiner subiu" de "contêiner subiu e está realmente atendendo tráfego". Timeout razoável: 5 segundos. Retry razoável: 3 vezes antes de marcar como unhealthy. Sem isso, você vai entrar em restart loops e demorar horas pra entender o que está acontecendo.

Volumes nomeados versus bind mounts. Volumes nomeados (volumes: [meudata:/var/lib/postgresql/data]) sobrevivem a recriação do contêiner, são gerenciados pelo Docker, e funcionam consistentemente entre estágios. Bind mounts (./data:/var/lib/postgresql/data) dependem do filesystem do host, têm comportamento estranho com SELinux e AppArmor, e quebram quando o contêiner muda de máquina (estágio 3 e 4). Use bind mount só pra desenvolvimento e pra arquivos de configuração read-only.

Logs. Stdout e stderr é o caminho certo, sempre. Aplicação que escreve log em arquivo dentro do contêiner é aplicação que vai te dar dor de cabeça. O orquestrador captura stdout, roteia pra onde precisa ir (driver syslog, agregador externo, serviço interno), e você nunca mais precisa exec dentro do contêiner pra ver o que aconteceu.

Secrets. Variáveis de ambiente em arquivo .env são confortáveis e perigosas — vazam em log, em backup, em snapshot. Pra estágio 1 e 2, dá pra viver com elas se você for cuidadoso. Pra estágio 3 em diante, use o mecanismo nativo de secrets do orquestrador. Em ferramentas mais novas (HeroCtl incluso), o cofre é parte do cluster — você não monta um produto separado só pra guardar senha.

Custo concreto de cada estágio (Brasil, 2026)

A matemática crua, sem floreios:

  • Estágio 1. 1 VPS de R$30 por mês = R$360 por ano. Tempo de setup inicial: uma tarde. Tempo de operação contínua: cerca de 1 hora por mês.
  • Estágio 2. 1 VPS de R$50 por mês = R$600 por ano. Tempo de setup: um dia. Tempo de operação: cerca de 2 horas por mês, principalmente lidando com Watchtower atualizando algo que não devia.
  • Estágio 3. 3 VPS de R$50 = R$150 por mês = R$1.800 por ano. Tempo de setup: cerca de 3 dias até estar confortável. Tempo de operação: 4 a 8 horas por mês, dependendo de quantos jobs rodam.
  • Estágio 4 (HeroCtl Community). 4 VPS de R$50 = R$200 por mês = R$2.400 por ano. Tempo de setup: 1 a 2 dias até estar confortável. Tempo de operação: comparável ao estágio 3, mas sem os patches manuais e com observabilidade na caixa.

E pra calibrar a comparação que muita gente faz cedo demais: Kubernetes gerenciado pra a mesma escala custa entre R$700 e R$1.500 por mês de plano de controle e load balancers, então R$8,4k a R$18k por ano só de infraestrutura — sem contar os 1 a 2 SREs (R$25k a R$35k por mês cada) que esse estágio passa a exigir. A diferença entre estágio 4 e Kubernetes gerenciado, no quesito custo total, costuma ser de uma ordem de grandeza inteira.

Perguntas que a gente recebe

Compose com restart: always não é suficiente? É suficiente até a primeira coisa que restart: always não cobre: o VPS inteiro indisponível, o disco corrompido, a falha de rede do provedor, ou um deploy que sobe imagem quebrada e entra em loop sem alguém pra notar. Pra hobby project, suficiente; pra cliente pago, é o ponto de início, não o ponto de chegada.

Docker Swarm está realmente deprecated? Não no sentido oficial — a Docker Inc. não anunciou descontinuação. Mas está em manutenção, sem features novas relevantes desde 2019, e o ecossistema de plugins parou de crescer. Funciona em produção hoje. Uma escolha defensável pra quem já está nele. Uma escolha questionável pra quem está adotando agora em 2026.

Quando vale subir pra Kubernetes gerenciado? Quando você tem mais de 50 servidores, time de plataforma com 3+ pessoas dedicadas, e problemas específicos que o ecossistema do K8s resolve melhor (federação multi-região, autoscaling sofisticado, biblioteca profunda de operadores stateful). Antes disso, está pagando o custo sem usar o benefício.

Watchtower é seguro? Razoavelmente, com ressalvas. Ele puxa qualquer imagem nova publicada na tag que você está apontando, sem distinguir entre "atualização que você publicou" e "imagem comprometida que alguém empurrou via cadeia de suprimento". Pra estágio 2, o trade-off vale: o ganho operacional supera o risco. Pra estágios maiores, prefira mecanismos que validam imagem antes de promover.

Como faço backup de volume Docker no estágio 1? Cron diário rodando docker exec no contêiner do banco com o utilitário de dump nativo (pg_dump, mysqldump, etc.), pipe pra gzip, e upload pra storage objeto fora do mesmo provedor. A regra de ouro: o backup tem que viver longe do dado primário. Se o data center cair, o backup precisa estar em outro data center.

Posso pular do estágio 1 direto pro 4? Tecnicamente sim, especialmente com ferramentas que fazem o salto suave (HeroCtl é uma delas, instala em minutos e roda confortavelmente em 3 servidores). Recomendado, só se você já sabe que vai precisar do estágio 4 nos próximos seis meses. Caso contrário, o estágio 2 te ensina coisas (deploy automatizado, TLS, registry de imagens) que você vai usar de qualquer jeito mais tarde.

E se eu não souber Linux profundamente? Estágio 1 e 2 são muito acessíveis com conhecimento básico. Estágio 3 começa a exigir entendimento de rede (overlay networks, MTU, iptables ocasional). Estágio 4, com a ferramenta certa, abstrai a maior parte da complexidade — mas debug de incidente ainda exige saber ler log de systemd, entender o que dmesg está dizendo, e diagnosticar disco cheio. Não há mágica que substitua os fundamentos quando algo dá errado às três da manhã.

Fechando

A maturidade não é virtude moral. Não é "melhor" estar no estágio 4 do que no estágio 1 — é melhor estar no estágio que combina com o tamanho do problema que você está resolvendo. Hobby project no estágio 4 é desperdício de capital e atenção; SaaS com cinquenta clientes pagantes no estágio 1 é negligência operacional.

O HeroCtl existe pra tornar o estágio 4 acessível pra quem antes precisava escolher entre o desconforto do Swarm e o custo do Kubernetes. Se você sente que passou do estágio 2 e está pesando entre as opções:

curl -sSL https://get.heroctl.com/install.sh | sh

Instala em minutos, roda confortavelmente em 3 a 5 servidores, e tem plano Community gratuito permanente — sem feature gate artificial, sem limite de servidores, sem amarração contratual. Os planos Business e Enterprise existem pra empresas com requisitos formais de SSO, auditoria detalhada e suporte com SLA, e os preços estão publicados sem "fale com vendas" obrigatório.

Pra quem está comparando ferramentas no mesmo nicho, dois posts complementares: HeroCtl vs Coolify cobre o trade-off de adotar uma ferramenta com HA real versus um painel single-server elegante; HeroCtl vs Dokploy cobre a diferença de adotar um cluster com plano de controle replicado versus um painel que internamente roda Swarm.

E se a pergunta for "qual estágio combina comigo agora?", a resposta honesta quase sempre é: o anterior ao que você acha que precisa. Volta um, fica até doer, sobe quando doer mesmo.

#docker#deploy#producao#cluster#ha#engenharia