Conteúdo
Tutorial de redes Docker: bridge, redes personalizadas e comunicação entre contêineres
Quando um aplicativo precisa se conectar a um banco de dados, cache ou outro contêiner, você precisa entender as redes Docker. A ideia mais importante é: coloque os contêineres que precisam se comunicar na mesma rede personalizada para que eles possam se conectar usando os nomes uns dos outros.
Drivers de rede
Uma instalação nova do Docker tem três redes integradas:
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a74caef4acb9 bridge bridge local
b9a49b39804b host host local
87a8a7fd2cd9 none null local
| Driver | Descrição |
|---|---|
bridge | Padrão. O contêiner tem seu próprio IP em uma sub-rede virtual |
host | O contêiner usa diretamente a rede do host, sem isolamento (funciona melhor no Linux) |
none | Sem rede |
overlay | Entre vários hosts (Docker Swarm) |
macvlan | Faz o contêiner aparecer na rede local como uma máquina física |
Limitações da bridge padrão
Se você não especificar uma rede, o contêiner se conectará à rede padrão chamada bridge. Nessa rede, os contêineres não podem se conectar pelo nome:
$ docker run -d --name web1 nginx:1.30
b1d3fb9024c112c5990d9ac85012cd3f5e38c114ab4409a06f960c6d8cdb496e
$ docker run --rm alpine:3.23 ping -c 1 -W 2 web1
ping: bad address 'web1'
$ docker inspect --format '{{.NetworkSettings.IPAddress}}' web1
template parsing error: template: :1:18: executing "" at <.NetworkSettings.IPAddress>: map has no entry for key "IPAddress"
$ docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web1
172.18.0.2
$ docker run --rm alpine:3.23 ping -c 1 172.18.0.2
PING 172.18.0.2 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.058 ms
--- 172.18.0.2 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.058/0.058/0.058 ms
$ docker rm -f web1
web1
- Não é possível encontrar o nome
web1(bad address), mas é possível se conectar usando o IP172.18.0.2. - Porém, o Docker atribui o IP automaticamente, e ele pode mudar quando o contêiner for recriado. Por isso, não o fixe na configuração.
Mudança no Docker 29: nas versões anteriores, você podia usar
{{.NetworkSettings.IPAddress}}para obter o IP do contêiner. O Docker 29 removeu esse campo (veja otemplate parsing erroracima). Use{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}.
Por isso, na prática, quase sempre se cria uma rede personalizada.
Rede personalizada: comunicação pelo nome
docker network create appnet
docker run -d --name db --network appnet -e POSTGRES_PASSWORD=secret postgres:18
$ docker network create appnet
fadfeb6028cb78335fa94cfd7536265256a914cc461caae1026b6ebb21e9d7a0
$ docker run -d --name db --network appnet -e POSTGRES_PASSWORD=secret postgres:18
227033e27591e6a1c195a6d63a141aaf4486c6285477792fe3080e1d4deeb2c0
$ docker run --rm --network appnet alpine:3.23 ping -c 2 db
PING db (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.069 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.092 ms
--- db ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.069/0.080/0.092 ms
$ docker run --rm --network appnet -e PGPASSWORD=secret postgres:18 psql -h db -U postgres -c "SELECT version();"
version
--------------------------------------------------------------------------------------------------------------------
PostgreSQL 18.6 (Debian 18.6-1.pgdg13+2) on x86_64-pc-linux-gnu, compiled by gcc (Debian 14.2.0-19) 14.2.0, 64-bit
(1 row)
$ docker network inspect appnet --format "{{range .Containers}}{{.Name}} {{.IPv4Address}}{{println}}{{end}}"
db 172.19.0.2/16
- Na rede
appnet, o DNS integrado do Docker resolve o nomedbpara o IP do contêiner do banco de dados. - O cliente PostgreSQL se conectou usando
-h dbe consultou a versão do banco de dados (PostgreSQL 18.6). - O contêiner do banco de dados não usa
-p, então o host e sistemas externos não conseguem acessá-lo. Somente os contêineres na mesma rede podem, o que é mais seguro.
A configuração de conexão do aplicativo também usa o nome do contêiner, por exemplo:
docker run -d --name app --network appnet -p 3000:3000 \
-e DATABASE_URL=postgres://postgres:secret@db:5432/postgres \
myapp
Atenção:
- A conexão entre contêineres usa a porta interna do contêiner (5432), independentemente de
-p. - Só os serviços que precisam ser acessados pelo host ou externamente (como um site) precisam de
-p. - Evite usar nomes de contêiner como
webouapp, que também são palavras usadas como domínios de nível superior, como destino da conexão. Dentro da mesma rede, não há problema, mas consultas feitas fora dela podem resolver para endereços inesperados e confundir a depuração.
Um contêiner em várias redes e aliases de rede
$ docker network create appnet
77fadbc5633854c9e75fd9aa65325d0155ad33f5de453abac7f15f6766402bee
$ docker run -d --name app --network appnet nginx:1.30
25b4c1d92caeef5ca8765daf2f3ad6247982cacfad4914000ded8a0a455df851
$ docker network create frontend
45a9ab78fddb9f1b47a22b9ce156144286888c42eadc2b4f589986fe1f98cee0
$ docker network connect frontend app
$ docker inspect --format '{{range $k, $v := .NetworkSettings.Networks}}{{$k}} {{$v.IPAddress}}{{println}}{{end}}' app
appnet 172.19.0.2
frontend 172.20.0.2
$ docker run -d --name search --network appnet --network-alias es nginx:1.30
43b07713e7ec032d21e37fdf690064b389f798ed26b2715e7ea18c15840647af
$ docker run --rm --network appnet alpine:3.23 getent hosts es
172.19.0.3 es es
$ docker rm -f app search
app
search
$ docker network rm appnet frontend
appnet
frontend
docker network connectadiciona um contêiner em execução a outra rede. Agora,apptem dois IPs. Isso é usado com frequência para isolamento: a rede frontend conecta o Nginx ao aplicativo, e a rede backend conecta o aplicativo ao banco de dados. Assim, o Nginx não consegue acessar o banco de dados.--network-alias espermite que outros contêineres na mesma rede também usem o nomeespara se conectar asearch. Quando vários contêineres usam o mesmo alias, o DNS retorna vários IPs.
Gerenciar redes
docker network create appnet
docker network ls
docker network inspect appnet # Veja os contêineres e IPs
docker network connect appnet nome-do-contêiner # Adicione o contêiner em execução à rede
docker network disconnect appnet nome-do-contêiner
docker network rm appnet
docker network prune # Remova redes não utilizadas
Mapeamento de portas: o aplicativo precisa escutar em 0.0.0.0
-p 8000:8000 faz com que o Docker encaminhe o tráfego enviado à porta 8000 do host para a porta 8000 na interface de rede do contêiner. Por isso, o aplicativo dentro do contêiner precisa escutar em 0.0.0.0 (todas as interfaces), e não apenas em 127.0.0.1 (o localhost do próprio contêiner). Compare na prática com o servidor web integrado do Python:
$ docker run -d --name localonly -p 8000:8000 python:3.14-slim python -m http.server 8000 --bind 127.0.0.1
246edb96a9affefaab188ac7d5ceec2fb103b511bdac352cca6ed3a80ae6764a
$ curl -sS http://localhost:8000
curl: (52) Empty reply from server
$ docker rm -f localonly
localonly
$ docker run -d --name allif -p 8000:8000 python:3.14-slim python -m http.server 8000 --bind 0.0.0.0
438fa44edf6aec790a7e6b2bfcdb7af33c16a14c661c50b8d9564ff52844e5e6
$ curl -s http://localhost:8000 | head -n 3
<!DOCTYPE HTML>
<html lang="en">
<head>
$ docker rm -f allif
allif
- Quando o aplicativo escuta apenas em
127.0.0.1, a porta está mapeada, mas ocurlretornaEmpty reply from server: o tráfego chegou ao contêiner, mas o aplicativo está aguardando apenas no localhost do próprio contêiner e não recebe a conexão. - Ao configurar a escuta em
0.0.0.0, tudo funciona.
Muitos servidores de desenvolvimento escutam em localhost por padrão. Ao executá-los em um contêiner, especifique o endereço:
flask run --host 0.0.0.0
uvicorn main:app --host 0.0.0.0
vite --host 0.0.0.0
Conectar-se ao host a partir de um contêiner
Para permitir que um contêiner acesse um serviço no host (por exemplo, um banco de dados em execução no host), use o nome especial host.docker.internal:
$ docker run --rm alpine:3.23 getent hosts host.docker.internal
$ docker run --rm --add-host=host.docker.internal:host-gateway alpine:3.23 getent hosts host.docker.internal
172.18.0.1 host.docker.internal host.docker.internal
- Docker Desktop (Windows, macOS): oferece suporte integrado a
host.docker.internal. - Linux: esse nome não existe por padrão (o primeiro comando não retorna nenhuma saída). Adicione
--add-host=host.docker.internal:host-gateway; o nome será resolvido para o endereço do host na rede Docker.
O serviço no host também precisa escutar em uma interface acessível pelo contêiner, e não apenas em 127.0.0.1.
Rede host e rede none
docker run -d --network host nginx:1.30
O contêiner usa diretamente a interface de rede do host. Se o nginx escutar na porta 80, essa será a porta 80 do host, sem precisar de -p (se você informar essa opção, ela será ignorada). O desempenho é o melhor possível, mas não há isolamento e pode haver conflito de portas com aplicativos no host. O comportamento no Docker Desktop não é exatamente igual ao do Linux.
Com --network none, o contêiner fica totalmente sem rede e tem apenas a interface de loopback local:
$ docker run --rm --network none alpine:3.23 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
É útil para tarefas que não precisam de rede ou não devem se conectar a ela (por exemplo, processar arquivos não confiáveis).
Solução de problemas
Não é possível conectar contêineres usando localhost
Cada contêiner tem seu próprio localhost. Se você se conectar a localhost:5432 dentro do contêiner app, estará se conectando ao próprio app, e não ao contêiner do banco de dados. Use o nome do contêiner, por exemplo, db:5432.
Não é possível conectar ao contêiner a partir do host
Verifique nesta ordem:
- Confira com
docker psse o campoPORTScontém0.0.0.0:8080->80/tcp. - Verifique se o aplicativo dentro do contêiner está escutando em
0.0.0.0(Empty reply from server, mostrado acima, é um sintoma típico). - Verifique se o firewall do host ou o grupo de segurança na nuvem permite essa porta.
O contêiner não consegue acessar a internet
Geralmente, é um problema de DNS. Você pode especificar o DNS em /etc/docker/daemon.json (no Docker Desktop, em Settings → Docker Engine). Reinicie o Docker depois da alteração:
{ "dns": ["1.1.1.1", "8.8.8.8"] }
Ao usar Docker Compose, o Compose cria automaticamente uma rede para o projeto. Os serviços podem se conectar diretamente usando os nomes uns dos outros.
Resumo
- A rede bridge padrão não oferece resolução de nomes. Use uma rede personalizada para conectar contêineres.
- Em uma rede personalizada, conecte os contêineres usando seus nomes ou
--network-alias. - O aplicativo precisa escutar em
0.0.0.0para que o mapeamento de portas funcione. - Para um contêiner se conectar ao host, use
host.docker.internal.
Exercícios
Exercício 1: Crie a rede lab, inicie nela um contêiner redis:8-alpine chamado cache e, em seguida, use outro contêiner para testar com redis-cli -h cache ping.
Resposta
docker network create lab
docker run -d --name cache --network lab redis:8-alpine
docker run --rm --network lab redis:8-alpine redis-cli -h cache ping
A saída é PONG. Consulte os comandos de rede em docker network.
Perguntas frequentes
Por que localhost dentro de um contêiner não conecta a outro contêiner?
Cada contêiner tem sua própria rede, e localhost aponta para o próprio contêiner. Para se conectar a outro contêiner, coloque os dois na mesma rede personalizada e use o nome do contêiner.
Como um contêiner se conecta a um serviço em execução no host?
No Docker Desktop, use host.docker.internal; no Linux, adicione --add-host host.docker.internal:host-gateway. Veja “Como conectar um contêiner ao host” neste capítulo.
Como obter o IP de um contêiner no Docker 29?
{{.NetworkSettings.IPAddress}} foi removido. Use docker inspect -f "{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}" contêiner.
Atualizado 14 de outubro de 2026