MODULO 4.2

🎼 Docker Compose: Multi-Servicos

Uma aplicacao de verdade quase nunca e um container so: tem o app, o banco de dados, talvez um cache. O Docker Compose e a ferramenta que rege todos esses containers de uma vez, com um unico arquivo e um unico comando.

6
Topicos
45
Minutos
Basico
Nivel
Pratico
Tipo
1

O Que e o Docker Compose

No modulo anterior voce subiu um container de cada vez, na mao, com docker run. Funciona para um container. Mas e quando seu site precisa de tres ao mesmo tempo: o app, o banco de dados e um cache? Digitar tres comandos gigantes toda vez, lembrar de cada porta, cada volume, cada conexao? Esquece. O Docker Compose resolve isso: voce descreve tudo num arquivo e sobe a stack inteira com um comando so.

docker-compose.yml services: app: banco: cache: up -d rede do compose (os containers se enxergam pelo nome) app node :3000 banco postgres :5432 cache redis :6379 💾 volume (dados) Um arquivo descreve a stack inteira. Um comando sobe tudo: docker compose up -d

🧠 Analogia: O Maestro da Orquestra

Imagine uma orquestra. Cada musico (container) sabe tocar seu instrumento sozinho: o app toca, o banco toca, o cache toca. Mas se cada um comecar na hora que quiser, o resultado e barulho. O maestro (o Compose) le a partitura (o arquivo docker-compose.yml) e rege todos juntos: quem comeca primeiro, quem fala com quem, em que tom.

  • A partitura = o arquivo docker-compose.yml
  • Os musicos = cada servico (app, banco, cache)
  • O "comecar a tocar" = docker compose up

💡 Docker Compose ja vem junto

Se voce instalou o Docker moderno (Docker Desktop ou o Docker Engine recente no Linux), o Compose ja esta instalado como um subcomando: voce chama docker compose (com espaco). Em maquinas antigas o comando era docker-compose (com hifen). Os dois fazem a mesma coisa; neste modulo usamos a forma nova com espaco.

# Conferir se o Compose esta disponivel

$ docker compose version

Docker Compose version v2.27.0

2

O Arquivo docker-compose.yml Basico

Toda a magia mora num unico arquivo de texto chamado docker-compose.yml. Ele e escrito em YAML, um formato simples baseado em indentacao (espacos no comeco da linha). A regra de ouro: a indentacao dita o que esta dentro do que. Vamos do mais simples ao completo.

O menor compose possivel: um servico

# docker-compose.yml

services:

app:

image: nginx:alpine

ports:

- "8080:80"

Isso descreve um servico chamado app, que usa a imagem nginx:alpine e expoe a porta 80 do container na porta 8080 da sua maquina.

services

A lista de todos os containers da stack. Cada chave aqui dentro e um servico.

image

A imagem pronta a usar (do Docker Hub). Alternativa: build: para construir do seu Dockerfile.

ports

Mapeia portas no formato "host:container". A da esquerda e a do seu PC.

💡 Sobre o "version:" no topo

Em tutoriais antigos voce vai ver uma linha version: "3.8" no comeco do arquivo. No Compose moderno (v2) essa linha e opcional e ignorada: pode comecar direto em services:. Se um arquivo de exemplo tiver o version:, nao se assuste, ainda funciona.

⚠️ Erro Comum

Problema: "yaml: line 4: mapping values are not allowed in this context" ou a stack nao sobe.
Solucao: Quase sempre e indentacao errada. YAML nao aceita Tab, so espacos. Mantenha sempre 2 espacos por nivel e nunca misture Tab com espaco. No VS Code, ative "mostrar espacos em branco" para enxergar o problema.

✓ O que FAZER

  • Usar sempre 2 espacos por nivel de indentacao
  • Colocar versoes fixas nas imagens (nginx:1.27)
  • Dar nomes claros aos servicos (app, banco)

✗ O que NAO fazer

  • Usar Tab para indentar (quebra o YAML)
  • Usar so :latest em producao (vira surpresa)
  • Esquecer as aspas em "8080:80"
3

Servicos, Redes e Volumes

