Docker Compose: o que é, como usar e subir seu primeiro ambiente

Docker Compose é a ferramenta que descreve vários containers num arquivo só e sobe tudo com um comando. Veja o que instalar, como escrever o compose.yaml e os erros que mais aparecem.

Docker Compose: o que é, como usar e subir seu primeiro ambiente
Neste artigo
  1. O que o Docker Compose resolve, na prática?
  2. Quando usar Docker Compose e quando ele é exagero?
  3. O que precisa instalar para rodar Compose em 2026?
  4. Como fica o primeiro compose.yaml, linha a linha?
  5. Por que depends_on sozinho não resolve a ordem de subida?
  6. Quais comandos você usa de verdade no dia a dia?
  7. Como usar IA para gerar o arquivo sem decorar a sintaxe?
  8. Como validar se o ambiente subiu de verdade?
  9. Onde ficam as senhas e o que nunca vai para o repositório?
  10. Quais portas expor e como não abrir o banco para a internet?
  11. Como atualizar as imagens sem quebrar o ambiente?
  12. Quais são os erros mais comuns e como corrigir cada um?
  13. Quanto custa rodar Docker e Compose?
  14. Quando o Compose deixa de bastar e o que vem depois?
  15. Como eu uso o Compose no meu homelab e na operação?
  16. Quais são as dúvidas mais comuns sobre Docker Compose?
  17. Por onde começar hoje?

Docker Compose é a ferramenta do Docker que descreve um ambiente de vários containers num arquivo só e sobe tudo com um comando. Em menos de 30 minutos você instala o Docker, escreve um compose.yaml com aplicação, banco e cache, e confere que está funcionando, não só rodando. Este guia é o caminho completo, do requisito de máquina até o dia em que o Compose deixa de bastar.

Você já perdeu uma tarde porque o container subiu mas a aplicação não conectava no banco. Ou configurou tudo na mão numa máquina, foi rodar em outra e nada funcionou igual. Esse vai e vem é o desperdício que o Compose resolve, e a confusão nunca esteve na ferramenta. Esteve no excesso de tutorial mostrando comando solto sem explicar por que aquilo existe. Não precisa decorar sintaxe para começar, precisa entender o que cada peça faz e o que acontece quando ela falha.

Eu rodo serviços em container no dia a dia e tenho um homelab que vive de Compose. Já quebrei ambiente por não entender ordem de subida, já vazei senha por colocar no lugar errado. O que está aqui é o que eu queria ter lido antes de cada um desses tropeços. Todo número de versão, requisito e preço foi conferido na documentação oficial em 15/09/2026, com o endereço na tabela. Tutorial de Docker envelhece rápido, e o comando que você copia de 2021 não é mais o de hoje.

O que o Docker Compose resolve, na prática?

Imagine um projeto com três peças, uma aplicação, um banco de dados e um cache. Sem Compose você sobe cada uma separada com um docker run comprido, conecta uma na outra na mão, cria rede, cria volume. E refaz tudo isso toda vez que derruba o ambiente. Esquecer um detalhe é regra, não exceção, e o detalhe esquecido costuma ser justamente a senha ou a porta, que são os dois que mais custam caro.

Com Compose você descreve esse ambiente inteiro uma vez, num arquivo YAML, e sobe tudo junto com docker compose up. O arquivo vira a fonte da verdade do ambiente. Quem entra no projeto clona o repositório, roda um comando e tem exatamente o que você tem, e o servidor recebe o mesmo arquivo. Acabou o “na minha máquina funciona”, porque a máquina passou a ser descrita em texto versionado. E texto versionado dá para revisar, comparar e voltar atrás quando alguém quebra.

Vale dizer o que ele não é. Compose não é orquestrador de vários servidores, não faz escala automática e não substitui o Dockerfile. O Dockerfile continua sendo quem descreve como a imagem da sua aplicação é construída. O Compose coordena containers numa máquina só, e faz isso muito bem. Isso cobre quase todo projeto de pequeno e médio porte que eu vejo passar por aqui, do sistema interno de uma empresa ao SaaS que ainda cabe numa VPS.

Quando usar Docker Compose e quando ele é exagero?

