DevOps Admin

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

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,

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 (docker0), 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.

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.

Criando e Testando uma Bridge Network

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

# Criar uma bridge network customizada
docker network create minha-bridge --driver bridge

# Verificar a rede criada
docker network inspect minha-bridge

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

# 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

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

# Testar conectividade (dentro do container app-node)
docker exec app-node ping postgres-db
# Resposta esperada: resolução bem-sucedida

Limitações e Quando Não Usar Bridge

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.

Docker Overlay Networks: Orquestração Multi-Host

Quando Docker Swarm Entra em Cena

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.

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.

Inicializando Docker Swarm e Criando uma Overlay Network

# Inicializar o Swarm no seu host (host1)
docker swarm init

# Resultado esperado: token de join para adicionar workers
# docker swarm join --token SWMTKN-1-... <ip>:<porta>

# 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

Agora criamos um serviço (não apenas um container) nessa rede:

# 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

A diferença fundamental: aqui usamos docker service em vez de docker run. 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.

# Verificar detalhe da rede overlay
docker network inspect meu-overlay-swarm

# Você verá que a rede tem escopo "swarm" (não "local" como bridge)

Comparação Prática: Bridge vs Overlay

Aspecto Bridge Network Overlay Network
Escopo Um host Docker Múltiplos hosts Docker
Requisito Docker daemon rodando Docker em modo Swarm
DNS Interno ✓ Automático ✓ Automático
Encapsulamento Nenhum (L2) VXLAN (L3)
Performance Mais rápido Ligeiramente mais lento (overhead de encapsulamento)
Use Case Desenvolvimento local, Docker Compose Produção com múltiplos nós

Volumes e Bind Mounts: Persistência e Compartilhamento de Dados

Volumes vs Bind Mounts: Uma Distinção Crucial

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

Um volume é um caminho de armazenamento completamente gerenciado pelo Docker. O Docker decide onde armazenar os dados no host (normalmente em /var/lib/docker/volumes/), 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.

Um bind mount 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.

Criando e Usando Volumes Gerenciados

# 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

Resultado esperado:

[
    {
        "Name": "dados-aplicacao",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/dados-aplicacao/_data",
        "Labels": {},
        "Scope": "local"
    }
]

Agora usamos esse volume em um container:

# 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 'while true; do echo "$(date): evento registrado" >> /app/data/app.log; sleep 5; done'

# 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

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.

Bind Mounts: Compartilhamento Bidirecional

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.

# 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 "Criado do host" > ~/meu-projeto/arquivo-teste.txt

# Verificar dentro do container
docker exec app-dev cat /workspace/arquivo-teste.txt
# Resultado: "Criado do host"

# Agora criar um arquivo dentro do container
docker exec app-dev sh -c 'echo "Criado do container" > /workspace/container-arquivo.txt'

# Verificar no host
cat ~/meu-projeto/container-arquivo.txt
# Resultado: "Criado do container"

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

Estratégia de Persistência em Produção

Em produção, recomendo uma abordagem estruturada:

# 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

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.

Permissões e Propriedade de Arquivos

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.

# Entender o mapping de UIDs
docker run -d \
  --name uid-test \
  --volume dados-aplicacao:/dados \
  alpine sh -c 'id > /dados/uid-info.txt; sleep 100'

# 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 'id > /dados/uid-info-user.txt; sleep 100'

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

Cenário: Microserviços em Desenvolvimento e Produção

Vamos consolidar tudo em um exemplo realista. Imagine uma aplicação com:
- API em Node.js que precisa de um banco PostgreSQL
- Cache em Redis para performance
- Arquivo de logs persistido
- Dados do banco sempre salvos

Para desenvolvimento local (usando bridge + bind mount):

# 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

Para produção (usando overlay + volumes gerenciados):

# 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

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).

Troubleshooting Comum

Containers não conseguem se comunicar

Verificação passo a passo:

# 1. Confirmar que ambos estão na mesma rede
docker inspect container1 | grep -A 5 "Networks"
docker inspect container2 | grep -A 5 "Networks"

# 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 "Containers" 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

Volumes não aparecem onde esperado

# Confirmar mount point
docker inspect --format='{{json .Mounts}}' 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

Overlay network não funciona entre hosts

# 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 '2377|7946|4789'

# Inspecionar a rede overlay no detalhe
docker network inspect nome-overlay
# Procura por peers em ambos os nós

Conclusão

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.

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

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

Terceiro aprendizado: a transição entre ambientes (dev → prod) deve ser clara e previsível. 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.

Referências


Artigos relacionados