Tres conceitos resolvem 90% dos casos: servicos (os containers), redes (como eles conversam) e volumes (onde os dados ficam guardados). A grande sacada do Compose: ele cria uma rede automatica para a sua stack, e dentro dela um servico chama o outro pelo nome.

👁 O que voce vai ver: comunicacao pelo nome

Voce nao usa IP. Se o servico do banco se chama banco, o app se conecta nele pela URL usando o proprio nome do servico como endereco:

# Dentro do container do app, a conexao com o banco e assim:

DATABASE_URL=postgres://user:senha@banco:5432/meubanco

# "banco" e o nome do servico, NAO um IP. O Compose resolve.

Rede: por padrao, ja vem pronta

Ao subir a stack, o Compose cria uma rede so para ela. Todos os servicos entram nessa rede automaticamente e se enxergam pelo nome. Voce so declara redes manualmente quando quer isolar grupos (ex: separar frontend de backend).

services:

app:

image: meu-app

depends_on:

- banco # garante que o banco suba antes

Volume: para os dados nao sumirem

Container e descartavel: se voce remove o container do banco, os dados vao junto. O volume guarda os dados fora do container, num lugar que sobrevive a recriacao. Declare na raiz e use dentro do servico:

services:

banco:

image: postgres:16

volumes:

- dados-db:/var/lib/postgresql/data

# Declaracao do volume na raiz do arquivo:

volumes:

dados-db:

Formato: nome-do-volume:/caminho/dentro/do/container. Mesmo derrubando e recriando o container, os dados continuam la.

⚠️ Erro Comum

Problema: "Toda vez que eu rodo docker compose down meu banco zera."
Solucao: Faltou o volume. Sem volume, os dados moram dentro do container e somem na remocao. Declare um volume nomeado para o banco. Cuidado tambem com down -v: o -v apaga os volumes de proposito.

4

Subir uma Stack Completa: App + Banco

Chegou a hora de juntar tudo. Vamos montar uma stack real: um app web que conversa com um banco PostgreSQL, com volume para os dados nao sumirem. Um arquivo, um comando, dois containers conversando.

O docker-compose.yml completo

# docker-compose.yml

services:

app:

build: . # constroi do Dockerfile local

ports:

- "3000:3000"

environment:

- DATABASE_URL=postgres://user:senha@banco:5432/app

depends_on:

- banco

banco:

image: postgres:16

environment:

- POSTGRES_USER=user

- POSTGRES_PASSWORD=senha

- POSTGRES_DB=app

volumes:

- dados-db:/var/lib/postgresql/data

volumes:

dados-db:

1

Subir a stack inteira

O -d ("detached") solta os containers rodando em segundo plano

$ docker compose up -d

[+] Running 3/3

✓ Network meuapp_default Created

✓ Container meuapp-banco-1 Started

✓ Container meuapp-app-1 Started

2

Conferir que subiu

Lista os containers da stack e o estado de cada um

$ docker compose ps

NAME SERVICE STATUS PORTS

meuapp-app-1 app Up 12 seconds 0.0.0.0:3000->3000/tcp

meuapp-banco-1 banco Up 13 seconds 5432/tcp

3

Derrubar quando terminar

Para e remove os containers e a rede (mas mantem o volume de dados)

$ docker compose down

[+] Running 3/3

✓ Container meuapp-app-1 Removed

✓ Container meuapp-banco-1 Removed

✓ Network meuapp_default Removed

💡 Dica: up sem o -d para ver tudo de uma vez

Na primeira vez, rode docker compose up sem o -d. Os logs de todos os servicos aparecem misturados na tela, ao vivo. Otimo para ver se algo deu erro na subida. Quando estiver tudo certo, derrube com Ctrl+C e suba de novo com -d.

5

Logs e Debug: Quando Algo Quebra

Subiu a stack e o site nao abre? Calma, isso e normal. O Compose te da tres ferramentas para investigar: ver os logs (o que cada servico esta dizendo), ver o estado dos containers, e entrar dentro de um container para olhar de perto.

logs - Ler o que os servicos dizem

# Logs de todos os servicos, acompanhando ao vivo (-f = follow)

$ docker compose logs -f

banco-1 | database system is ready to accept connections