O sinal mais claro é o projeto ter mais de uma peça. Assim que existe aplicação mais banco, ou mais um cache, ou qualquer combinação de serviços que conversam entre si, Compose já compensa. A rede entre eles e a ordem de subida passam a ser problema do arquivo, não seu. Uma peça só, tipo um script que roda e morre, nem precisa, um docker run resolve e o arquivo seria burocracia.

O segundo sinal é rodar o mesmo ambiente em lugares diferentes. Se mais de uma pessoa mexe no projeto, ou se ele roda no seu notebook e também numa VPS, a descrição única evita a divergência que aparece quando cada um sobe do seu jeito. O terceiro é querer subir e derrubar rápido, para teste, demo ou recomeço limpo. Esse ganho você só sente depois de usar: docker compose down, docker compose up, e o ambiente nasceu de novo em segundos.

Um exemplo concreto desse padrão, se você trabalha com modelo de machine learning, é subir MLflow no Docker para rastrear experimentos. Servidor, banco e armazenamento de artefato ficam num arquivo só, o tipo de stack que ninguém quer instalar na mão duas vezes. Onde ele vira exagero é o oposto: quando você precisa de vários servidores cooperando, com o container renascendo em outra máquina se uma cair. Disso eu falo mais para o fim do guia.

O que precisa instalar para rodar Compose em 2026?

Compose não se instala sozinho, ele vem junto do Docker. No Windows e no Mac o caminho recomendado pela própria Docker é o Docker Desktop, que já traz o Engine, a CLI e o plugin do Compose no mesmo instalador. No Linux de servidor, que é onde o ambiente vai morar, o caminho é o Docker Engine pelo repositório oficial. O pacote docker-compose-plugin entra na mesma linha de instalação. Os requisitos que costumam travar estão na tabela.

Item (conferido em 15/09/2026, fonte: documentação oficial da Docker)Versão ou requisitoOnde conferir
Docker Desktop, versão atual4.91.0, lançada em 14/09/2026notas de versão do Desktop
Docker Desktop no WindowsWindows 10 22H2 (build 19045) ou Windows 11 23H2 (build 22631) ou mais novo, 64 bitsinstalação no Windows
Backend WSL 2 no WindowsWSL 2.1.5 ou mais novo, processador 64 bits com SLAT, 8 GB de RAM, virtualização ligada na BIOSmesma página
Docker Engine no Linux, versão atual29.8.1, lançada em 15/09/2026notas de versão do Engine
Docker Engine no Ubuntu64 bits em Ubuntu 22.04, 24.04 ou 26.04 (LTS)instalação no Ubuntu
Docker Compose, versão atualv5.5.1, lançada em 03/09/2026releases no GitHub
Compose v1 (docker-compose, em Python)fora das versões suportadas, que hoje são a v2 e a v5histórico do Compose

Depois de instalar, o teste é docker compose version no terminal. Se a resposta começar com v2 ou v5, está pronto. Se o único comando que responde é docker-compose com hífen, você está na geração antiga em Python, que não está mais entre as versões suportadas e ignora recurso novo do arquivo. A versão 5 é funcionalmente igual à 2. A Docker pulou a numeração para não confundir com os formatos antigos de arquivo 2.x e 3.x, e o que ela trouxe de novo foi um SDK em Go para quem embute o Compose em outro programa.

No Windows eu uso pelo PowerShell e pelo Git Bash, os dois funcionam. O WSL 2 é o backend padrão do Desktop, então não precisa instalar um Linux separado para rodar container. Um detalhe de licença que pega empresa maior: o Docker Desktop é gratuito para uso pessoal, educação e empresa pequena. Empresa com mais de 250 funcionários ou mais de US$ 10 milhões de faturamento anual precisa de assinatura paga para uso comercial. O Engine no Linux não tem essa restrição, e é ele que roda no servidor.

Como fica o primeiro compose.yaml, linha a linha?

O arquivo abaixo é o ambiente que eu citei no começo: uma aplicação, um Postgres e um Redis. Eu rodei ele antes de publicar, com docker compose config para validar a sintaxe e docker compose up para ver os três subirem na ordem certa. O resultado está na seção de validação. Salve como compose.yaml na raiz do projeto, esse é o nome que o Compose procura primeiro. O docker-compose.yml antigo continua funcionando só por compatibilidade.

