Um arquivo do Compose costuma ser a descrição mais honesta que você tem de um sistema. É o que de fato sobe no notebook, no CI e às vezes em produção. Também é uma parede de YAML, e quem acabou de entrar no time ainda precisa perguntar qual serviço conversa com qual.
Este guia transforma um arquivo do Compose em um diagrama de arquitetura confiável: renderize o arquivo que o Compose realmente executa, mapeie cada chave para um elemento do diagrama, adicione as chamadas que o arquivo não consegue expressar e mantenha o desenho em sincronia com o arquivo. No final, usamos a ferramenta gratuita do Archboard para ter o primeiro rascunho em segundos.
O exemplo: uma pequena stack shop
Este é o compose.yaml que vamos desenhar. Ele é curto, mas tem as armadilhas de sempre: um serviço em duas redes, uma dependência que só existe em um arquivo de configuração e uma ferramenta só para desenvolvimento.
name: shop
services:
web:
image: nginx:1.27
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- api
networks: [frontend]
api:
build: ./api
environment:
DATABASE_URL: postgres://shop:${POSTGRES_PASSWORD}@db:5432/shop
REDIS_URL: redis://cache:6379/0
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
networks: [frontend, backend]
worker:
build: ./api
command: ["node", "worker.js"]
environment:
DATABASE_URL: postgres://shop:${POSTGRES_PASSWORD}@db:5432/shop
REDIS_URL: redis://cache:6379/0
depends_on:
- db
deploy:
replicas: 2
networks: [backend]
db:
image: postgres:16
environment:
POSTGRES_USER: shop
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U shop"]
interval: 5s
networks: [backend]
cache:
image: redis:7
networks: [backend]
adminer:
image: adminer
ports:
- "8081:8080"
profiles: [debug]
networks: [backend]
volumes:
db-data:
networks:
frontend:
backend:
Passo 1: renderize o arquivo que o Compose realmente executa
Times raramente executam um único arquivo do jeito que ele está escrito. Um arquivo override adiciona portas, um arquivo .env preenche variáveis e extends puxa campos de outro serviço. Antes de desenhar, peça o resultado ao Compose:
docker compose config > rendered.yaml
docker compose config junta os arquivos override, preenche as variáveis e resolve extends, depois imprime o modelo que o Compose vai executar. Desenhe a partir dessa saída, não do arquivo que por acaso estiver aberto.
Um aviso: a saída contém os valores reais das suas variáveis, inclusive qualquer segredo do .env. Trate o rendered.yaml como o próprio arquivo .env: não faça commit nem compartilhe.
Passo 2: mapeie as chaves do Compose para elementos do diagrama
A maior parte do diagrama vem direto do arquivo:
| Chave do Compose | Elemento do diagrama |
|---|---|
services.<name> |
Um cartão por serviço, com o nome da sua chave |
image / build |
No cartão: a tag da imagem ou o contexto de build |
ports (8080:80) |
No cartão e na conexão que vem de fora: :8080 → 80 |
deploy.replicas / scale |
Um número de réplicas no cartão, não caixas extras |
networks |
Um frame por rede; cada serviço fica no frame da sua primeira rede |
volumes nomeados |
Um nó de volume ligado aos serviços que o montam |
secrets, configs |
Nós ligados aos serviços que os usam, apenas pelo nome |
depends_on |
Ordem de inicialização, escrita no cartão ou como conexão tracejada |
profiles |
Serviços opcionais: deixe de fora ou marque como opcionais |
Duas regras mantêm o desenho honesto. Um serviço que entra em duas redes, como o api, é a ponte entre elas: coloque-o na borda do frame da sua primeira rede e deixe as conexões dele atravessarem para a outra. E réplicas são um número, não uma pilha de caixas: worker ×2 continua correto quando você escala para cinco.
Passo 3: adicione as chamadas que o arquivo não mostra
Este é o passo que nenhuma ferramenta faz por você. depends_on trata da ordem de inicialização: o Compose sobe o db antes do api e, com condition: service_healthy, espera o healthcheck passar. Ele não diz nada sobre quem chama quem em tempo de execução.
As chamadas reais se escondem em três lugares:
- Strings de conexão.
DATABASE_URLeREDIS_URLnomeiam hosts (db,cache) e portas. Cada uma é uma conexão no diagrama. - Arquivos de configuração montados nos contêineres. O
nginx.confcontémproxy_pass http://api:3000;. Essa é a conexão dowebpara oapi, e ela fica fora do arquivo do Compose. - Código. Um serviço pode chamar outro sem nenhuma linha no Compose. O
workerusaREDIS_URL, mas não temdepends_onpara ocache. Se o Redis subir atrasado, o worker falha na inicialização, e o diagrama é o primeiro lugar onde essa lacuna aparece.
Uma busca rápida encontra a maioria delas:
grep -rnE "://([^/@[:space:]]*@)?(api|web|db|cache)[:/]|proxy_pass" --include="*.conf" --include="*.yaml" --include="*.yml" --include="*.env" .
Depois confirme com o dono de cada serviço. Desenhe as chamadas em tempo de execução como conexões contínuas, rotuladas com protocolo e porta, e mantenha o depends_on como nota ou conexão tracejada, para ninguém confundir ordem de inicialização com tráfego.
Passo 4: decida o que deixar de fora
Um arquivo do Compose mistura o sistema com as ferramentas em volta dele. Normalmente você deixa de fora:
- Serviços só de desenvolvimento atrás de
profiles, como oadminer, capturadores de e-mail ou proxies de debug. - Jobs avulsos, como migrations ou seeders, a menos que o diagrama seja sobre deploy.
- Bind mounts de código-fonte e arquivos de configuração. Mostre um arquivo de configuração só pela dependência que ele carrega, como aqui a conexão
proxy_passque vem donginx.conf. - Valores de ambiente. Nomes de variáveis podem explicar uma conexão; os valores ficam no seu gerenciador de segredos, não em um diagrama.
Passo 5: monte o layout
Coloque o tráfego da esquerda para a direita: o navegador, depois a porta publicada, depois os serviços por trás dela. Desenhe cada rede como um frame, para que uma chamada que atravessa redes salte aos olhos. Agrupe os armazenamentos de dados e coloque os volumes abaixo do serviço que os monta. Rotule cada conexão com protocolo e porta, por exemplo HTTP :3000 ou SQL :5432.
Gere o primeiro rascunho com a ferramenta gratuita
Você não precisa desenhar os cartões à mão. Cole o arquivo (ou a saída renderizada; a ferramenta não lê valores de ambiente) na ferramenta gratuita Docker Compose para diagrama. Para visualizar não é preciso conta. Os serviços viram cartões com imagem, portas e réplicas, as redes viram frames, volumes nomeados, secrets e configs são ligados aos serviços que os usam, e o depends_on vira conexões entre serviços.
A ferramenta desenha só o que o arquivo diz. Ela não mostra chamadas em tempo de execução, não lê valores de ambiente nem o conteúdo de env_file, não segue include e, para um serviço que usa extends, desenha só os campos escritos naquele serviço. Por isso os passos 1 e 3 continuam importantes.
Com uma conta gratuita, você abre o resultado no Archboard como um novo diagrama e depois adiciona as conexões em tempo de execução do passo 3 e remove o ruído do passo 4. Esta é a stack shop depois dessa revisão:
Conteúdo do diagrama
- Browser
- frontend
- backend
- web
- api
- cache
- db
- worker
- db-data
- HTTP :8080 → 80
- proxy_pass :3000
- SQL :5432
- RESP :6379
- jobs :6379
- /var/lib/postgresql/data
Os cartões vêm do pack Docker, o navegador do pack Rede, e o diagrama inteiro cabe nos 15 nós de diagrama do plano Free. Para outro layout Docker, com contêineres, um registry e um balanceador de carga, veja o exemplo Docker Runtime Mesh.
Mantenha atualizado
Um diagrama desenhado a partir de um arquivo do Compose fica desatualizado no dia em que alguém adiciona um serviço. Três hábitos ajudam:
- Adicione uma linha ao template de pull request: "Adiciona um serviço, uma rede, uma porta publicada ou uma string de conexão? Atualize o diagrama."
- Rode
docker compose configde novo nas revisões e compare a lista de serviços com o diagrama. - No README, coloque um link para o diagrama ao vivo em vez de colar um screenshot, para que exista só uma cópia para atualizar.
Quando a stack migrar para o Kubernetes, o mesmo método vale para os manifests; veja Do YAML do Kubernetes a um diagrama de arquitetura.
Perguntas frequentes
depends_on significa que um serviço chama outro?
Não. Ele controla a ordem de inicialização e, com condition: service_healthy, também espera um healthcheck. As chamadas em tempo de execução vêm das strings de conexão, dos arquivos de configuração e do código.
Posso fazer o diagrama de vários arquivos do Compose de uma vez?
Renderize-os primeiro com docker compose config, que junta os arquivos override em um único modelo. A ferramenta gratuita lê um arquivo por vez.
A ferramenta lê meu arquivo .env?
Não. As variáveis não são substituídas: uma tag de imagem ou porta escrita com uma variável, como image: shop-api:${TAG}, aparece exatamente como foi escrita, e os valores em environment e em env_file não são lidos.
Devo desenhar uma caixa por contêiner? Desenhe um cartão por serviço e escreva nele o número de réplicas. Contêineres individuais vêm e vão; o time raciocina em termos de serviços.
O diagrama é atualizado quando eu mudo o compose.yaml? Não. Ele é um ponto de partida. Mantenha-o atualizado com os hábitos acima, ou redesenhe com a ferramenta e copie suas conexões em tempo de execução.