DEV Community

Celso Nery
Celso Nery

Posted on

Parte 6: Automatizando com Docker Compose

🇺🇸 English version here

Docker para Desenvolvedores — Parte 6: Automatizando com Docker Compose

Ao longo desta série, vimos containers, volumes, redes e gerenciamento de imagens — sempre usando comandos individuais do docker run, docker network create, docker volume create, etc. Isso funciona, mas se torna trabalhoso (e propenso a erros) conforme uma aplicação passa a depender de múltiplos serviços. É aí que o Docker Compose entra: ele permite descrever toda essa configuração em um único arquivo declarativo, tornando o processo mais limpo, mais fácil de repetir e de versionar em um repositório Git.

Criando seu docker-compose.yaml

Um docker-compose.yaml mínimo

A estrutura mais simples possível, rodando um único serviço:

services:
  web:
    image: httpd
    ports:
      - "8080:80"
Enter fullscreen mode Exit fullscreen mode

Isso já é equivalente a rodar docker run -p 8080:80 httpd — mas de forma declarativa, reaplicável e fácil de versionar.

Acrescentando um volume

Para persistir dados desse serviço (como vimos na Parte 3 desta série), basta adicionar uma seção volumes:

services:
  web:
    image: httpd
    ports:
      - "8080:80"
    volumes:
      - web-data:/usr/local/apache2/htdocs

volumes:
  web-data:
Enter fullscreen mode Exit fullscreen mode

Repare que o volume precisa ser declarado em dois lugares: referenciado dentro do serviço (volumes: dentro de web) e definido na seção raiz volumes: no final do arquivo — é ali que o Compose realmente cria o volume nomeado.

Acrescentando uma rede

Da mesma forma, é possível declarar redes customizadas (vistas na Parte 4):

services:
  web:
    image: httpd
    ports:
      - "80:80"
    volumes:
      - web-data:/usr/local/apache2/htdocs
    networks:
      - app-network

volumes:
  web-data:

networks:
  app-network:
Enter fullscreen mode Exit fullscreen mode

Na prática, quando você não declara uma rede explicitamente, o Compose já cria uma rede padrão para o projeto automaticamente, permitindo que os serviços do mesmo docker-compose.yaml se enxerguem entre si pelo nome. Declarar redes manualmente vale a pena quando você precisa de mais de uma rede isolada, ou quer conectar serviços de arquivos Compose diferentes.

Subindo os containers

Para criar e iniciar todos os serviços definidos no arquivo:

$ docker compose up
Enter fullscreen mode Exit fullscreen mode

Assim como no docker run, o terminal fica preso mostrando os logs de todos os serviços. Para rodar em segundo plano:

$ docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Derrubando os containers

Para parar e remover os containers, redes e (por padrão) preservar os volumes criados pelo Compose:

$ docker compose down
Enter fullscreen mode Exit fullscreen mode

Por padrão, docker compose down não remove volumes — isso evita perda acidental de dados. Se você quiser remover os volumes também, use docker compose down -v (com cautela).

Juntando vários containers: App + Database + Redis

O verdadeiro poder do Compose aparece quando uma aplicação depende de múltiplos serviços trabalhando juntos. Um exemplo comum: um proxy Nginx na frente, uma aplicação, um banco de dados MySQL e um cache Redis.

services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app
    networks:
      - app-network

  app:
    image: myapp:1.0.0
    environment:
      DB_HOST: db
      DB_USER: appuser
      DB_PASSWORD: apppassword
      REDIS_HOST: redis
    depends_on:
      - db
      - redis
    networks:
      - app-network

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: appdb
      MYSQL_USER: appuser
      MYSQL_PASSWORD: apppassword
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - app-network

  redis:
    image: redis:alpine
    networks:
      - app-network

volumes:
  db-data:

networks:
  app-network:
Enter fullscreen mode Exit fullscreen mode

Alguns pontos importantes desse exemplo:

  • depends_on: define a ordem de inicialização dos containers (o app só sobe depois do db e do redis). Vale notar que isso garante apenas a ordem de início do container, não que o serviço interno (como o MySQL) já esteja pronto para aceitar conexões — para isso, a aplicação normalmente precisa implementar alguma lógica de retry na conexão com o banco;
  • Variáveis de ambiente (environment): usadas para configurar a aplicação e o MySQL sem precisar alterar imagens ou hardcodar valores;
  • db-data: volume nomeado garantindo que os dados do MySQL sobrevivam a reinicializações e recriações do container;
  • app-network: todos os serviços compartilham a mesma rede, permitindo que se comuniquem entre si pelo nome do serviço (db, redis) em vez de IPs fixos.

Subindo tudo de uma vez:

$ docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Com um único comando, o Compose cria a rede, os volumes, e sobe os quatro containers já conectados e prontos para se comunicar entre si.

Considerações finais da série

Ao longo desta série, cobrimos o ciclo completo do Docker no dia a dia: instalação, comandos essenciais da CLI, persistência de dados com volumes, comunicação entre containers via redes, gerenciamento e publicação de imagens, e, por fim, orquestração de múltiplos serviços com Docker Compose. Com essa base, você já tem tudo o que precisa para rodar aplicações containerizadas de forma profissional — seja em um ambiente de desenvolvimento local, seja em um servidor de produção.

Para quem quiser ir além de um único host, o próximo passo natural é o Kubernetes — que resolve os mesmos problemas de orquestração, mas em escala, distribuindo containers entre múltiplos servidores.

Você pode encontrar uma série de artigo que fiz sobre kubernetes

Top comments (0)