services:
  app:
    build: .
    ports: ["3000:3000"]
    env_file: .env
    depends_on:
      db:
        condition: service_healthy
        restart: true
      cache:
        condition: service_started
    restart: unless-stopped

  db:
    image: postgres:18
    env_file: .env
    volumes: ["dados-db:/var/lib/postgresql"]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped

  cache:
    image: redis:8-alpine
    restart: unless-stopped

volumes:
  dados-db:

A chave services é a lista de containers, e cada nome ali, app, db e cache, vira também o hostname que os outros usam para conversar. A aplicação conecta no banco pelo endereço db, porta 5432, sem IP nenhum, porque o Compose cria uma rede interna e resolve os nomes sozinho. Em app, build: . diz que a imagem sai do Dockerfile da mesma pasta. O ports publica a porta 3000 do container na 3000 da sua máquina, e o env_file carrega as variáveis do arquivo .env sem escrever nenhuma senha no YAML.

Em db, image: postgres:18 puxa a imagem oficial numa versão fixa. O mesmo env_file entrega POSTGRES_USER, POSTGRES_PASSWORD e POSTGRES_DB para dentro do container, e a senha é a única obrigatória para a imagem subir. O bloco volumes é o que faz o dado sobreviver: sem ele, o banco morre junto com o container. Repare que na imagem do Postgres 18 o ponto de montagem mudou para /var/lib/postgresql. Até a versão 17 era /var/lib/postgresql/data, um detalhe que faz tutorial antigo perder dado em silêncio.

O healthcheck roda pg_isready a cada 10 segundos, com 30 segundos de carência inicial e 5 tentativas, e é ele que define quando o banco está de fato pronto. O cifrão dobrado em $${POSTGRES_USER} manda o Compose deixar a variável para o container resolver, em vez de substituir na sua máquina. O restart: unless-stopped faz o container voltar sozinho depois de um reboot do servidor, a não ser que você tenha parado ele de propósito. E a chave version, que todo tutorial antigo põe na primeira linha, não está aí porque ficou obsoleta. O Compose de hoje ignora e ainda avisa que ela sobrou.

Por que depends_on sozinho não resolve a ordem de subida?

Esse é o erro que mais me custou tempo no começo. O depends_on simples garante que o container do banco foi criado e iniciado antes do container da aplicação, mas iniciado não é pronto. O Postgres leva alguns segundos entre o processo existir e aceitar conexão, e nesse intervalo a aplicação tenta conectar, falha e cai. O container do banco aparece como rodando, o da aplicação aparece como reiniciando. Você fica olhando para um container verde sem entender o vermelho do lado.

A solução está no arquivo acima: depends_on na forma longa, com condition: service_healthy, combinado com um healthcheck no serviço do banco. Com isso o Compose segura a criação da aplicação até o teste do banco passar. Você vê isso no terminal em duas linhas, Container db Waiting e depois Container db Healthy, antes de a aplicação começar. Para dependência sem healthcheck, tipo o Redis, service_started basta. E existe ainda service_completed_successfully, para um container de migração que precisa terminar antes de a aplicação abrir.

Um complemento que pouca gente usa é o restart: true dentro do depends_on. Ele reinicia a aplicação quando você reinicia o banco por um docker compose restart, para ela reabrir a conexão em vez de ficar segurando um socket morto. Não é obrigatório, mas em aplicação que não faz reconexão sozinha evita aquele estado em que tudo está no ar e nada responde. É o pior tipo de problema para diagnosticar às duas da manhã.

Quais comandos você usa de verdade no dia a dia?

São poucos, e na maior parte do tempo são três. docker compose up -d sobe o ambiente em segundo plano, docker compose ps mostra o que está rodando e em que estado. docker compose logs -f acompanha o registro de todos os serviços ao vivo, ou de um só se você passar o nome dele no fim. Quando algo quebra, o log é onde o erro real aparece, não na mensagem genérica que o up devolve.

