JAVA Learning

Hub de Conteúdo

🐳 Docker Compose - Orquestração de Containers

Conceitos, Configuração, MySQL, PostgreSQL e Desenvolvimento Local

1. O que é Docker Compose?

Docker Compose é uma ferramenta que permite definir e executar aplicações multi-container com Docker. Com um único arquivo YAML, você pode descrever todos os serviços, redes e volumes necessários para sua aplicação.

Em vez de executar múltiplos comandos `docker run`, você define tudo em um arquivo `docker-compose.yml` e inicia com um simples comando: `docker-compose up`.

Docker Compose é ideal para desenvolvimento local, testes, e ambientes de staging. Permite que você defina uma stack completa (banco de dados, cache, web server, etc) com facilidade e reprodutibilidade.

Os principais benefícios do Docker Compose são:

  • Simplicidade: Uma único arquivo para toda a stack
  • Reprodutibilidade: Mesmo ambiente em qualquer máquina
  • Isolamento: Containers isolados em redes próprias
  • Facilidade: Sem necessidade de lembrar comandos complexos
  • Velocidade: Inicie múltiplos serviços com um comando

O fluxo de trabalho é simples: você escreve um `docker-compose.yml` descrevendo os serviços, depois executa `docker-compose up` para iniciá-los. Todos os containers são criados, conectados em rede e iniciados automaticamente.

Docker Compose é especialmente útil para criar ambientes de desenvolvimento que espelham o ambiente de produção, permitindo que problemas sejam detectados mais cedo.

Em resumo, Docker Compose simplifica o gerenciamento de múltiplos containers, tornando o desenvolvimento mais rápido, previsível e collaborativo! 🚀

2. Conceitos Fundamentais

Serviço (Service)

  • Definição: Um container ou grupo de containers relacionados
  • Exemplos: MySQL, Redis, Node.js, Nginx
  • Configuração: Definido no docker-compose.yml
  • Comunicação: Serviços se comunicam por nome de serviço

Volume (Volume)

  • Definição: Armazenamento persistente para dados
  • Tipos: Volumes nomeados ou mounts de host
  • Uso: Dados de banco de dados, arquivos de aplicação
  • Persistência: Dados survivem ao restart do container

Rede (Network)

  • Definição: Conexão entre containers
  • Padrão: Rede bridge automática por projeto
  • DNS: Serviços se resolvem por nome
  • Isolamento: Cada projeto tem sua própria rede

Arquivo docker-compose.yml

  • Formato: YAML (indentação importa!)
  • Versão: Especifica compatibilidade (v3.x é padrão)
  • Localização: Raiz do projeto
  • Nomes: docker-compose.yml ou docker-compose.yaml

3. Instalação do Docker e Docker Compose

Windows e Mac (Desktop):

bash
# Docker Desktop já inclui Docker Compose
# Download em: https://www.docker.com/products/docker-desktop

# Verificar instalação
docker --version
docker-compose --version

# Deve retornar algo como:
# Docker version 24.0.0, build abcdef
# Docker Compose version 2.20.0

Linux (Ubuntu/Debian):

bash
# Instalar Docker
sudo apt update
sudo apt install docker.io

# Instalar Docker Compose
sudo apt install docker-compose

# Adicionar usuário ao grupo docker (para não usar sudo)
sudo usermod -aG docker $USER
newgrp docker

# Testar instalação
docker --version
docker-compose --version

4. Estrutura do docker-compose.yml

Arquivo Básico:

yaml
version: '3.8'  # Versão do Compose

services:
  # Nome do serviço (como você irá referenciar)
  mysql:
    image: mysql:8.0                 # Imagem Docker a usar
    container_name: meu-mysql        # Nome do container
    environment:                      # Variáveis de ambiente
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: meu_banco
      MYSQL_USER: usuario
      MYSQL_PASSWORD: senha123
    ports:
      - "3306:3306"                 # Porta host:container
    volumes:
      - mysql_data:/var/lib/mysql   # Volume para persistência
    networks:
      - minha_rede                   # Rede customizada

volumes:
  # Define volumes que serão criados
  mysql_data:
    driver: local

networks:
  # Define redes customizadas
  minha_rede:
    driver: bridge

5. Exemplo Prático: MySQL com Docker Compose

Vamos criar um ambiente MySQL completo para desenvolvimento.

docker-compose.yml - MySQL Simples:

yaml
version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: mysql-dev
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: dev_db
      MYSQL_USER: dev_user
      MYSQL_PASSWORD: dev_pass123
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - dev_network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 10

volumes:
  mysql_data:
    driver: local

networks:
  dev_network:
    driver: bridge

Iniciar e Gerenciar:

bash
# Iniciar os containers em background
docker-compose up -d

# Ver status dos containers
docker-compose ps

