Docker Compose na Prática: Criando Ambientes com Múltiplos Containers

setembro 1, 2026 · 8 min de leitura · Luiz Seabra

Docker Compose na Prática: Criando Ambientes com Múltiplos Containers

Introdução

Gerenciar um único container é simples, mas aplicações reais geralmente dependem de múltiplos serviços (banco de dados, cache, fila, front‑end). O Docker Compose resolve esse problema ao permitir declarar, configurar e orquestrar grupos de containers através de um único arquivo YAML. Este artigo destina‑se a desenvolvedores, administradores de sistemas e entusiastas de homelab que já conhecem Docker e desejam evoluir para ambientes compostos.

O que você vai aprender

  • Por que Docker Compose é necessário para projetos multi‑container.
  • Estrutura completa de compose.yaml (services, networks, volumes).
  • Uso de healthchecks e restart policies.
  • Configuração de variáveis de ambiente via .env e env_file.
  • Estratégias de dependência com depends_on e condições de saúde.
  • Criação de um stack WordPress + MySQL + Adminer.
  • Manipulação de volumes nomeados e redes customizadas.
  • Laboratório completo e reproduzível.
  • Troubleshooting de portas, healthchecks e variáveis.

Pré‑requisitos

  • Ubuntu 22.04 LTS com Docker Engine instalado (veja o artigo Docker no Linux).
  • Usuário com permissão para executar docker (grupo docker).
  • Conexão à internet para baixar imagens oficiais.
  • Editor de texto (vim, nano ou VS Code).

Conceitos fundamentais

Conceito Definição
Compose file Arquivo YAML que descreve serviços, redes e volumes.
Service Um container gerenciado pelo Compose.
Network Rede Docker onde os serviços podem comunicar‑se por nome.
Volume Persistência de dados fora do ciclo de vida do container.
Healthcheck Teste que determina se o container está saudável; usado por depends_on.
depends_on Declara dependência entre serviços; opcionalmente aguarda health.
.env Arquivo de variáveis de ambiente interpoladas no compose file.
env_file Arquivo externo carregado como variáveis de ambiente.

Preparação do ambiente

  1. Criar diretório do projeto
mkdir -p $HOME/docker-compose-lab && cd $HOME/docker-compose-lab

Resultado esperado: Diretório vazio pronto para receber arquivos.
2. Criar .env com credenciais do MySQL

cat > .env <<'EOF'
MYSQL_ROOT_PASSWORD=StrongRootPass123!
MYSQL_DATABASE=wpdb
MYSQL_USER=wpuser
MYSQL_PASSWORD=WpPass123!
EOF

Resultado esperado: Arquivo .env criado com as variáveis.
3. Criar docker-compose.yaml (ver seção abaixo).

Estrutura completa do compose.yaml

version: "3.9"

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - backend

  wordpress:
    image: wordpress:6.5-php8.2-apache
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: ${MYSQL_USER}
      WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
      WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
    ports:
      - "8080:80"
    volumes:
      - wp_data:/var/www/html
    networks:
      - backend
      - frontend

  adminer:
    image: adminer:latest
    restart: unless-stopped
    ports:
      - "8081:8080"
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true

volumes:
  db_data:
  wp_data:

Explicação linha a linha
– version – Versão do schema Compose (3.9 oferece recursos avançados).
– services.db – Container MySQL com variáveis interpoladas do .env.
– healthcheck – Garante que o MySQL esteja pronto antes do WordPress iniciar.
– depends_on com condition: service_healthy – WordPress aguarda MySQL saudável.
– networks.backend marcado como internal impede acesso externo direto ao banco.
– networks.frontend permite que o WordPress exponha a porta 8080 ao host.
– volumes nomeados (db_data, wp_data) preservam dados entre recriações.

Tutorial passo a passo

Etapa 1 – Levantar o stack

docker compose up -d

Resultado esperado: Containers docker-compose-lab_db_1, docker-compose-lab_wordpress_1, docker-compose-lab_adminer_1 em estado Up.

Etapa 2 – Verificar saúde dos serviços

docker compose ps

Resultado esperado: Coluna State mostra healthy para db e running para WordPress.

Etapa 3 – Acessar WordPress

Abra o navegador em http://localhost:8080 e conclua a instalação padrão.

Etapa 4 – Gerenciar o banco via Adminer

Acesse http://localhost:8081, use as credenciais definidas no .env.

Etapa 5 – Parar e remover o ambiente sem perder dados

docker compose down -v   # remove containers e redes, mantém volumes

Resultado esperado: Containers e redes são removidos, mas volumes db_data e wp_data permanecem.

Etapa 6 – Recriar o ambiente reutilizando os volumes

docker compose up -d

WordPress carrega a base de dados previamente criada, permitindo continuação.

Laboratório completo

