DevOps & CI/CD

Redes e Volumes Avançados no Docker: Bridge, Overlay e Bind Mounts: Do Básico ao Avançado

17 min de leitura

Redes e Volumes Avançados no Docker: Bridge, Overlay e Bind Mounts: Do Básico ao Avançado

Introdução: A Importância da Comunicação e Persistência de Dados em Containers Quando começamos a trabalhar com Docker, rapidamente percebemos que containers isolados são úteis, mas limitados. A verdadeira potência do Docker emerge quando precisamos orquestrar múltiplos containers que conversam entre si ou quando necessitamos persistir dados de forma confiável. Este artigo aborda exatamente isso: como criar redes sofisticadas entre containers e gerenciar volumes de dados de forma profissional. Nos próximos tópicos, você compreenderá não apenas como usar bridge networks, overlay networks e bind mounts, mas por que cada uma existe e em que contextos específicos aplicá-las. Vou partir do pressuposto que você já conhece os fundamentos básicos do Docker (containers, images, Docker daemon), e focaremos em casos de uso reais. Docker Bridge Networks: Comunicação em Host Único O que é uma Bridge Network? A bridge network é o driver padrão de rede do Docker quando você cria uma rede customizada. Diferente da bridge padrão ( ), que apresenta limitações severas,

<h2>Introdução: A Importância da Comunicação e Persistência de Dados em Containers</h2>

<p>Quando começamos a trabalhar com Docker, rapidamente percebemos que containers isolados são úteis, mas limitados. A verdadeira potência do Docker emerge quando precisamos orquestrar múltiplos containers que conversam entre si ou quando necessitamos persistir dados de forma confiável. Este artigo aborda exatamente isso: como criar redes sofisticadas entre containers e gerenciar volumes de dados de forma profissional.</p>

<p>Nos próximos tópicos, você compreenderá não apenas <em>como</em> usar bridge networks, overlay networks e bind mounts, mas <em>por que</em> cada uma existe e em que contextos específicos aplicá-las. Vou partir do pressuposto que você já conhece os fundamentos básicos do Docker (containers, images, Docker daemon), e focaremos em casos de uso reais.</p>

<h2>Docker Bridge Networks: Comunicação em Host Único</h2>

<h3>O que é uma Bridge Network?</h3>

<p>A bridge network é o driver padrão de rede do Docker quando você cria uma rede customizada. Diferente da bridge padrão (<code>docker0</code>), que apresenta limitações severas, uma bridge customizada oferece DNS automático entre containers, isolamento de rede melhorado e configuração simplificada. Ela é a escolha ideal para comunicação entre containers em um único host.</p>

<p>Quando um container se conecta a uma bridge network customizada, o Docker automaticamente resolve o hostname do container para seu endereço IP interno. Isso significa que você não precisa gerenciar IPs manualmente — pode referenciar containers pelo seu nome. Essa é uma diferença crucial em relação à bridge padrão, onde containers precisavam ser linkados explicitamente.</p>

<h3>Criando e Testando uma Bridge Network</h3>

<p>Vou demonstrar com um exemplo prático: dois containers (um com Nginx e outro com uma aplicação cliente) que precisam se comunicar.</p>

<pre><code class="language-bash"># Criar uma bridge network customizada

docker network create minha-bridge --driver bridge

Verificar a rede criada

docker network inspect minha-bridge</code></pre>

<p>Agora vamos criar um container de banco de dados e um container de aplicação que precisa acessá-lo:</p>

<pre><code class="language-bash"># Container 1: PostgreSQL

docker run -d \

--name postgres-db \

--network minha-bridge \

-e POSTGRES_PASSWORD=senha123 \

-e POSTGRES_USER=app_user \

postgres:15-alpine

Container 2: Uma aplicação que conecta ao PostgreSQL

docker run -d \

--name app-node \

--network minha-bridge \

-e DATABASE_HOST=postgres-db \

-e DATABASE_USER=app_user \

-e DATABASE_PASSWORD=senha123 \

node:18-alpine sleep 1000</code></pre>

<p>O ponto crucial aqui: o container <code>app-node</code> consegue resolver <code>postgres-db</code> para o IP correto automaticamente. Internamente, o Docker mantém um resolver DNS que mapeia nomes de containers para IPs.</p>

