Solução de Problemas de Rede no Docker: Resolvendo Problemas de Conectividade de Forma Eficaz

Corrija problemas de rede no Docker com DNS de contêiner, redes definidas pelo usuário, publicação de portas, acesso ao host, DNS e firewalls.

Solução de Problemas de Rede no Docker: Resolvendo Problemas de Conectividade de Forma Eficaz

Problemas de rede no Docker são muito mais fáceis de resolver quando você nomeia a direção da conexão com falha. "O contêiner não consegue conectar" é muito vago. O host está tentando alcançar um contêiner? Um contêiner está tentando alcançar outro? Um contêiner está tentando alcançar a internet? O tráfego está entrando de outra máquina? Cada caminho usa um comportamento diferente do Docker.

Comece escrevendo o caminho em linguagem simples:

navegador no host -> localhost:8080 -> porta do contêiner 80
contêiner api -> contêiner db -> porta 5432
contêiner worker -> internet pública -> api.example.com:443
laptop remoto -> IP público do servidor -> porta publicada do contêiner

Depois de conhecer o caminho, você pode testar cada salto em vez de alterar as redes aleatoriamente.

Conheça os modos básicos de rede do Docker

A maioria das configurações de Docker em um único host usa rede bridge. O Docker cria uma rede virtual no host, atribui endereços IP privados aos contêineres e pode publicar portas selecionadas dos contêineres no host.

A rede bridge padrão funciona, mas as redes bridge definidas pelo usuário são melhores para aplicativos porque fornecem DNS integrado por nome do contêiner. Isso significa que um contêiner api pode alcançar um contêiner db em db:5432 se ambos estiverem conectados à mesma rede definida pelo usuário.

Crie uma assim:

docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name api --network appnet my-api

Existem outros modos. A rede host compartilha o namespace de rede do host e remove o comportamento normal de publicação de portas; é útil em alguns casos no Linux, mas reduz o isolamento. none fornece ao contêiner nenhuma rede. overlay é para redes Docker Swarm de vários hosts. O Compose cria redes definidas pelo usuário para projetos automaticamente, a menos que você configure o contrário.

"Rede não encontrada"

Este erro geralmente significa que o nome da rede está errado ou a rede existe em um contexto diferente do que o comando espera.

Verifique as redes disponíveis:

docker network ls

Inspecione a que você pretende usar:

docker network inspect appnet

Se ela não existir, crie-a:

docker network create appnet

Com o Compose, o nome real da rede pode ser prefixado pelo nome do projeto. Uma rede chamada backend no compose.yml pode aparecer como myproject_backend. Use:

docker compose ps
docker network ls

Se você declarou uma rede externa no Compose, o Compose não a criará para você:

networks:
  appnet:
    external: true

Nesse caso, crie-a manualmente ou remova external: true se o Compose deve gerenciá-la.

A comunicação entre contêineres falha

Para que dois contêineres conversem pelo nome, eles geralmente precisam estar na mesma rede definida pelo usuário. Confirme isso primeiro:

docker network inspect appnet

Procure por ambos os contêineres na seção Containers.

Em seguida, teste a partir de um contêiner que tenha ferramentas básicas. Sua imagem de aplicativo pode não incluir curl, dig ou ping, e tudo bem. Use um contêiner de depuração temporário na mesma rede:

docker run --rm -it --network appnet nicolaka/netshoot

De dentro:

dig db
curl -v http://api:8080/health
nc -vz db 5432

Se o DNS falhar, os contêineres provavelmente não estão na mesma rede definida pelo usuário ou você está usando a rede bridge padrão esperando uma resolução de nomes que ela não fornece da mesma forma. Se o DNS funcionar, mas a conexão falhar, verifique se o serviço de destino está ouvindo na porta esperada.

Dentro do contêiner de destino:

docker exec -it api sh
ss -ltnp || netstat -ltnp

Um erro comum é vincular o aplicativo a 127.0.0.1 dentro do contêiner. Isso só escuta no loopback dentro desse contêiner. Outros contêineres não conseguem alcançá-lo. Configure o aplicativo para escutar em 0.0.0.0.

Certifique-se também de usar a porta do contêiner, não a porta publicada no host, para tráfego entre contêineres. Se o banco de dados escuta na porta 5432 no contêiner, outros contêineres devem usar db:5432, não localhost:15432 ou a porta publicada no host.

O host não consegue alcançar um contêiner

Para que o host alcance um serviço em um contêiner com rede bridge, você normalmente precisa de uma porta publicada:

docker run -d --name web -p 8080:80 nginx

Isso mapeia a porta 8080 do host para a porta 80 do contêiner. Teste a partir do host:

curl -v http://localhost:8080

Verifique o que o Docker publicou:

docker port web
docker ps --format 'table {{.Names}}	{{.Ports}}'

Se não houver mapeamento de porta, EXPOSE no Dockerfile não publica a porta. EXPOSE é documentação e metadados. Você ainda precisa de -p ou ports: no Compose.

Se a porta estiver publicada, mas a conexão falhar, verifique quatro coisas:

  1. O aplicativo está ouvindo dentro do contêiner na porta do contêiner.
  2. O aplicativo está ouvindo em 0.0.0.0, não apenas em 127.0.0.1.
  3. Nenhum firewall do host bloqueia a porta do host.
  4. Nenhum outro processo já possui a porta do host.

Encontre conflitos de porta do host:

