DEV Community

Celso Nery
Celso Nery

Posted on Edited on

Docker - Parte 6: Automatizando com Docker Compose

🇺🇸 English version here

Docker para Desenvolvedores - Parte 6: Orquestrando 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)