Comunicação entre services e DNS interno
2 min de leitura
Na trilha de Docker Fundamentos, você aprendeu que uma rede bridge
customizada dá DNS interno: containers na mesma rede se acham por
nome. O Compose faz isso por padrão, sem você declarar nada. Toda
stack do Compose ganha uma rede com o nome do projeto (o nome da
pasta onde está o docker-compose.yml, kebab-case), e cada service
participa dela automaticamente.
Como o DNS resolve
services:
api:
build: .
environment:
DATABASE_URL: postgres://user:pass@db:5432/app # "db" é o nome do service
db:
image: postgres:16
Quando o Compose sobe essa stack, ele cria uma rede chamada
nome-do-projeto_default (ex: minha-api_default). Os containers
api e db são conectados nela e podem se resolver por nome:
Repare: o db resolve pra um IP interno da rede Docker (algo
como 172.18.0.3), não pra localhost. O api está na mesma
rede, então o DNS interno resolve o nome. De fora (do seu navegador),
você acessa localhost:3000 por causa do ports: "3000:3000".
depends_on - ordem de inicialização
services:
api:
depends_on:
- db
db:
image: postgres:16
depends_on garante que db é criado e iniciado antes de api.
Útil, mas tem um problema sutil: o Postgres pode demorar 5-10s pra
ficar pronto pra aceitar conexões, e a api pode subir antes disso.
No primeiro request, dá erro de conexão.
A solução robusta é um healthcheck (que detalhamos mais pra frente, mas já fica o spoiler):
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
api:
depends_on:
db:
condition: service_healthy # espera o healthcheck passar
Agora api só sobe depois que db reporta healthy. Bem mais
confiável.
Networks customizadas
A rede padrão cobre 90% dos casos. Pra casos mais complexos - isolar o banco da API, separar frontend de backend - você cria redes explícitas:
services:
nginx:
networks: [frontend]
api:
networks: [frontend, backend]
db:
networks: [backend]
networks:
frontend:
backend:
Aqui nginx e api se conversam; api e db se conversam; mas
nginx não alcança db (não estão na mesma rede). Bom pra
reduzir superfície de ataque.
Três conceitos que você acabou de aprender:
- DNS interno é padrão - services na mesma stack se resolvem por nome sem você declarar rede nenhuma.
depends_oncontrola ordem de subida, mas pra esperar o serviço ficar saudável, combine comhealthcheckecondition: service_healthy.- Networks customizadas isolam grupos de services. Útil pra segurança (banco não exposto) e organização.
Dica: o nome da rede padrão é
<projeto>_defaultonde<projeto>é o nome da pasta atual. Se quiser mudar, declare a rede explicitamente e usename: minha-redeno nível raiz.
No próximo nó, vamos turbinar o desenvolvimento com hot reload, watch e profiles - porque ninguém quer rebuildar imagem a cada save.