<pre><code class="language-bash"># Testar conectividade (dentro do container app-node)

docker exec app-node ping postgres-db

Resposta esperada: resolução bem-sucedida</code></pre>

<h3>Limitações e Quando Não Usar Bridge</h3>

<p>Bridge networks funcionam apenas em um único host Docker. Se você tem múltiplos hosts Docker (swarm ou Kubernetes), containers em hosts diferentes não conseguem se comunicar através de uma bridge network simples. Para isso, existem as overlay networks, que veremos a seguir.</p>

<h2>Docker Overlay Networks: Orquestração Multi-Host</h2>

<h3>Quando Docker Swarm Entra em Cena</h3>

<p>Overlay networks foram criadas especificamente para comunicação entre containers distribuídos em múltiplos hosts. Elas funcionam encapsulando o tráfego de rede entre hosts usando VXLAN (Virtual Extensible LAN), criando uma camada de abstração que torna a comunicação transparente — você programa como se todos os containers estivessem no mesmo host.</p>

<p>Diferente das bridge networks, overlay networks requerem que o Docker esteja operando em modo Swarm (orquestração nativa do Docker). Em um cluster Swarm, o Docker mantém um banco de dados distribuído de configurações que todos os nós acessam, permitindo que redes overlay funcionem perfeitamente através de múltiplos hosts.</p>

<h3>Inicializando Docker Swarm e Criando uma Overlay Network</h3>

<pre><code class="language-bash"># Inicializar o Swarm no seu host (host1)

docker swarm init

Resultado esperado: token de join para adicionar workers

docker swarm join --token SWMTKN-1-... &lt;ip&gt;:&lt;porta&gt;

Se você tiver outro host, execute o comando de join nele

Para este exemplo, simulamos localmente com apenas um manager

Criar uma overlay network

docker network create --driver overlay meu-overlay-swarm</code></pre>

<p>Agora criamos um serviço (não apenas um container) nessa rede:</p>

<pre><code class="language-bash"># Criar um serviço de banco de dados em modo overlay

docker service create \

--name postgres-service \

--network meu-overlay-swarm \

-e POSTGRES_PASSWORD=senha456 \

postgres:15-alpine

Criar um serviço de aplicação que depende do banco

docker service create \

--name app-service \

--network meu-overlay-swarm \

-e DATABASE_HOST=postgres-service \

alpine sleep 1000

Listar serviços

docker service ls</code></pre>

<p>A diferença fundamental: aqui usamos <code>docker service</code> em vez de <code>docker run</code>. Serviços são entidades de mais alto nível que mantêm o container rodando, podem ser escalados e distribuídos automaticamente pelo Swarm.</p>

<pre><code class="language-bash"># Verificar detalhe da rede overlay

docker network inspect meu-overlay-swarm

Você verá que a rede tem escopo &quot;swarm&quot; (não &quot;local&quot; como bridge)</code></pre>

<h3>Comparação Prática: Bridge vs Overlay</h3>

<div class="table-wrap"><table><thead><tr><th>Aspecto</th><th>Bridge Network</th><th>Overlay Network</th></tr></thead><tbody><tr><td><strong>Escopo</strong></td><td>Um host Docker</td><td>Múltiplos hosts Docker</td></tr><tr><td><strong>Requisito</strong></td><td>Docker daemon rodando</td><td>Docker em modo Swarm</td></tr><tr><td><strong>DNS Interno</strong></td><td>✓ Automático</td><td>✓ Automático</td></tr><tr><td><strong>Encapsulamento</strong></td><td>Nenhum (L2)</td><td>VXLAN (L3)</td></tr><tr><td><strong>Performance</strong></td><td>Mais rápido</td><td>Ligeiramente mais lento (overhead de encapsulamento)</td></tr><tr><td><strong>Use Case</strong></td><td>Desenvolvimento local, Docker Compose</td><td>Produção com múltiplos nós</td></tr></tbody></table></div>

<h2>Volumes e Bind Mounts: Persistência e Compartilhamento de Dados</h2>

<h3>Volumes vs Bind Mounts: Uma Distinção Crucial</h3>

<p>Docker oferece dois mecanismos principais para persistir dados: <strong>volumes gerenciados pelo Docker</strong> e <strong>bind mounts</strong>. Essa é uma distinção que frequentemente confunde iniciantes, mas é fundamental para trabalhar corretamente em produção.</p>