Os outros entram conforme a necessidade. docker compose down derruba tudo e apaga a rede, mas preserva os volumes. O down -v apaga os volumes também, o que é irreversível e merece um segundo de atenção antes do Enter. docker compose pull baixa a versão nova das imagens, e docker compose exec db psql -U app abre um terminal dentro do container do banco. docker compose restart app reinicia um serviço só. E docker compose config imprime o arquivo já resolvido, com as variáveis substituídas, que é o jeito mais rápido de ver o que o Compose entendeu do que você escreveu.

Um hábito que vale adotar desde o primeiro dia é rodar docker compose config depois de editar o arquivo e antes de qualquer up. YAML é sensível a indentação, e um espaço a mais em volumes vira um erro de sintaxe que o config mostra na hora com número de linha. O up, sem esse passo, às vezes falha com uma mensagem que aponta para outro lugar, e te faz procurar o problema onde ele não está.

Como usar IA para gerar o arquivo sem decorar a sintaxe?

Você não precisa escrever o YAML na mão, e eu mesmo quase nunca escrevo. O que eu faço é descrever o ambiente em português para o Claude Code ou o Codex e pedir a configuração explicada. Quais peças o projeto tem, qual aplicação, qual banco, se usa cache, quais portas devem ficar acessíveis de fora e o que precisa sobreviver a um reinício. Quanto mais concreto o pedido, melhor o arquivo que volta. Pedido vago devolve arquivo genérico com porta aberta para tudo.

Não aceite só o arquivo pronto. Peça que a IA explique em palavras o que cada bloco faz, o que sobe primeiro e o que acontece quando você derruba o ambiente. É essa explicação que te deixa capaz de ler o log e corrigir sozinho depois. E cobre explicitamente três coisas que modelo de IA esquece com frequência: healthcheck com service_healthy no banco, segredo em .env separado do YAML, e comando na forma docker compose sem hífen. Tem muito tutorial de 2020 no treinamento, e a forma antiga ainda escapa.

Quando quebrar, cole o log de volta para a IA junto com o arquivo. Erro de Compose costuma ser localizado, porta ocupada, variável vazia, volume no caminho errado, e com o log na mão o modelo acerta de primeira na maioria das vezes. O que ele não faz por você é decidir o que precisa persistir e o que pode ficar exposto. Isso é decisão sua, e as próximas seções são exatamente sobre essas decisões.

Como validar se o ambiente subiu de verdade?

Subir não é o mesmo que funcionar, e a diferença entre os dois é onde a maioria perde tempo. O checklist que eu uso tem quatro passos. docker compose ps mostrando todos os serviços em Up, com healthy ao lado do banco. docker compose logs sem erro de conexão se repetindo. Um teste real da aplicação, um curl na porta publicada ou uma requisição que leia do banco. E um docker compose restart seguido de uma consulta que prove que o dado continua lá.

Esse quarto passo é o que quase ninguém faz e o que mais evita susto. Quando eu testei o arquivo deste post, criei uma tabela, inseri uma linha, reiniciei o banco e consultei de novo, e a linha estava lá. Isso prova que o volume está montado no caminho certo. Depois rodei docker compose down, conferi com docker volume ls que o volume sobreviveu, e só então o down -v para limpar. Se a linha some depois de um restart, o volume está no caminho errado ou nem existe. É melhor descobrir isso no primeiro dia do que no dia em que tem dado de cliente dentro.

Se a aplicação sobe antes do banco estar pronto, o sintoma é ela reiniciar em loop nos primeiros segundos e depois estabilizar, ou não estabilizar nunca. A correção é o healthcheck da seção anterior. O sinal de que funcionou é a linha Container db Healthy aparecendo antes de Container app Starting na saída do up, na ordem exata em que apareceu no meu teste.

Onde ficam as senhas e o que nunca vai para o repositório?

Senha e dado sensível nunca entram direto no compose.yaml que vai para o controle de versão. O caminho certo é um arquivo .env na mesma pasta, com uma variável por linha, e o YAML referenciando essas variáveis com ${POSTGRES_PASSWORD} ou carregando o arquivo inteiro com env_file. O .env entra no .gitignore antes do primeiro commit, sem exceção. O que vai para o repositório é um .env.example com os nomes das variáveis e valores de mentira, para quem clonar saber o que precisa preencher.