Reproduza o laboratório inteiro seguindo os passos acima. Verifique:
– A aplicação WordPress persiste após down -v (dados permanecem).
– O healthcheck realmente impede que o WordPress tente conectar ao MySQL antes que ele esteja pronto (observe logs de docker compose logs wordpress).
– As redes frontend e backend isolam o tráfego como esperado (tente docker exec -it <container> ping db).

Troubleshooting: problemas comuns e como resolver

1. Sintoma – Port already allocated: 8080.

  • Possível causa: Outro serviço (Apache, Nginx) já usa a porta.
  • Diagnóstico: sudo lsof -i :8080.
  • Solução: Alterar o mapeamento de porta no compose.yaml (ex.: "8082:80").
  • Prevenção: Verificar uso de portas antes de iniciar o stack.

2. Sintoma – db nunca fica healthy.

  • Possível causa: Credenciais incorretas ou conexão lenta ao disco.
  • Diagnóstico: docker compose logs db para ver falhas do mysqladmin ping.
  • Solução: Ajustar interval/retries ou garantir que a variável MYSQL_ROOT_PASSWORD esteja correta.
  • Prevenção: Testar a imagem MySQL isoladamente antes de integrar.

3. Sintoma – Variáveis de ambiente não são lidas (environment vazio).

  • Possível causa: Arquivo .env não está no mesmo diretório do compose.yaml.
  • Diagnóstico: docker compose config exibe valores interpolados.
  • Solução: Mover .env para o diretório raiz ou especificar env_file explicitamente.
  • Prevenção: Sempre rodar docker compose config após mudanças.

4. Sintoma – docker compose up falha com ERROR: No such file or directory: docker-compose.yaml.

  • Possível causa: Nome do arquivo errado (deve ser docker-compose.yml ou compose.yaml).
  • Diagnóstico: ls para confirmar o nome.
  • Solução: Renomear para docker-compose.yml ou usar a flag -f.
  • Prevenção: Padronizar o nome do arquivo no início do projeto.

Segurança

  • Política de reinício – restart: unless-stopped evita que containers entrem em ciclo de crash.
  • Segurança de rede – Redes internas (internal: true) impedem acesso externo ao banco.
  • Variáveis sensíveis – Não versionar .env; armazenar em secret manager ou usar docker secret.
  • Imagem fixa – Defina versões específicas (mysql:8.0.36, wordpress:6.5-php8.2-apache).
  • Least privilege – Use usuário não‑root dentro do container (user: www-data).

Boas práticas

Prática Justificativa
Versionar o compose file Garante reprodutibilidade em CI/CD.
Separar redes – frontend / backend Isola serviços críticos de acesso público.
Healthcheck consistente Permite orquestração confiável; evita “race condition”.
Volumes nomeados Dados persistem independentemente de recriações.
docker compose config antes de up Detecta erros de sintaxe e interpolação.
Limitar recursos – mem_limit, cpus Evita consumo excessivo em ambientes compartilhados.

Comparação Docker Compose vs Docker Swarm (quando houver confusão)

Aspecto Docker Compose Docker Swarm
Escopo Máquina única (ou host com Docker). Cluster multi‑host.
Orquestração Declarativa, via docker compose up. Declarativa + serviço distribuído (docker swarm init).
Load balancing Não nativo (necessita de proxy externo). Integrado (routing mesh).
Escalabilidade docker compose up --scale (limitado ao host). docker service scale (across nodes).
Persistência Volumes locais; bind ou named. Volumes distribuídos via plugins (e.g., NFS).
Uso típico Desenvolvimento, teste, pequenos prod. Produção em larga escala.

Conclusão

Docker Compose simplifica a orquestração de múltiplos containers, permitindo que desenvolvedores descrevam infraestrutura como código em um único arquivo YAML. Ao dominar healthchecks, dependências e redes, você cria ambientes robustos, reproduzíveis e seguros, prontos para avançar rumo a orquestradores de cluster como Kubernetes ou Docker Swarm.

Perguntas frequentes

P1: Posso usar docker compose sem o Docker Engine instalado?
R: Não. O Compose depende do daemon Docker; instale o Docker Engine primeiro (veja o artigo Docker no Linux).

P2: Qual a diferença entre depends_on simples e com condition: service_healthy?
R: O primeiro inicia os containers na ordem declarada, sem aguardar saúde. O segundo espera o healthcheck do serviço dependente reportar healthy antes de iniciar o dependente.

Próximo passo

Agora que você domina Docker Compose Na Pratica, o próximo passo lógico da nossa trilha de aprendizado é continuar desenvolvendo suas habilidades.

→ Continue: Nginx e Reverse Proxy no Linux

Artigos relacionados

Estes artigos complementam o conteúdo apresentado:

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Rolar para cima