<p>Um <strong>volume</strong> é um caminho de armazenamento completamente gerenciado pelo Docker. O Docker decide onde armazenar os dados no host (normalmente em <code>/var/lib/docker/volumes/</code>), e você não precisa se preocupar com detalhes. Volumes são agnósticos ao sistema de arquivos host, portáveis entre sistemas operacionais e fáceis de fazer backup.</p>

<p>Um <strong>bind mount</strong> mapeia um diretório específico do host (que você controla) diretamente para um caminho dentro do container. É mais explícito, permite acesso direto aos arquivos do host, mas é também mais frágil — se o diretório host não existir, você terá problemas.</p>

<h3>Criando e Usando Volumes Gerenciados</h3>

<pre><code class="language-bash"># Criar um volume nomeado

docker volume create dados-aplicacao

Listar volumes existentes

docker volume ls

Inspecionar um volume (ver onde está armazenado fisicamente)

docker volume inspect dados-aplicacao</code></pre>

<p>Resultado esperado:</p>

<pre><code class="language-json">[

{

&quot;Name&quot;: &quot;dados-aplicacao&quot;,

&quot;Driver&quot;: &quot;local&quot;,

&quot;Mountpoint&quot;: &quot;/var/lib/docker/volumes/dados-aplicacao/_data&quot;,

&quot;Labels&quot;: {},

&quot;Scope&quot;: &quot;local&quot;

}

]</code></pre>

<p>Agora usamos esse volume em um container:</p>

<pre><code class="language-bash"># Container que escreve dados em um volume

docker run -d \

--name app-com-volume \

--volume dados-aplicacao:/app/data \

-e LOG_FILE=/app/data/app.log \

alpine sh -c &#039;while true; do echo &quot;$(date): evento registrado&quot; &gt;&gt; /app/data/app.log; sleep 5; done&#039;

Aguardar alguns segundos e verificar os dados

sleep 10

Acessar o arquivo de log diretamente no volume

docker exec app-com-volume cat /app/data/app.log</code></pre>

<p>A vantagem aqui é portabilidade: se você mover esse container para outro host Docker, o volume pode ser facilmente restaurado desde que você tenha feito backup dos dados.</p>

<h3>Bind Mounts: Compartilhamento Bidirecional</h3>

<p>Bind mounts são extremamente úteis em desenvolvimento, onde você quer que mudanças no seu código local se reflitam imediatamente dentro do container.</p>

<pre><code class="language-bash"># Criar um diretório local (ele deve existir)

mkdir -p ~/meu-projeto/data

Container com bind mount

docker run -d \

--name app-dev \

--mount type=bind,source=$(pwd)/meu-projeto,target=/workspace \

-v ~/meu-projeto/data:/app/persistido \

node:18-alpine sleep 1000

Criar um arquivo no host

echo &quot;Criado do host&quot; &gt; ~/meu-projeto/arquivo-teste.txt

Verificar dentro do container

docker exec app-dev cat /workspace/arquivo-teste.txt

Resultado: &quot;Criado do host&quot;

Agora criar um arquivo dentro do container

docker exec app-dev sh -c &#039;echo &quot;Criado do container&quot; &gt; /workspace/container-arquivo.txt&#039;

Verificar no host

cat ~/meu-projeto/container-arquivo.txt

Resultado: &quot;Criado do container&quot;</code></pre>

<p>Esse bidirecionalismo é perfeito para desenvolvimento, mas perigoso em produção — alguém pode acidentalmente modificar arquivos críticos do host.</p>

<h3>Estratégia de Persistência em Produção</h3>

<p>Em produção, recomendo uma abordagem estruturada:</p>

<pre><code class="language-bash"># Criar volumes para diferentes componentes

docker volume create db-data

docker volume create cache-data

docker volume create logs-data

Composição de um stack com volumes apropriados

docker service create \

--name postgres-prod \

--volume db-data:/var/lib/postgresql/data \

--network producao-overlay \

postgres:15-alpine

docker service create \

--name redis-prod \

--volume cache-data:/data \

--network producao-overlay \

redis:7-alpine

docker service create \

--name app-prod \

--volume logs-data:/var/log/aplicacao \