Dois detalhes que pegam. O primeiro é que o Compose lê o .env automaticamente para substituir variáveis no YAML, mas env_file é outra coisa: ele injeta as variáveis dentro do container. Dá para usar os dois, e é comum precisar dos dois. O segundo é que docker compose config imprime o arquivo com as senhas já substituídas. Não cole a saída dele num chat, num ticket ou num post sem revisar, porque é um jeito bem comum de credencial vazar sem ninguém perceber.

Para produção com mais de uma pessoa mexendo, o .env solto no servidor começa a ficar frágil, porque não tem histórico, não tem rotação e qualquer um com acesso ao shell lê. O Compose suporta secrets montados como arquivo dentro do container. A partir daí o assunto vira gestão de segredo propriamente dita, cofre, rotação e auditoria, que eu detalhei em gestão de segredos em produção. Para começar, .env fora do git resolve, e é o que a maioria dos projetos precisa.

Quais portas expor e como não abrir o banco para a internet?

A chave ports publica uma porta do container na máquina hospedeira. Um “5432:5432” no serviço do banco significa que qualquer um que alcance o IP do seu servidor alcança o seu Postgres. Num notebook atrás do roteador de casa isso é inofensivo, numa VPS com IP público é um convite, e scanner automatizado encontra porta 5432 aberta em minutos. A regra que eu sigo é simples: só a aplicação publica porta. O banco e o cache ficam sem ports, acessíveis apenas pela rede interna do Compose, onde app já enxerga db pelo nome.

Se você precisa acessar o banco da sua máquina para uma consulta, tem dois caminhos que não abrem a porta para o mundo. O primeiro é publicar só na interface local, “127.0.0.1:5432:5432”, que expõe para quem está dentro do servidor e para mais ninguém, e aí você entra por túnel SSH. O segundo é nem publicar e usar docker compose exec db psql, que abre o cliente dentro do container. Um cuidado extra no Linux: o Docker escreve as próprias regras de firewall. Uma porta publicada pode passar por cima de uma regra do ufw que você achava que estava protegendo.

Para a porta da aplicação, o padrão que eu uso é não publicar 80 e 443 direto no container dela. Entra um reverse proxy na frente, que cuida de domínio, certificado e roteamento para vários serviços na mesma máquina. O Traefik com Docker Compose faz isso lendo labels dos próprios containers. No homelab, onde eu não quero porta nenhuma aberta no roteador, a entrada externa vem por Cloudflare Tunnel, que sobe como mais um serviço no mesmo compose.yaml.

Como atualizar as imagens sem quebrar o ambiente?

Toda imagem no arquivo leva uma tag, e a tag é o que decide se uma atualização vai ser tranquila ou uma surpresa. postgres:18 fixa a versão maior e recebe correção da 18.x, que é o equilíbrio que eu prefiro. Já postgres:latest pode virar 19 num pull qualquer e recusar o diretório de dado da 18. Imagem sem tag nenhuma é a mesma coisa que latest. É o jeito mais comum de um ambiente que funcionava na segunda quebrar na quarta sem ninguém ter mexido em nada.

O fluxo de atualização que eu uso é docker compose pull, que só baixa, seguido de docker compose up -d, que recria apenas os containers cuja imagem mudou e deixa os outros em paz. Antes disso, em banco, backup. Um docker compose exec -T db pg_dump -U app app > backup.sql leva segundos e é a diferença entre uma atualização que deu errado e um dia perdido. Troca de versão maior do Postgres não é atualização, é migração. Exige dump e restore ou pg_upgrade, e a página da imagem oficial documenta o caminho.

Imagem antiga fica acumulando no disco depois de cada atualização, e docker image prune remove as que não estão mais em uso. Vale também conhecer o limite de download do Docker Hub, que pega quem faz pull sem login. São 100 pulls a cada 6 horas por endereço IP sem autenticação, e 200 a cada 6 horas para conta Personal autenticada. Numa VPS que sobe dez serviços de uma vez isso raramente estoura, num pipeline que roda toda hora estoura. O erro que volta é um 429 que parece problema de rede.

Quais são os erros mais comuns e como corrigir cada um?