app-1 | Server listening on port 3000

# Logs de UM servico so

$ docker compose logs app

# Apenas as ultimas 50 linhas

$ docker compose logs --tail 50 banco

O log e o primeiro lugar para olhar. 9 em cada 10 problemas aparecem aqui em texto claro.

ps - Ver o estado de cada container

$ docker compose ps

NAME SERVICE STATUS PORTS

meuapp-app-1 app Exited (1) 4 seconds ago

meuapp-banco-1 banco Up 20 seconds 5432/tcp

Aqui o app esta como Exited (1): ele caiu. O proximo passo e olhar o log dele com docker compose logs app.

🔎 exec - Entrar dentro de um container

As vezes voce precisa olhar por dentro: rodar um comando, abrir o cliente do banco, conferir um arquivo. O exec roda um comando dentro de um container que ja esta de pe:

# Abrir um terminal dentro do container do app

$ docker compose exec app sh

/app # ls

node_modules package.json server.js

# Abrir o cliente do PostgreSQL dentro do banco

$ docker compose exec banco psql -U user -d app

app=# \dt

⚠️ Erro Comum

Problema: "O app sobe mas nao conecta no banco: connection refused."
Solucao: O depends_on garante a ordem de subida, mas nao espera o banco ficar pronto para aceitar conexoes (ele leva alguns segundos). Solucao simples: faca o app tentar reconectar algumas vezes. Solucao robusta: use healthcheck no banco + condition: service_healthy no depends_on.

6

Atualizacao e Rollback

Sua aplicacao esta no ar e voce quer publicar uma nova versao. Ou pior: voce publicou e deu ruim, precisa voltar rapido. Com o Compose, atualizar e voltar versao sao operacoes de poucos comandos. O segredo e fixar a tag da imagem para saber sempre qual versao esta rodando.

Atualizar para uma nova versao

Suponha que sua imagem no arquivo era meu-app:1.4 e a nova versao e a 1.5. Voce troca a tag no arquivo e atualiza so o que mudou:

# 1. Editar o compose: image: meu-app:1.4 -> image: meu-app:1.5

# 2. Baixar a nova imagem do registry

$ docker compose pull

✓ app Pulled

# 3. Recriar so os containers que mudaram

$ docker compose up -d

[+] Running 2/2

✓ Container meuapp-banco-1 Running

✓ Container meuapp-app-1 Recreated

Repare: o banco fica Running (nao mexeu) e so o app e Recreated. O Compose so toca no que mudou.

Rollback: voltar para a versao anterior

Deu ruim na 1.5? Volte a tag para 1.4 e suba de novo. Como voce fixou a versao, sabe exatamente para onde voltar.

# Editar o compose de volta: image: meu-app:1.5 -> image: meu-app:1.4

$ docker compose up -d

✓ Container meuapp-app-1 Recreated

# Pronto: em segundos voce esta na versao 1.4 de novo

✓ O que FAZER

  • Fixar tags de versao (app:1.4) para poder voltar
  • Rodar pull antes do up -d
  • Guardar o compose no Git (cada versao vira historico)

✗ O que NAO fazer

  • Usar :latest (nao da para saber qual versao voltar)
  • Rodar down -v achando que e so reiniciar
  • Atualizar direto em producao sem testar antes

🏆 Voce ja consegue rodar uma stack de verdade

Com app + banco + volume num arquivo, subindo com um comando, lendo logs, entrando nos containers e voltando versao quando precisa, voce ja tem o essencial de orquestracao local. No proximo modulo voce vai aprender a fazer essa stack subir sozinha quando o servidor liga, com o systemd.

📚 Resumo do Modulo

Compose e o maestro - rege varios containers com um arquivo e um comando
docker-compose.yml - YAML com indentacao por espacos; comeca em services:
Servicos, redes e volumes - falam pelo nome; volume guarda os dados
up -d / down / ps / logs / exec - subir, derrubar, ver estado, ler logs, entrar
pull + up -d e voltar a tag - atualizar e fazer rollback fixando versoes

Proximo Modulo:

4.3 - Systemd: deixar sua stack subir sozinha quando o servidor liga e reiniciar se cair