--network producao-overlay \

minha-app:latest</code></pre>

<p>Cada componente tem seu próprio volume, facilitando backup, restore e troubleshooting. Volumes gerenciados também possuem suporte a drivers customizados (NFS, iSCSI, cloud storage), permitindo arquitetura escalável.</p>

<h3>Permissões e Propriedade de Arquivos</h3>

<p>Um detalhe frequentemente ignorado: o UID/GID dos arquivos dentro do volume. Quando um container escreve em um volume, a propriedade do arquivo reflete o usuário dentro do container.</p>

<pre><code class="language-bash"># Entender o mapping de UIDs

docker run -d \

--name uid-test \

--volume dados-aplicacao:/dados \

alpine sh -c &#039;id &gt; /dados/uid-info.txt; sleep 100&#039;

Verificar no host (precisa de sudo)

sudo cat /var/lib/docker/volumes/dados-aplicacao/_data/uid-info.txt

Mostrará: uid=0(root) gid=0(root) (se rodou como root)

Solução: executar container com usuário específico

docker run -d \

--name uid-test-user \

--user 1000:1000 \

--volume dados-aplicacao:/dados \

alpine sh -c &#039;id &gt; /dados/uid-info-user.txt; sleep 100&#039;</code></pre>

<h2>Integração Prática: Um Stack Completo com Bridge, Overlay e Volumes</h2>

<h3>Cenário: Microserviços em Desenvolvimento e Produção</h3>

<p>Vamos consolidar tudo em um exemplo realista. Imagine uma aplicação com:</p>

<ul>

<li><strong>API em Node.js</strong> que precisa de um banco PostgreSQL</li>

<li><strong>Cache em Redis</strong> para performance</li>

<li><strong>Arquivo de logs</strong> persistido</li>

<li><strong>Dados do banco</strong> sempre salvos</li>

</ul>

<p>Para <strong>desenvolvimento local</strong> (usando bridge + bind mount):</p>

<pre><code class="language-bash"># Criar a bridge network

docker network create dev-network

PostgreSQL com volume local

docker run -d \

--name postgres-dev \

--network dev-network \

--volume postgres-dev-data:/var/lib/postgresql/data \

-e POSTGRES_PASSWORD=dev123 \

postgres:15-alpine

Redis

docker run -d \

--name redis-dev \

--network dev-network \

redis:7-alpine

Aplicação Node (com bind mount para código)

docker run -d \

--name app-dev \

--network dev-network \

--mount type=bind,source=$(pwd)/src,target=/app/src \

--volume app-logs:/app/logs \

-e DB_HOST=postgres-dev \

-e REDIS_HOST=redis-dev \

-p 3000:3000 \

node:18-alpine node /app/src/index.js</code></pre>

<p>Para <strong>produção</strong> (usando overlay + volumes gerenciados):</p>

<pre><code class="language-bash"># Iniciar swarm (apenas uma vez)

docker swarm init

Criar overlay network

docker network create --driver overlay producao-network

Serviços

docker service create \

--name postgres-prod \

--network producao-network \

--volume postgres-prod-data:/var/lib/postgresql/data \

-e POSTGRES_PASSWORD=$(openssl rand -base64 12) \

postgres:15-alpine

docker service create \

--name redis-prod \

--network producao-network \

--volume redis-prod-data:/data \

redis:7-alpine

docker service create \

--name app-prod \

--network producao-network \

--volume app-prod-logs:/app/logs \

-e DB_HOST=postgres-prod \

-e REDIS_HOST=redis-prod \

--publish 80:3000 \

minha-app-image:latest</code></pre>

<p>A transição entre desenvolvimento e produção é clara: mudamos driver de rede (bridge → overlay), mecanismo de execução (docker run → docker service), e vinculação de volumes (bind mount → volume gerenciado).</p>

<h2>Troubleshooting Comum</h2>

<h3>Containers não conseguem se comunicar</h3>

<p>Verificação passo a passo:</p>

<pre><code class="language-bash"># 1. Confirmar que ambos estão na mesma rede

docker inspect container1 | grep -A 5 &quot;Networks&quot; docker inspect container2 | grep -A 5 &quot;Networks&quot;

2. Testar DNS

docker exec container1 nslookup container2