Os mesmos tropeços se repetem, os meus e os de quem me manda log para olhar, e a lista abaixo cobre o que aparece em quase todo pedido de ajuda. A coluna do meio é a causa que ninguém enxerga na hora. A mensagem de erro do Docker costuma apontar para o sintoma e não para a origem, e é aí que a gente perde a tarde procurando no lugar errado.

Sintoma (conferido em 15/09/2026, fonte: documentação oficial do Docker e da imagem postgres no Docker Hub)CausaCorreção
Aplicação reinicia em loop nos primeiros segundos e depois estabiliza, ou nunca estabilizaSubiu antes do banco aceitar conexão; depends_on simples só espera o container iniciarhealthcheck no db e depends_on com condition: service_healthy
“port is already allocated” no upOutra coisa já usa a porta publicada, muitas vezes um container antigo do mesmo projeto ou um Postgres instalado direto no sistemadocker ps para achar quem ocupa, ou trocar o lado esquerdo do ports, tipo “5433:5432”
Dado do banco some depois de recriar o containerVolume não declarado, ou montado no caminho errado: na imagem postgres 18 é /var/lib/postgresql, até a 17 era /var/lib/postgresql/dataDeclarar o volume nomeado e conferir com docker volume ls que ele persiste depois do down
“variable is not set” e senha vazia no containerO .env não está na pasta do compose.yaml, ou o nome da variável no YAML difere do nome no .envdocker compose config e conferir a saída, variável por variável
Aviso “the attribute version is obsolete” na primeira linhaArquivo copiado de tutorial do Compose v1Apagar a linha version, ela não faz falta na v2 nem na v5
“docker-compose: command not found”A máquina só tem o plugin novo, e o comando é docker compose sem hífenTrocar o comando; se um script antigo exige o hífen, criar um alias para docker compose
Erro 429 “toomanyrequests” no pullLimite do Docker Hub: 100 pulls a cada 6 horas por IP sem logindocker login com conta gratuita, que sobe para 200 a cada 6 horas, ou espelhar a imagem em registry próprio
Banco fica em “unhealthy” sem pararhealthcheck com usuário ou banco errado, o pg_isready falha mesmo com o banco no arRodar o comando do healthcheck com docker compose exec db e ajustar usuário e banco
Erro de sintaxe no YAML apontando uma linha que parece certaMistura de tab e espaço, ou um item de lista fora do níveldocker compose config mostra a linha; usar só espaço, dois por nível

Um padrão nessa lista: quase todo erro se resolve olhando o log certo, docker compose logs com o nome do serviço, e não o log geral com tudo misturado. Quando você não sabe qual serviço olhar, docker compose ps mostra quem está reiniciando, quem está unhealthy e quem saiu com código diferente de zero. Isso já aponta o caminho antes de abrir qualquer log.

Quanto custa rodar Docker e Compose?

O Compose em si é gratuito e de código aberto sob licença Apache 2.0, e o Docker Engine no Linux também. O custo de rodar um ambiente com Compose numa VPS é o custo da VPS. O que tem preço é o Docker Desktop para empresa grande e os recursos de conta do Docker Hub. A tabela abaixo mostra os planos como estão na página de preços da Docker hoje, em dólar, com o valor mensal e o anual por usuário.

Plano (conferido em 15/09/2026, fonte: docker.com/pricing e docs.docker.com/docker-hub/usage)Preço por usuárioO que muda para quem usa Compose
Docker PersonalUS$ 0Desktop, Engine e Hub com 1 repositório privado; 200 pulls a cada 6 horas com login; vale para pessoa física, educação e empresa com até 250 funcionários e até US$ 10 milhões de faturamento anual
Docker ProUS$ 11 por mês, ou US$ 9 por mês no plano anualPulls sem limite no Hub e mais repositórios privados; é o plano de quem usa o Desktop profissionalmente sozinho
Docker TeamUS$ 16 por mês, ou US$ 15 por mês no plano anualO mesmo do Pro com gestão de equipe
Docker BusinessUS$ 24 por mêsObrigatório para empresa acima de 250 funcionários ou US$ 10 milhões de faturamento que use o Desktop, com controle centralizado
Docker Engine e Compose no LinuxUS$ 0, código abertoSem restrição de tamanho de empresa; é o que roda no servidor
Docker Hub sem loginUS$ 0100 pulls a cada 6 horas por endereço IPv4

