Docker · 50 min

Conecte containers com redes Docker

Vá além da publicação de portas e aprenda como os containers de fato conversam entre si. Explore a bridge padrão, crie uma rede personalizada com DNS automático e prove a comunicação container-a-container pelo nome com testes reais de ping e wget.

Problema

Você já sabe rodar um container e publicar uma porta para o navegador. Mas aplicações reais nunca são um container só — um app web conversa com um banco, um cache, uma fila. No momento em que você tem dois containers que precisam se alcançar, surge uma nova pergunta: **como um container acha e conversa com o outro?** Iniciantes apelam para endereços IP fixos, e funciona — até um container reiniciar, ganhar um IP novo e tudo quebrar. A resposta do Docker são as *redes*: redes virtuais que conectam containers e, numa rede personalizada, te dão **DNS automático** para que um container alcance o outro simplesmente pelo nome, não importa qual IP ele receba. Neste lab você vai ver exatamente por que a rede `bridge` padrão não basta, criar sua própria rede, rodar dois containers nela e provar que eles se resolvem pelo nome com saída real de `ping` e `wget`. Você também vai aprender a inspecionar redes, conectar e desconectar containers em tempo real e usar redes separadas para isolar grupos de serviços — o exato mecanismo que o Compose usa por baixo dos panos.

Objetivos

Pré-requisitos

O que você vai construir

Você não vai escrever código de aplicação neste lab. Em vez disso, vai conectar dois containers
para que eles conversem entre si pelo nome
— a habilidade de rede mais importante para apps
reais, multi-serviço. Você primeiro vai ver a bridge padrão falhar em resolver nomes, depois
criar sua própria rede onde isso funciona, e provar com saída real de ping e wget capturada
de dentro de um container.

O modelo mental essencial: containers ficam isolados até uma rede conectá-los

Por padrão um container é uma caixa lacrada. Publicar uma porta com -p abre uma porta para o
host, mas não diz nada sobre como dois containers se alcançam entre si. É isso que uma
rede Docker é: um switch virtual no qual os containers se plugam. Dois containers na mesma rede
podem conversar; dois containers em redes diferentes não podem (a menos que você os ligue de
propósito).

Os três drivers de rede que você vai encontrar

Driver O que faz Quando usar
bridge O padrão. Uma rede virtual privada num único host; containers ganham IPs internos e podem conversar entre si Quase sempre — a escolha padrão para containers numa máquina
host Remove o isolamento de rede; o container compartilha diretamente a pilha de rede do host (sem precisar de -p) Raro — quando você precisa de desempenho máximo de rede ou o container precisa ligar em portas do host diretamente
none Desabilita a rede por completo; o container tem só uma interface de loopback Quando um container precisa ficar totalmente isolado de qualquer rede

Existe também a overlay, usada para conectar containers em múltiplos hosts num Swarm/cluster
— fora do escopo deste lab de host único, mas vale saber que ela existe.

A sacada principal: bridge padrão vs bridge personalizada

Ambas são redes "bridge", mas se comportam de forma diferente, e isso pega quase todo mundo:

Você vai ver os dois comportamentos em primeira mão. Faça os passos em ordem — cada um se apoia no
anterior, e você vai coletar as saídas que precisa para a entrega do Passo 6.