# Ver logs
docker-compose logs -f mysql

# Acessar o MySQL
docker-compose exec mysql mysql -u root -p dev_db

# Parar os containers
docker-compose stop

# Parar e remover containers
docker-compose down

# Remover também os volumes (CUIDADO - apaga dados!)
docker-compose down -v

Arquivo init.sql (Inicializar banco):

sql
-- Arquivo: init.sql
-- Será executado automaticamente ao criar o container

CREATE TABLE IF NOT EXISTS usuarios (
    id INT PRIMARY KEY AUTO_INCREMENT,
    nome VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL UNIQUE,
    criado_em TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO usuarios (nome, email) VALUES
('Ana Silva', 'ana@example.com'),
('Bruno Costa', 'bruno@example.com'),
('Carlos Souza', 'carlos@example.com');

6. PostgreSQL com Docker Compose

Alternativa ao MySQL com mais recursos avançados.

docker-compose.yml - PostgreSQL:

yaml
version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    container_name: postgres-dev
    environment:
      POSTGRES_USER: dev_user
      POSTGRES_PASSWORD: dev_pass123
      POSTGRES_DB: dev_db
      POSTGRES_INITDB_ARGS: "--encoding=UTF8"
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - dev_network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U dev_user"]
      interval: 10s
      timeout: 5s
      retries: 5

  # PgAdmin - Interface web para gerenciar PostgreSQL
  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: pgadmin-dev
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@example.com
      PGADMIN_DEFAULT_PASSWORD: admin123
    ports:
      - "5050:80"
    networks:
      - dev_network
    depends_on:
      - postgres

volumes:
  postgres_data:
    driver: local

networks:
  dev_network:
    driver: bridge

Acessar PgAdmin:

bash
# Iniciar
docker-compose up -d

# Acessar PgAdmin em: http://localhost:5050
# Email: admin@example.com
# Senha: admin123

# Conectar ao PostgreSQL:
# Host: postgres (nome do serviço)
# Port: 5432
# Database: dev_db
# User: dev_user
# Password: dev_pass123

# Ou via CLI
docker-compose exec postgres psql -U dev_user -d dev_db

7. Stack Completa: Aplicação + Banco + Redis

Um exemplo real com múltiplos serviços para uma aplicação Java/Spring Boot.

docker-compose.yml - Stack Completa:

yaml
version: '3.8'

services:
  # Banco de Dados MySQL
  mysql:
    image: mysql:8.0
    container_name: app-mysql
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: app_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: app_pass123
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - app_network
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      timeout: 20s
      retries: 10

  # Cache Redis
  redis:
    image: redis:7-alpine
    container_name: app-redis
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - app_network
    command: redis-server --appendonly yes
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Aplicação Java/Spring Boot
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: app-server
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/app_db?useSSL=false
      SPRING_DATASOURCE_USERNAME: app_user
      SPRING_DATASOURCE_PASSWORD: app_pass123
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
    ports:
      - "8080:8080"
    volumes:
      - ./src:/app/src
    networks:
      - app_network
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped

volumes:
  mysql_data:
    driver: local
  redis_data:
    driver: local

networks:
  app_network:
    driver: bridge

Dockerfile (para a aplicação Spring Boot):

dockerfile
FROM maven:3.9-eclipse-temurin-17 AS builder

WORKDIR /app

# Copiar arquivos do projeto
COPY pom.xml .
COPY src ./src

# Build da aplicação
RUN mvn clean package -DskipTests

# Estágio final
FROM eclipse-temurin:17-jre

WORKDIR /app

# Copiar JAR do build anterior
COPY --from=builder /app/target/app.jar app.jar

# Expor porta
EXPOSE 8080

# Iniciar aplicação
ENTRYPOINT ["java", "-jar", "app.jar"]

Iniciar a Stack Completa:

bash
# Iniciar todos os serviços
docker-compose up -d

# Ver status
docker-compose ps

# Ver logs de um serviço específico
docker-compose logs -f app

# Ver logs de todos
docker-compose logs -f

# Parar tudo
docker-compose down

# Parar e remover volumes
docker-compose down -v

8. Comandos Docker Compose Úteis

Gerenciamento de Containers:

bash
# UP - Criar e iniciar containers
docker-compose up -d              # Background
docker-compose up                 # Modo verbose

# DOWN - Parar e remover containers
docker-compose down               # Mantém volumes
docker-compose down -v            # Remove volumes também

# PS - Listar containers
docker-compose ps

# START/STOP - Iniciar/Parar containers
docker-compose start
docker-compose stop

# RESTART - Reiniciar containers
docker-compose restart

# LOGS - Ver logs
docker-compose logs -f            # Todos
docker-compose logs -f mysql      # Serviço específico
docker-compose logs --tail 50     # Últimas 50 linhas

# EXEC - Executar comando dentro do container
docker-compose exec mysql bash    # Abrir shell
docker-compose exec mysql ls -la  # Listar arquivos

# BUILD - Reconstruir imagens
docker-compose build
docker-compose build --no-cache   # Sem cache

# PULL - Atualizar imagens
docker-compose pull

# RM - Remover containers parados
docker-compose rm

# CONFIG - Validar e exibir configuração
docker-compose config

9. Boas Práticas

✓ Use .env para Variáveis de Ambiente

  • Crie arquivo `.env` na raiz do projeto
  • Docker Compose lê automaticamente
  • Não committe `.env` no git (adicione ao .gitignore)

✓ Use Healthchecks

  • Verifique se serviço está realmente pronto
  • Use `depends_on` com condition
  • Evita problemas de inicialização

✓ Volumes para Desenvolvimento

  • Mapeie seu código local em tempo real
  • Evite reconstruir imagens a cada mudança
  • Perfeito para desenvolvimento local

✓ Versionamento de Imagens

  • Sempre especifique versão da imagem
  • Evite usar `latest` em produção
  • Garanta reprodutibilidade

10. Usando Arquivo .env

.env - Variáveis de Ambiente:

bash
# .env
MYSQL_ROOT_PASSWORD=root123
MYSQL_DATABASE=app_db
MYSQL_USER=app_user
MYSQL_PASSWORD=app_pass123

REDIS_PORT=6379

SPRING_PORT=8080
SPRING_PROFILE=dev

docker-compose.yml com .env:

yaml
version: '3.8'

services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:7-alpine
    ports:
      - "${REDIS_PORT}:6379"
    volumes:
      - redis_data:/data

volumes:
  mysql_data:
  redis_data:

.gitignore - Proteger .env:

bash
# .gitignore
.env
.env.local
.env.*.local

node_modules/
target/
*.log

.DS_Store
.vscode/
.idea/

11. Troubleshooting Comum

Problemas e Soluções:

bash
# ❌ Problema: Porta já em uso
# Solução: Mude a porta no docker-compose.yml ou:
docker-compose down
sudo lsof -i :3306  # Ver qual processo usa porta
kill -9 PID

---

# ❌ Problema: Não consegue conectar ao banco
# Solução: Verifique healthcheck e dependências
docker-compose logs mysql
docker-compose exec mysql mysql -u root -p

---

# ❌ Problema: Container sai logo após iniciar
# Solução: Verifique logs
docker-compose logs app
# Procure por erros no console

---

# ❌ Problema: Volume não está funcionando
# Solução: Verifique sintaxe e permissões
docker-compose exec app ls -la /app
# Verifique sintaxe do volume no yml

---

# ❌ Problema: Rede não consegue se comunicar
# Solução: Use nome do serviço como hostname
# Correto: jdbc:mysql://mysql:3306/db
# Errado: jdbc:mysql://localhost:3306/db

---

# ❌ Problema: Mudanças no código não aparecem
# Solução: Verifique se volume está configurado
volumes:
  - ./src:/app/src  # Mapeie seu código local

---

# Limpar tudo e começar novamente
docker-compose down -v
docker system prune -a
docker-compose up -d --build

12. Exercícios Práticos

Exercício 1: MySQL + PhpMyAdmin

Crie um docker-compose com MySQL e PhpMyAdmin. Inicialize com dados de exemplo. Acesse via PhpMyAdmin e realize consultas.

Exercício 2: PostgreSQL + PgAdmin

Configure PostgreSQL com PgAdmin. Crie tabelas e dados via SQL. Pratique operações CRUD através do PgAdmin.

Exercício 3: Stack Multi-container

Crie uma aplicação Spring Boot que se conecta com MySQL e Redis. Configure docker-compose com todos os serviços, healthchecks e dependências.

Exercício 4: Usando .env

Refatore um docker-compose existente para usar arquivo .env. Crie variáveis para senhas, portas e nomes de bancos.

Exercício 5: Volumes e Persistência

Configure volumes nomeados para banco de dados. Teste que dados persistem após `docker-compose down`.

Conclusão

Docker Compose é essencial para desenvolvimento moderno, permitindo que todos na equipe tenham o mesmo ambiente.

Pontos-chave para lembrar:

  • Um arquivo: docker-compose.yml define toda a stack
  • Fácil setup: `docker-compose up -d` para começar
  • Isolamento: Containers isolados em rede própria
  • Reprodutibilidade: Mesmo ambiente em qualquer máquina
  • Variáveis: Use .env para configurações sensíveis
  • Healthchecks: Verifique se serviços estão prontos

Docker Compose é a ponte entre desenvolvimento local e produção. Domine-o para ser um desenvolvedor mais eficiente! 🚀