Na prática, para quem está começando ou tem uma empresa pequena, a conta de licença fecha em zero e o dinheiro vai para a máquina. Uma VPS pequena roda a stack do exemplo com folga. O que faz o custo subir depois é banco crescendo e serviço acumulando, não o Docker. Eu detalhei como escolher e dimensionar em VPS na prática. A decisão de licença do Desktop só aparece quando a empresa cresce, e nesse ponto ela é pequena perto do resto da conta.

Quando o Compose deixa de bastar e o que vem depois?

Compose é excelente para desenvolvimento local e para rodar num único servidor, e resolve a maioria esmagadora dos projetos que eu vejo. Ele deixa de bastar quando você precisa de vários servidores trabalhando juntos, com um container voltando em outro servidor quando o primeiro cai. Escala automática por carga e atualização sem segundo de indisponibilidade também ficam de fora. Aí o assunto vira orquestração, e é outro nível de complexidade, de custo e de gente para operar.

Ferramenta (conferido em 15/09/2026, fonte: documentação oficial de Docker Compose, Docker Swarm e k3s)EscopoRequisito mínimo documentadoQuando faz sentido
Docker Compose v5.5.11 máquina, vários containersO mesmo do Docker Engine, nada alémDev local, VPS única, homelab, projeto pequeno e médio
Docker Swarm (já vem no Engine)Várias máquinas, serviços replicadosNúmero ímpar de managers: 3 toleram a perda de 1, 5 toleram a perda de 2Mais de um servidor com o mesmo arquivo adaptado, sem entrar no Kubernetes
k3s (Kubernetes leve)Cluster, autoescala, ecossistema KubernetesServer com 2 cores e 2 GB de RAM, agente com 1 core e 512 MBQuando o time já fala Kubernetes ou precisa do ecossistema, como Helm e operators

Na minha visão o erro mais comum aqui é o contrário do esperado: gente partindo para a ferramenta complexa antes de ter o problema que justifica. Paga em tempo de operação por uma escala que nunca chega. Se Compose resolve, fica no Compose. Quando a dúvida aparecer com número de usuário e de servidor na mão, eu escrevi um comparativo em Docker Compose ou Kubernetes: quando trocar. O Swarm é o meio termo esquecido: já vem no Engine, aceita quase o mesmo arquivo e leva o mesmo ambiente para dois ou três servidores sem trocar de mundo.

Antes de qualquer orquestrador, o que costuma faltar é enxergar o que já roda. Um ambiente com métrica e alerta numa máquina só entrega mais tranquilidade do que um cluster sem monitoramento. Dá para montar isso no mesmo Compose com Prometheus e Grafana, sem custo de licença. Deploy automatizado é o outro passo natural, e GitHub Actions faz o pull e o up na VPS a cada push com pouca configuração.

Como eu uso o Compose no meu homelab e na operação?

Meu homelab vive de Compose, com o mesmo padrão descrito aqui: arquivo por serviço, segredo em .env fora do git, banco sem porta publicada e restart: unless-stopped em tudo que precisa voltar sozinho depois de um reboot. A camada de baixo é o Proxmox, que eu descrevi em como montar homelab com Proxmox do zero, com uma VM Linux rodando o Docker. A entrada de fora vem pelo Cloudflare Tunnel como mais um container do mesmo arquivo, então nenhuma porta do roteador fica aberta.

Os dois erros que eu mais cometi são os que mais espaço ganharam neste guia. Ambiente quebrado por não entender ordem de subida, antes de aprender o healthcheck, e senha vazada por colocar no lugar errado, antes de separar o .env. Se você levar só duas coisas daqui, leve essas. São as que custam mais caro para descobrir por conta própria e as que nenhum tutorial de dez minutos mostra.

Quando esse ambiente deixa de ser estudo e vira a operação de uma empresa, com agente de IA atendendo cliente, fila processando pedido e banco com dado de cliente, o Compose continua sendo a base. O que muda é o que roda em cima dele e quem responde quando cai. É o tipo de projeto que a SyntaxLab constrói em agentes de IA e automação, com fila persistente, log estruturado e a infra sem porta pública, do jeito que este guia recomenda. Para sistema sob medida além de agente, o caminho é a página de software sob medida.