Se falhar, eles não estão na mesma rede customizada

3. Verificar firewalls/iptables

docker network inspect nome-rede

Procura por &quot;Containers&quot; e confirme que ambos aparecem

4. Testar conectividade em baixo nível

docker exec container1 ping container2

docker exec container1 nc -zv container2 5432 # Para aplicações de rede</code></pre>

<h3>Volumes não aparecem onde esperado</h3>

<pre><code class="language-bash"># Confirmar mount point

docker inspect --format=&#039;{{json .Mounts}}&#039; nome-container | jq .

Verificar permissões

docker exec nome-container ls -la /caminho/no/container

Para bind mount, confirmar que source existe no host

ls -la /seu/caminho/local</code></pre>

<h3>Overlay network não funciona entre hosts</h3>

<pre><code class="language-bash"># Confirmar que ambos hosts estão no mesmo Swarm

docker node ls

Deve listar ambos os nós

Verificar conectividade de rede (portas necessárias: 2377, 7946, 4789)

Entre os hosts

ss -tuln | grep -E &#039;2377|7946|4789&#039;

Inspecionar a rede overlay no detalhe

docker network inspect nome-overlay

Procura por peers em ambos os nós</code></pre>

<h2>Conclusão</h2>

<p>Compreender redes bridge, overlay e volumes não é apenas dominar sintaxe — é entender as abstrações que Docker fornece para resolver problemas reais de comunicação e persistência.</p>

<p>Primeiro aprendizado: <strong>bridge networks são suficientes e melhores para desenvolvimento local</strong>, enquanto <strong>overlay networks escalam para produção multi-host</strong> com o custo de complexidade adicionada. Escolher entre elas é uma decisão arquitetural que afeta toda sua operação.</p>

<p>Segundo aprendizado: <strong>volumes gerenciados e bind mounts servem propósitos diferentes</strong> — volumes para persistência profissional, bind mounts para desenvolvimento iterativo. Confundir os dois em produção é receita para desastre.</p>

<p>Terceiro aprendizado: <strong>a transição entre ambientes (dev → prod) deve ser clara e previsível</strong>. Se sua aplicação funciona localmente com bridge + bind mount, a versão em Swarm com overlay + volumes deve funcionar igualmente bem, com mudanças apenas no driver de rede e mecanismo de orquestração.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://docs.docker.com/network/" target="_blank" rel="noopener noreferrer">Docker Official Documentation - Networks</a></li>

<li><a href="https://docs.docker.com/storage/volumes/" target="_blank" rel="noopener noreferrer">Docker Official Documentation - Volumes</a></li>

<li><a href="https://docs.docker.com/engine/swarm/" target="_blank" rel="noopener noreferrer">Docker Swarm Mode Documentation</a></li>

<li><a href="https://github.com/moby/moby/blob/master/docs/articles/networking.md" target="_blank" rel="noopener noreferrer">Moby (Docker) GitHub - Networking Deep Dive</a></li>

<li><a href="https://www.amazon.com/Docker-Deep-Dive-Nigel-Poulton/dp/B01LXWQUFF" target="_blank" rel="noopener noreferrer">Nigel Poulton - &quot;Docker Deep Dive&quot; (Capítulos sobre Networking e Storage)</a></li>

</ul>

<p>&lt;!-- FIM --&gt;</p>

Comentários

Mais em DevOps & CI/CD

Guia Completo de Podman e Alternativas ao Docker: Daemonless Containers na Prática
Guia Completo de Podman e Alternativas ao Docker: Daemonless Containers na Prática

Entendendo Containers Tradicionais vs. Daemonless A história dos containers c...

Gerenciamento de Usuários, Grupos e Sudo em Ambientes de Produção: Do Básico ao Avançado
Gerenciamento de Usuários, Grupos e Sudo em Ambientes de Produção: Do Básico ao Avançado

Fundamentos de Gerenciamento de Usuários em Ambientes Linux Em ambientes de p...

O que Todo Dev Deve Saber sobre AWS Avançado: EKS, ECS, Lambda e RDS em Ambientes Reais
O que Todo Dev Deve Saber sobre AWS Avançado: EKS, ECS, Lambda e RDS em Ambientes Reais

Arquitetura Moderna na AWS: Da Orquestração de Contêineres ao Serverless A co...