Passos

  1. Entenda o modelo de rede do Docker e os drivers

    Antes de criar qualquer coisa, tenha o mapa na cabeça: o que é uma rede Docker e qual driver
    faz o quê.

    Por que redes existem

    Um container é isolado por padrão. Quando você rodou docker run -d -p 8080:80 nginx, a flag
    -p abriu um caminho do seu host até o container — mas isso é host-para-container. Não diz
    nada sobre como um segundo container alcançaria o primeiro. Para isso, ambos os containers
    precisam compartilhar uma rede.

    Liste as redes que o Docker já tem

    Uma instalação nova do Docker vem com três redes. Olhe para elas:

    docker network ls
    

    Você verá ao menos:

    NETWORK ID     NAME      DRIVER    SCOPE
    xxxxxxxxxxxx   bridge    bridge    local
    xxxxxxxxxxxx   host      host      local
    xxxxxxxxxxxx   none      null      local
    

    Elas mapeiam diretamente para os três drivers que você vai usar num único host:

    • bridge — a rede privada padrão. Todo container iniciado sem --network entra nesta.
      Containers aqui ganham um IP interno e se alcançam por IP.
    • host — sem isolamento; o container usa a rede do host diretamente. Inicie um container
      com --network host e suas portas são as portas do host (sem mapeamento -p). Rápido, mas
      você perde o isolamento e não pode rodar dois containers que querem a mesma porta.
    • none — rede desabilitada. --network none dá ao container só uma interface de loopback.
      Útil para um job que não pode tocar a rede de jeito nenhum.

    A decisão em uma linha

    Use bridge (quase sempre), apele para host só quando precisar da rede crua do host, e
    use none quando um container precisa ficar isolado da rede. Para clusters multi-host
    existe a overlay, que este lab não cobre.

    Checkpoint

    • Qual driver os containers usam se você não passa --network? (bridge — o padrão)
    • -p 8080:80 deixa dois containers conversarem entre si? (Não — ele só conecta o host a um container. Container-a-container precisa de uma rede compartilhada.)
    • Qual driver você escolheria para um job em lote que nunca pode fazer chamada de rede? (none)
  2. Explore a bridge padrão e bata no limite de DNS dela

    Vamos provar por que a bridge padrão não basta, para que a rede personalizada do Passo 3
    pareça merecida e não arbitrária.

    Baixe uma imagem pequena e amiga do ping

    Você vai usar o busybox — uma imagem minúscula que traz ping, wget, nslookup e um
    shell, perfeita para testes de rede.

    docker pull busybox:1.36
    docker pull nginx:1.27-alpine
    

    Rode dois containers na bridge padrão

    Inicie dois containers busybox de vida longa sem a flag --network, para que entrem na
    bridge padrão. O sleep 3600 só os mantém vivos para você conseguir dar exec neles.

    docker run -d --name c1 busybox:1.36 sleep 3600
    docker run -d --name c2 busybox:1.36 sleep 3600
    docker ps
    

    Inspecione a bridge padrão

    Veja quem está conectado e quais IPs receberam:

    docker network inspect bridge
    

    Role até a seção "Containers" — você verá c1 e c2, cada um com um IPv4Address como
    172.17.0.2/16 e 172.17.0.3/16. Anote o IP de c2; você vai usá-lo já já.

    A limitação: a resolução de nomes falha

    Tente alcançar c2 pelo nome de dentro de c1:

    docker exec c1 ping -c 2 c2
    

    Isso falha — ping: bad address 'c2'. Na bridge padrão não há DNS, então o nome c2 não
    significa nada. Agora tente o mesmo container pelo IP (use o endereço que você viu na
    saída do inspect):

    docker exec c1 ping -c 2 172.17.0.3
    

    Isso funciona. Os containers conseguem se alcançar — estão na mesma rede — mas só por IP.
    E IPs mudam toda vez que um container reinicia, o que faz de fixá-los uma armadilha.

    Checkpoint

    • Na bridge padrão, por que ping c2 falhou mas ping <IP do c2> funcionou? (Sem DNS na bridge padrão — nomes não são resolvidos, só IPs crus roteiam.)
    • Por que depender do IP é uma má ideia? (IPs são atribuídos dinamicamente e mudam no restart; sua config quebraria.)

    Entregável deste passo: capture a saída do ping c2 que falha e a do ping <IP> que
    funciona — elas são a metade "antes" da sua entrega.

  3. Crie uma rede personalizada com DNS automático

    Agora o ganho. Numa rede que você cria, o Docker roda um servidor DNS embutido e os
    containers se resolvem pelo nome.

    Crie a rede

    docker network create minha-rede
    

    O Docker imprime o ID da nova rede. Por padrão ela usa o driver bridge (você pode ser
    explícito com --driver bridge, mas bridge é o padrão para um único host). Confirme que
    existe:

    docker network ls
    

    Você verá minha-rede na lista ao lado das embutidas bridge, host e none.

    Rode dois containers na nova rede

    A flag --network liga um container a uma rede no momento em que ele inicia. Rode um servidor
    web nginx e um cliente busybox, ambos em minha-rede:

    docker run -d --network minha-rede --name web nginx:1.27-alpine
    docker run -d --network minha-rede --name cliente busybox:1.36 sleep 3600
    
    • web — o servidor nginx, alcançável na porta 80 dentro da rede (repare: nenhum -p é
      preciso para tráfego container-a-container; você só publica uma porta quando o
      host/navegador precisa entrar).
    • cliente — uma caixa busybox de onde você vai rodar os comandos de teste.

    Inspecione a rede personalizada

    docker network inspect minha-rede
    

    No bloco "Containers" você verá web e cliente conectados, cada um com um IP na sub-rede
    desta rede. Igual à bridge padrão até aqui — a diferença fica invisível até você usar um nome,
    que é o próximo passo.

    Por que isso importa

    No instante em que dois containers compartilham uma rede personalizada, o Docker registra os
    nomes deles no seu DNS interno. web e cliente agora se acham pelo nome — sem IPs, sem
    arquivos de config, sem restarts quebrando nada. É exatamente isso que o Docker Compose
    configura para você automaticamente nos bastidores; aqui você está fazendo na mão para
    entender a engrenagem.

    Checkpoint

    • Para qual driver o docker network create cai por padrão num único host? (bridge)
    • Por que você não passou -p ao iniciar web? (Porque cliente o alcança pela rede compartilhada na porta 80 diretamente; -p é só para expor um container ao host.)

    Entregável deste passo: a saída de docker network ls mostrando minha-rede, e a saída de
    docker network inspect minha-rede mostrando os dois containers conectados.

  4. Prove a comunicação container-a-container pelo nome

    Este é o coração do lab: rodar testes reais de dentro de um container contra outro, usando só
    nomes. Este é o "depois" que contrasta com a falha do Passo 2.

    Ping pelo nome — agora funciona

    De dentro de cliente, dê ping em web pelo nome:

    docker exec cliente ping -c 3 web
    

    Diferente do Passo 2, isso funciona: você verá respostas de web e, o mais importante, o
    nome resolve para um IP na minha-rede:

    PING web (172.19.0.2): 56 data bytes
    64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.089 ms
    64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.101 ms
    ...
    

    O DNS embutido do Docker transformou web no IP certo automaticamente. Este é todo o
    propósito das redes personalizadas.

    Confirme a resolução de DNS explicitamente

    docker exec cliente nslookup web
    

    Você verá web resolver para o IP do container via o servidor DNS do Docker em 127.0.0.11 —
    o resolver embutido que toda rede personalizada ganha.

    Busque a página web de verdade pelo nome

    O ping prova alcançabilidade; agora prove que o serviço responde. web roda nginx na porta
    80, então peça a homepage dele a partir de cliente usando o nome:

    docker exec cliente wget -qO- http://web
    

    Você vai receber o HTML da página "Welcome to nginx!", buscado pela rede pelo nome. Se a saída
    do wget do busybox ficar silenciosa, wget -S http://web -O /dev/null mostra os cabeçalhos
    da resposta (um 200 OK do nginx) no lugar.

    Nota sobre curl: o busybox traz wget, não curl. Se você prefere curl, rode-o a
    partir de uma imagem que o tenha, ex.: docker run --rm --network minha-rede curlimages/curl:8.9.1 -s http://web.
    A lição é idêntica — o nome web resolve dentro da rede.

    Por que isso é tão importante

    Você acabou de endereçar outro container por um nome estável que sobrevive a restarts, em
    vez de um IP frágil. Seu app web pode apontar para db, seu worker para redis, e continua
    funcionando não importa quais IPs o Docker distribua. A descoberta de serviços por nome é a
    base da qual todo arquivo Compose e ferramenta de orquestração depende.

    Checkpoint

    • O que fez ping web funcionar aqui quando ping c2 falhou no Passo 2? (Esta rede é personalizada, então o DNS embutido do Docker resolve os nomes dos containers; a bridge padrão não tem esse DNS.)
    • Qual IP de servidor DNS o nslookup reportou? (127.0.0.11 — o resolver embutido do Docker.)

    Entregável deste passo: capture o ping -c 3 web bem-sucedido, a saída de nslookup web e
    a saída de wget -qO- http://web (ou -S) mostrando que o nginx respondeu pelo nome.

  5. Gerencie redes: conectar, desconectar, isolar, diagnosticar

    Redes não são estáticas. Você pode ligar e desligar containers em execução e usar redes
    separadas para isolar grupos de serviços — a verdadeira razão pela qual redes são uma
    ferramenta de segurança, não só uma conveniência.

    Isolamento: um container em outra rede não consegue entrar

    Inicie um terceiro container na bridge padrão (não na minha-rede) e tente alcançar web:

    docker run -d --name estranho busybox:1.36 sleep 3600
    docker exec estranho ping -c 2 web
    

    Isso falha — estranho não está na minha-rede, então nem consegue resolver ou rotear até
    web. Redes separadas isolam serviços: exatamente como você manteria um banco de dados fora da
    rede voltada ao público. Isso espelha a divisão webnet vs dbnet do ebook, onde um container
    web e um container db em redes diferentes simplesmente não conseguem conversar.

    Conecte um container em execução a uma rede

    Você não precisa recriar um container para ligá-lo à rede. Ligue estranho à minha-rede ao
    vivo:

    docker network connect minha-rede estranho
    docker exec estranho ping -c 2 web
    

    Agora funciona — estranho ganhou uma segunda interface na minha-rede e consegue
    resolver web. Este é o truque de "rede compartilhada" do ebook: dois grupos que de outra
    forma estariam isolados podem ser ligados de propósito ao entrarem numa rede comum, sem
    derrubar nada.

    Desconecte-o de novo

    docker network disconnect minha-rede estranho
    docker exec estranho ping -c 2 web    # falha de novo — de volta ao isolado
    

    Diagnostique de dentro de um container

    Quando algo não conecta, estas ferramentas (todas no busybox) dizem por quê:

    docker exec cliente nslookup web      # o nome está resolvendo?
    docker exec cliente ping -c 2 web     # o host está alcançável?
    docker exec cliente wget -S http://web -O /dev/null   # o serviço está respondendo (200)?
    docker network inspect minha-rede     # quem está de fato conectado?
    

    Trabalhe de cima para baixo: DNS → alcançabilidade → resposta do serviço → participação na
    rede. A maioria dos bugs de "não conecta" é um container simplesmente não estar na rede
    esperada — o docker network inspect revela na hora.

    Limpe as redes

    Desconecte ou pare os containers e então remova a rede. Uma rede não pode ser removida enquanto
    houver containers conectados:

    docker rm -f web cliente c1 c2 estranho
    docker network rm minha-rede
    docker network prune          # remove TODAS as redes não usadas; pede confirmação
    

    Checkpoint

    • Por que estranho não alcançava web a princípio? (Estava na bridge padrão, não na minha-rede — redes diferentes são isoladas.)
    • Como você as ligou sem recriar o container? (docker network connect minha-rede estranho o ligou ao vivo.)
    • O que precisa ser verdade antes de docker network rm funcionar? (Nenhum container conectado àquela rede.)

    Entregável deste passo: capture a falha de isolamento, o docker network connect + ping
    bem-sucedido, e a limpeza final confirmando que a rede sumiu.

  6. Entregue: documente sua rede e os testes de conectividade

    Prove que você conectou dois containers e os fez conversar pelo nome capturando a evidência
    real num pequeno repositório.

    Monte sua entrega

    Crie uma pasta, inicialize o git e escreva um SUBMISSION.md documentando o que você fez. Cole
    as saídas reais que coletou — não texto inventado. O contraste entre a bridge padrão (Passo
    2) e sua rede personalizada (Passo 4) é o núcleo da entrega.

    # Docker Lab 4 — Conecte containers com redes Docker
    
    ## 1. docker network ls (redes padrão + minha-rede)
    <cole seu `docker network ls` mostrando bridge/host/none e minha-rede>
    
    ## 2. Bridge padrão: nome FALHA, IP funciona
    Saída de `docker exec c1 ping -c 2 c2` (deve FALHAR: bad address):
    <cole>
    Saída de `docker exec c1 ping -c 2 <IP do c2>` (deve FUNCIONAR):
    <cole>
    
    ## 3. docker network inspect minha-rede
    <cole, mostrando web e cliente conectados>
    
    ## 4. Rede personalizada: nome RESOLVE
    Saída de `docker exec cliente ping -c 3 web` (deve FUNCIONAR):
    <cole>
    Saída de `docker exec cliente nslookup web`:
    <cole — repare no resolver 127.0.0.11>
    Saída de `docker exec cliente wget -qO- http://web` (ou `-S`):
    <cole — o nginx respondeu pelo nome>
    
    ## 5. Isolamento + connect/disconnect
    `docker exec estranho ping web` antes do connect (FALHA):
    <cole>
    Após `docker network connect minha-rede estranho`, ping web (FUNCIONA):
    <cole>
    
    ## 6. Limpeza
    <cole `docker network rm minha-rede` e um `docker network ls` final>
    
    ## Reflexão (2-3 frases)
    Nas minhas palavras: por que a bridge padrão não resolvia nomes, o que uma rede personalizada
    acrescenta (DNS embutido) e por que a descoberta por nome ganha de IPs fixos.
    

    Entregue

    git init
    git add SUBMISSION.md
    git commit -m "Docker lab 4 — redes de containers"
    # faça push para um repo público ou crie um gist, depois entregue essa URL
    

    Entregue a URL do repositório ou gist como seu deliverable do lab.

    Critério de submissão (autoverificação)

    • A saída de docker network ls mostra sua minha-rede ao lado das redes embutidas
    • Você capturou a bridge padrão falhando em resolver um nome (ping <nome> → bad address) mas funcionando por IP
    • docker network inspect minha-rede mostra os dois containers conectados
    • ping -c 3 web a partir de cliente funciona pelo nome na rede personalizada
    • nslookup web mostra a resolução via o DNS embutido 127.0.0.11
    • wget http://web retornou a resposta do nginx (HTML da página ou um cabeçalho 200) — um serviço real respondeu pelo nome
    • Você demonstrou o isolamento e um docker network connect ao vivo corrigindo-o
    • Um docker network ls final confirma que minha-rede foi removida (host limpo)
    • Sua reflexão explica corretamente bridge padrão vs DNS de rede personalizada e por que nomes ganham de IPs

    Checklist anti-stub

    Toda saída precisa ser real e sua. IPs inventados, blocos de exemplo copiados e colados
    ou um ping que "funcionaria" não são uma entrega. O corretor procura o contraste: o mesmo
    ping <nome> que falha na bridge padrão e funciona na minha-rede. Se os dois parecerem
    idênticos, você não rodou um deles de verdade.

    O que vem a seguir

    Você já sabe conectar containers em redes e fazê-los se descobrir pelo nome — a espinha dorsal
    de todo app multi-serviço. Mas tudo que você fez até aqui é efêmero: apague um container e
    os dados dele somem. No próximo lab de Docker você vai resolver isso com volumes e
    persistência de dados
    — mantendo bancos e arquivos vivos entre restarts e rebuilds de
    containers.