Quais são as dúvidas mais comuns sobre Docker Compose?

Preciso saber programar para usar Docker Compose?

Não para começar. Você precisa entender o conceito de peças que conversam entre si e saber descrever isso para uma IA, ou copiar um arquivo como o de cima e adaptar os nomes. A configuração a IA gera, você valida com docker compose config e com o checklist de subida. O entendimento de por que cada bloco existe vem com o primeiro erro que você corrige sozinho lendo o log.

Docker Compose serve para produção?

Serve bem para um único servidor e para projeto de pequeno e médio porte, que é a maioria. A condição é o banco ter volume, os segredos ficarem fora do YAML, só a aplicação publicar porta e cada serviço ter restart configurado. Para vários servidores com escala automática e tolerância à queda de uma máquina, aí o caso pede Swarm ou Kubernetes. A troca deve ser motivada por um problema real, não por antecipação.

Qual é a diferença entre docker-compose e docker compose?

docker-compose com hífen é a geração 1, escrita em Python, que a Docker já não lista como versão suportada. docker compose sem hífen é o plugin atual, escrito em Go, nas versões 2 e 5, que já vem no Docker Desktop e no pacote docker-compose-plugin do Linux. O arquivo é quase o mesmo, mas o comando antigo não conhece recurso novo como o depends_on com condição de saúde.

Compose e Dockerfile são a mesma coisa?

Não, e os dois se complementam. O Dockerfile descreve como construir a imagem de um serviço, qual base, quais dependências, qual comando roda. O compose.yaml descreve como vários serviços rodam juntos, com rede, volume, porta e ordem de subida. No exemplo deste guia, app tem um Dockerfile e build: . aponta para ele, enquanto db e cache usam imagens prontas do Docker Hub e não precisam de Dockerfile nenhum.

Por que meu container sobe mas a aplicação não conecta?

Quase sempre porque a aplicação subiu antes do banco estar pronto para aceitar conexão, e container rodando não é serviço pronto. A solução é um healthcheck no banco e depends_on com condition: service_healthy na aplicação, como no arquivo de exemplo. Se mesmo assim não conecta, confira se a aplicação usa o nome do serviço como host, db e não localhost. Dentro do container, localhost é o próprio container.

Onde coloco as senhas com segurança?

Num arquivo .env separado, fora do controle de versão, com o .gitignore configurado antes do primeiro commit, e um .env.example no repositório com valores fictícios. Nunca direto no compose.yaml, e nunca na saída de docker compose config colada em algum lugar público, porque ele imprime as variáveis já substituídas.

Por onde começar hoje?

Docker Compose do zero é menos sobre decorar configuração e mais sobre entender o que cada peça faz, descrever o ambiente com clareza e validar que ele subiu de verdade. Em menos de 30 minutos você tem seu primeiro ambiente de pé. O ganho de consistência você sente em todo deploy depois disso, quando a máquina nova sobe igual à antiga sem ninguém configurar nada na mão.

Se você quer subir seu primeiro ambiente ainda hoje, o próximo passo é:

  • Instalar o Docker conforme a tabela de requisitos e confirmar com docker compose version.
  • Copiar o compose.yaml deste guia, criar o .env com os nomes das variáveis e pôr o .env no .gitignore.
  • Rodar docker compose config, depois up -d, e validar peça por peça com o checklist, incluindo o restart que prova a persistência.

Para colocar esse ambiente num servidor de verdade, leia VPS na prática, e para automatizar o deploy dele, GitHub Actions do zero. A referência oficial está na documentação do Docker Compose, e é nela que você confere qualquer versão ou requisito quando este post envelhecer.

WA in X
Cláudio Campos

Escrito por

Cláudio Campos

Cláudio Campos é engenheiro de software com foco em automação e IA aplicada, baseado em Florianópolis (SC). Escreve na SyntaxLab sobre agentes de IA, Docker, automação com n8n e engenharia de software que precisa funcionar em produção — não só em demo. Aprendeu na prática, com pipelines que quebraram no deploy e agentes que alucinaram ao vivo; por isso não romantiza a tecnologia e descreve as limitações reais antes de chegar nelas.