O que é Docker Compose e por que ele é essencial
No mundo da infraestrutura moderna e do desenvolvimento ágil, a capacidade de provisionar ambientes complexos com um único comando é um diferencial competitivo. O Docker Compose é a ferramenta oficial da Docker para definir e executar aplicações multi-contêiner. Enquanto o comando docker run é excelente para iniciar um único serviço isolado, ele se torna impraticável quando precisamos orquestrar uma arquitetura completa: frontend, backend, banco de dados, cache e proxy reverso.
O Docker Compose utiliza um arquivo em formato YAML (docker-compose.yml) para configurar os serviços da sua aplicação. Esse arquivo define as redes, volumes, variáveis de ambiente e dependências entre os containers. Ao executar o comando docker compose up, o motor do Docker lê essa configuração e cria todos os recursos necessários simultaneamente, garantindo que a orquestração ocorra na ordem correta.
Neste tutorial, vamos construir uma stack completa em um ambiente VPS Linux. Utilizaremos o Traefik como reverse proxy para gerenciar o roteamento de tráfego e obter certificados SSL automáticos via Let's Encrypt. Além disso, configuraremos volumes persistentes para garantir que seus dados não sejam perdidos quando os containers forem reiniciados ou atualizados.
Pré-requisitos e Preparação do Ambiente
Antes de mergulhar na configuração do Compose, certifique-se de que seu servidor VPS atenda aos seguintes requisitos:
- Um sistema operacional Linux moderno (Ubuntu 22.04 LTS ou Debian 12 recomendados).
- Docker Engine instalado e atualizado.
- Docker Compose Plugin instalado (ou a versão standalone, dependendo da sua instalação).
- Dois domínios apontando para o IP público do seu servidor (ex:
app.seudominio.comedb.seudominio.com). Você pode usar subdomínios temporários para testes.
Para verificar se o Docker está funcionando corretamente, execute:
docker --version
docker compose version
Crie um diretório dedicado para este projeto. Isso manterá seu sistema organizado e facilitará o backup da configuração.
mkdir ~/docker-traefik-stack && cd ~/docker-traefik-stack
Estrutura de Arquivos do Projeto
A organização dos arquivos é crucial para a manutenibilidade. Vamos criar uma estrutura simples mas robusta:
docker-compose.yml: O arquivo principal de orquestração.traefik/: Diretório para configurações específicas do Traefik.app/: Diretório para a aplicação web (usaremos um container nginx simples como exemplo).
mkdir -p traefik app
Dentro da pasta app, crie um arquivo HTML simples para testar:
echo "<h1>Olá, Mundo Docker!</h1>" > app/index.html
Configurando o Traefik como Reverse Proxy
O Traefik é um reverse proxy moderno e dinâmico que se integra nativamente ao Docker. Ele lê as labels dos containers em tempo real para criar rotas automaticamente. Isso elimina a necessidade de reiniciar o servidor web sempre que adicionamos um novo serviço.
Criando o arquivo de configuração do Traefik
Crie o arquivo traefik/traefik.yml. Este arquivo define os endpoints de entrada, a integração com o Docker e as configurações de SSL.
global:
checkNewVersion: true
sendAnonymousUsage: false
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: web
file:
filename: /etc/traefik/dynamic.yml
watch: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
letsencrypt:
acme:
email: "[email protected]"
storage: /etc/traefik/acme.json
httpChallenge:
entryPoint: web
Nota importante: Substitua [email protected] por um endereço de e-mail válido. Esse e-mail será usado para notificações de expiração de certificados e recuperação de chave.
Criando o arquivo Docker Compose principal
Agora, vamos definir os serviços no docker-compose.yml. Este arquivo orquestrará o Traefik e nossa aplicação de exemplo.
version: '3.8'
services:
traefik:
image: traefik:v2.10
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard (recomendado restringir acesso)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./traefik/acme.json:/etc/traefik/acme.json
- ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
networks:
- web
app:
image: nginx:alpine
container_name: minha-app
restart: unless-stopped
volumes:
- ./app:/usr/share/nginx/html:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`app.seudominio.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=80"
networks:
- web
networks:
web:
external: true
Analisemos os pontos cruciais desta configuração:
- Volumes do Socket: A linha
/var/run/docker.sock:/var/run/docker.sock:ropermite que o Traefik ouça eventos do Docker. O sufixo:rogarante acesso apenas leitura, melhorando a segurança. - Redes Externas: Definimos a rede
webcomo externa. Isso é uma boa prática para permitir que outros containers (como bancos de dados) se conectem à mesma rede sem precisar ser declarados neste arquivo específico, facilitando a expansão da stack. - Labels do Traefik: Na seção
app, as labels dizem ao Traefik: "Ative o proxy para este container", "Roteie tráfego para o domínio especificado", "Use TLS com Let's Encrypt" e "Encaminhe para a porta 80 interna do Nginx".
Volumes Persistentes e Isolamento de Dados
Um erro comum em ambientes Docker é perder dados quando um container é removido. Para aplicações reais, como bancos de dados ou sistemas de arquivos, isso é inaceitável. O Docker Compose resolve isso através de volumes nomeados.
No exemplo acima, usamos volumes de montagem de arquivo (./app:/usr/share/nginx/html:ro). Isso é ideal para código fonte ou configurações estáticas. No entanto, para dados dinâmicos, devemos usar volumes gerenciados pelo Docker.
Imagine que adicionamos um serviço de banco de dados PostgreSQL à nossa stack. A configuração seria:
db:
image: postgres:15-alpine
container_name: postgres-db
restart: unless-stopped
environment:
POSTGRES_PASSWORD: senha_segura_aqui
POSTGRES_DB: myapp
volumes:
- db-data:/var/lib/postgresql/data
networks:
- web
volumes:
db-data:
A seção volumes no final do arquivo cria um volume persistente chamado db-data. Mesmo se o container postgres-db for destruído, os dados na pasta /var/lib/postgresql/data dentro do volume permanecerão intactos. Ao recriar o container com a mesma configuração, os dados serão restaurados automaticamente.
Dicas de Segurança para Volumes
- Sempre defina permissões de leitura/escrita adequadas.
- Nunca armazene senhas ou chaves de API diretamente no código-fonte do container; use variáveis de ambiente ou arquivos montados com restrições rígidas.
- Faça backups regulares dos diretórios onde os volumes são armazenados fisicamente no host (geralmente em
/var/lib/docker/volumes/).
Orquestração Avançada: Dependências e Healthchecks
A orquestração eficiente não depende apenas de iniciar containers na ordem correta, mas também de garantir que eles estejam prontos para receber tráfego. O Docker Compose suporta depends_on, mas ele espera apenas pelo início do container, não pela inicialização completa do serviço (ex: banco de dados aceitando conexões).
Para uma orquestração robusta, utilizamos Healthchecks. Vamos atualizar a configuração do banco de dados para incluir um verificador de saúde:
db:
image: postgres:15-alpine
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
Agora, atualizamos o serviço da aplicação para depender da saúde do banco de dados:
app:
depends_on:
db:
condition: service_healthy
Essa configuração garante que a aplicação app só será iniciada após o PostgreSQL estar realmente pronto para aceitar conexões, prevenindo erros de conexão nas primeiras tentativas do sistema.
Troubleshooting Containers Docker
Mesmo com configurações perfeitas, erros podem ocorrer. O Docker Compose oferece comandos poderosos para diagnóstico. Aqui estão os cenários mais comuns e como resolvê-los.
1. Logs Centralizados
Ao invés de acessar cada container individualmente, o Compose permite ver todos os logs em um único fluxo:
docker compose logs -f --tail=50
O flag -f mantém o terminal aberto para novos logs em tempo real. O --tail=50 mostra apenas as últimas 50 linhas, útil se os logs forem muito antigos.
2. Verificando o Status dos Serviços
Para ver rapidamente quais containers estão rodando, parados ou com falha:
docker compose ps
Se um serviço estiver em estado Exited, verifique os logs específicos dele:
docker compose logs app
3. Problemas com SSL e Traefik
Se o certificado Let's Encrypt não for obtido, verifique os seguintes pontos:
- O domínio está corretamente apontando para o IP do servidor (verifique com
nslookup seu-domínio.com)? - As portas 80 e 443 estão abertas no firewall do VPS? Use
ufw statusoufirewall-cmd --list-all. - O arquivo
acme.jsontem permissões de leitura para o usuário do container? Se necessário, ajuste comchmod 600 ./traefik/acme.json.
4. Containers "Zumbis"
Às vezes, containers param mas não são removidos. Para limpar todo o ambiente:
docker compose down -v
O flag -v remove também os volumes nomeados definidos no arquivo. Use com cautela, pois isso apaga dados persistentes.
Boas Práticas para Produção
Ao levar sua stack Docker Compose para produção em um VPS, considere as seguintes práticas:
- Imagens Estáveis: Evite usar tags
latestem produção. Especifique versões exatas, comonginx:1.25-alpine, para garantir reprodutibilidade. - Segurança de Rede: Não exponha portas internas (como a do banco de dados) diretamente ao mundo exterior. Deixe que apenas o Traefik ou serviços específicos exponham portas na porta 80/443.
- Monitoramento: Integre ferramentas como Prometheus e Grafana em sua stack para monitorar métricas de desempenho e disponibilidade.
- Backup Automático: Implemente scripts cron ou ferramentas como
resticoukopiapara backup automático dos volumes de dados.
Conclusão
O Docker Compose transforma a complexidade da orquestração de múltiplos serviços em uma tarefa gerenciável e repetível. Ao combinar o poder do Docker com a inteligência do Traefik, você cria uma infraestrutura resiliente, segura e escalável. A configuração de volumes persistentes garante a integridade dos seus dados, enquanto os healthchecks asseguram a estabilidade da aplicação.
A partir deste tutorial, você tem as bases para implantar aplicações profissionais em sua VPS. Lembre-se: a chave para o sucesso com containers é a documentação clara das dependências e o monitoramento contínuo. Experimente adicionar novos serviços à sua stack, como Redis para cache ou Elasticsearch para busca, utilizando os mesmos princípios de rede e volumes apresentados aqui.
A infraestrutura como código não é apenas uma tendência; é o padrão atual para desenvolvimento e operações de TI. Domine o Docker Compose e você estará preparado para qualquer desafio de orquestração moderna.