sudo lsof -i :8080
# ou
sudo ss -ltnp 'sport = :8080'

Para o Compose, lembre-se da sintaxe:

ports:
  - "8080:80"

O lado esquerdo é a porta do host. O lado direito é a porta do contêiner.

O contêiner não consegue alcançar a internet

Teste a conectividade IP e o DNS separadamente:

docker exec -it app sh
ping -c 2 1.1.1.1
ping -c 2 example.com

Algumas imagens não incluem ping. Use curl se disponível:

curl -I https://example.com

Se o IP funcionar, mas os nomes falharem, é um problema de DNS. Verifique:

cat /etc/resolv.conf

O Docker normalmente injeta configurações de resolvedor. VPNs corporativas, DNS personalizado e rede do Docker Desktop podem complicar isso. Você pode configurar o DNS no nível do daemon nas configurações do daemon do Docker, ou passar DNS para um contêiner específico:

docker run --dns 1.1.1.1 ...

Não use DNS público cegamente em ambientes corporativos onde nomes internos devem ser resolvidos. Use os servidores DNS apropriados para a rede.

Se nem IP nem DNS funcionarem, verifique se o contêiner está em --network none, se as regras de firewall/NAT do host estão quebradas, se o daemon do Docker tem configurações de rede personalizadas e se o próprio host tem acesso à internet.

Um contêiner precisa alcançar um serviço no host

A partir de um contêiner, localhost significa o próprio contêiner, não o host. Esta é uma das surpresas mais comuns de rede no Docker.

No Docker Desktop, host.docker.internal geralmente resolve para o host. No Docker Engine moderno para Linux, você pode adicionar uma entrada de gateway do host:

docker run --add-host=host.docker.internal:host-gateway ...

Então o contêiner pode chamar:

curl http://host.docker.internal:3000

Certifique-se de que o serviço do host escute em um endereço acessível pelo Docker, não apenas em uma vinculação de loopback que o Docker não pode acessar em seu ambiente. Se um servidor de desenvolvimento local só vincula a 127.0.0.1, você pode precisar vinculá-lo a 0.0.0.0 ou à interface do host, dependendo do sistema operacional e dos requisitos de segurança.

Máquinas remotas não conseguem alcançar o contêiner

Se o host consegue alcançar localhost:8080, mas outra máquina não consegue alcançar server-ip:8080, o Docker pode estar bem. Verifique o firewall do host, grupo de segurança da nuvem, roteador/NAT e se o Docker publicou apenas no loopback.

Isso publica em todas as interfaces do host:

docker run -p 8080:80 nginx

Isso publica apenas no localhost:

docker run -p 127.0.0.1:8080:80 nginx

A publicação apenas no loopback é frequentemente desejável para desenvolvimento local ou configurações de proxy reverso, mas bloqueará o acesso remoto por design.

Em servidores em nuvem, verifique também os firewalls do provedor. Abrir ufw na VM não ajuda se o grupo de segurança da nuvem ainda bloquear a porta.

Erros de rede no Compose

O Compose dá a cada serviço um nome DNS baseado no nome do serviço. Se seu serviço se chama db, outros serviços geralmente devem se conectar a db, não a localhost.

Exemplo:

services:
  api:
    build: .
    environment:
      DATABASE_URL: postgres://postgres:postgres@db:5432/app
    depends_on:
      - db
  db:
    image: postgres:16

depends_on controla a ordem de inicialização, não a prontidão. O contêiner do banco de dados pode iniciar antes que o Postgres esteja pronto para aceitar conexões. Seu aplicativo deve tentar reconexões ou usar um padrão de inicialização com verificação de saúde.

Também distinga ports de expose. ports publica no host. expose documenta ou expõe portas para serviços vinculados, mas não as torna acessíveis a partir do host da mesma forma.

Depuração no nível de pacotes

Quando as verificações normais não explicam o problema, use uma imagem de depuração de rede:

docker run --rm -it --network container:<target-container> nicolaka/netshoot

Isso entra no namespace de rede do contêiner de destino, permitindo que você inspecione a rede do mesmo ponto de vista sem instalar ferramentas na imagem do aplicativo.

Comandos úteis incluem:

ip addr
ip route
cat /etc/resolv.conf
dig service-name
curl -v http://service-name:port
tcpdump -nn -i any port 8080

Use tcpdump quando precisar saber se os pacotes chegam. Se os pacotes nunca chegarem, procure antes do contêiner: publicação, firewall, roteamento, balanceador de carga. Se os pacotes chegarem e nenhuma resposta sair, procure dentro do contêiner ou aplicativo.

Um fluxo curto de solução de problemas

Use esta ordem para a maioria dos problemas de rede no Docker:

  1. Defina o caminho exato: host para contêiner, contêiner para contêiner, contêiner para internet ou remoto para host para contêiner.
  2. Verifique a conexão de rede com docker network inspect.
  3. Verifique a resolução de nomes do lado de origem.
  4. Verifique se o processo de destino está ouvindo na interface e porta corretas.
  5. Verifique a publicação de portas apenas para tráfego que cruza do host para o contêiner.
  6. Verifique firewall, VPN, proxy, DNS e regras de segurança da nuvem fora do Docker.

A maioria dos problemas de rede no Docker não são bugs profundos do Docker. Geralmente são nomes errados, portas erradas, vinculação de loopback, portas publicadas ausentes, suposições de DNS ou tráfego sendo testado do lado errado do limite.