Containers são projetados para ser efêmeros. Quando um container é removido, tudo que foi escrito em seu sistema de arquivos desaparece junto. Para uma aplicação web stateless isso é perfeito — mas para um banco de dados, um sistema de arquivos de uploads ou qualquer serviço que precisa persistir dados entre reinicializações, essa característica é um problema.
Da mesma forma, containers são isolados por padrão — um container não enxerga os outros. Uma aplicação Node.js em um container não consegue se conectar a um PostgreSQL em outro container sem que essa comunicação seja explicitamente configurada.
Volumes e redes são as duas funcionalidades do Docker que resolvem esses dois problemas. Entendê-las é essencial para compor sistemas realistas com múltiplos serviços.
Volumes: Persistindo Dados
Um volume é um mecanismo de armazenamento gerenciado pelo Docker que existe independentemente do ciclo de vida dos containers. Quando um container é removido, o volume permanece intacto — e pode ser montado em um novo container.
Existem três formas de montar armazenamento externo em um container:
Volumes gerenciados pelo Docker — o Docker controla onde os dados ficam no host (/var/lib/docker/volumes/). É a forma recomendada para a maioria dos casos.
Bind mounts — mapeia um diretório específico do host para dentro do container. O desenvolvedor controla exatamente onde os dados ficam. Muito usado em desenvolvimento para que mudanças no código local reflitam imediatamente no container.
tmpfs mounts — armazenamento em memória, não persiste em disco. Útil para dados sensíveis temporários.
Trabalhando com Volumes
# Cria um volume gerenciado
docker volume create dados-postgres
# Lista volumes existentes
docker volume ls
# Inspeciona um volume — mostra onde os dados ficam no host
docker volume inspect dados-postgres
# Remove um volume
docker volume rm dados-postgres
# Remove volumes não utilizados por nenhum container
docker volume prune
Montando o volume em um container de banco de dados:
docker run -d \
--name postgres \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=senha123 \
-e POSTGRES_DB=producao \
-v dados-postgres:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16
O flag -v dados-postgres:/var/lib/postgresql/data instrui o Docker a montar o volume dados-postgres no caminho /var/lib/postgresql/data dentro do container — que é exatamente onde o PostgreSQL armazena seus arquivos de dados.
Para verificar que a persistência funciona:
# Conecta ao banco e cria uma tabela
docker exec -it postgres psql -U app -d producao -c \
"CREATE TABLE teste (id serial, nome text);"
docker exec -it postgres psql -U app -d producao -c \
"INSERT INTO teste (nome) VALUES ('dado persistido');"
# Remove o container
docker rm -f postgres
# Sobe um novo container com o mesmo volume
docker run -d \
--name postgres-novo \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=senha123 \
-e POSTGRES_DB=producao \
-v dados-postgres:/var/lib/postgresql/data \
postgres:16
# Verifica que os dados ainda existem
docker exec -it postgres-novo psql -U app -d producao -c \
"SELECT * FROM teste;"
A tabela e os dados estarão presentes no novo container — o volume sobreviveu à remoção do container original.
Bind Mounts em Desenvolvimento
Em desenvolvimento, é comum usar bind mounts para que alterações no código local reflitam imediatamente dentro do container, sem precisar reconstruir a imagem:
docker run -d \
--name app-dev \
-v $(pwd)/src:/app/src \
-v $(pwd)/package.json:/app/package.json \
-p 3000:3000 \
minha-app:dev
O $(pwd) captura o diretório atual. O resultado é que /app/src dentro do container aponta diretamente para ./src na máquina local — qualquer arquivo salvo no editor de texto aparece instantaneamente no container.
Em produção, bind mounts devem ser evitados — a imagem deve ser autossuficiente e não depender de arquivos do host.
Redes Docker: Comunicação entre Containers
Por padrão, cada container tem sua própria interface de rede isolada. Para que containers se comuniquem, precisam estar na mesma rede Docker.
O Docker cria automaticamente três redes ao ser instalado:
bridge — a rede padrão. Containers conectados a ela podem se comunicar via IP, mas não por nome.
host — remove o isolamento de rede. O container usa diretamente a interface de rede do host. Útil em casos específicos de performance, mas sacrifica isolamento.
none — sem rede. O container é completamente isolado.
Criando e Usando Redes Customizadas
Redes customizadas são superiores à rede bridge padrão por um motivo fundamental: elas oferecem resolução de nomes automática. Containers na mesma rede customizada podem se referenciar pelo nome do container, sem precisar conhecer IPs.
# Cria uma rede customizada
docker network create rede-app
# Lista redes existentes
docker network ls
# Inspeciona uma rede — mostra containers conectados e configurações
docker network inspect rede-app
# Remove uma rede
docker network rm rede-app
Subindo múltiplos serviços na mesma rede:
# Sobe o banco de dados na rede customizada
docker run -d \
--name postgres \
--network rede-app \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=senha123 \
-e POSTGRES_DB=producao \
-v dados-postgres:/var/lib/postgresql/data \
postgres:16
# Sobe o Redis na mesma rede
docker run -d \
--name redis \
--network rede-app \
redis:7-alpine
# Sobe a aplicação na mesma rede
docker run -d \
--name api \
--network rede-app \
-e DATABASE_URL=postgresql://app:senha123@postgres:5432/producao \
-e REDIS_URL=redis://redis:6379 \
-p 3000:3000 \
minha-app:1.0.0
Observa-se que a variável DATABASE_URL usa postgres como hostname — o nome do container — e não um endereço IP. O Docker resolve esse nome automaticamente dentro da rede rede-app. Da mesma forma, redis como hostname aponta para o container Redis.
Verificando Conectividade entre Containers
Para testar se um container consegue alcançar outro:
# Entra no container da API
docker exec -it api sh
# Testa conectividade com o banco
ping postgres
# Testa a porta do banco
nc -zv postgres 5432
# Testa o Redis
nc -zv redis 6379
exit
Se os containers estão na mesma rede customizada, todos esses testes devem ter sucesso.
Conectando um Container a Múltiplas Redes
Um container pode pertencer a mais de uma rede simultaneamente — útil para separar tráfego de frontend e backend:
# Cria redes separadas
docker network create rede-frontend
docker network create rede-backend
# O container de API pertence às duas redes
docker network connect rede-frontend api
docker network connect rede-backend api
# O banco pertence apenas ao backend
docker network connect rede-backend postgres
# O container de frontend pertence apenas ao frontend
docker run -d \
--name frontend \
--network rede-frontend \
-p 80:80 \
meu-frontend:1.0.0
Nessa configuração, o container frontend não consegue se comunicar diretamente com postgres — só com api. A API faz a ponte entre as duas redes, respeitando o princípio de menor exposição.
Um Ambiente Completo sem Docker Compose
Reunindo volumes e redes em um ambiente com três serviços:
# Cria infraestrutura
docker network create rede-producao
docker volume create dados-postgres
docker volume create dados-redis
# Banco de dados
docker run -d \
--name postgres \
--network rede-producao \
-v dados-postgres:/var/lib/postgresql/data \
-e POSTGRES_USER=app \
-e POSTGRES_PASSWORD=senha_segura \
-e POSTGRES_DB=minha_app \
postgres:16
# Cache
docker run -d \
--name redis \
--network rede-producao \
-v dados-redis:/data \
redis:7-alpine redis-server --appendonly yes
# Aplicação
docker run -d \
--name api \
--network rede-producao \
-e DATABASE_URL=postgresql://app:senha_segura@postgres:5432/minha_app \
-e REDIS_URL=redis://redis:6379 \
-e NODE_ENV=production \
-p 3000:3000 \
minha-app:1.0.0
# Verifica tudo rodando
docker ps
docker network inspect rede-producao
Esse conjunto de comandos funciona, mas já evidencia a necessidade do Docker Compose — gerenciar múltiplos containers manualmente se torna tedioso e propenso a erros rapidamente.
O Que Vem a Seguir
O próximo artigo apresenta o Docker Compose — a ferramenta que descreve em um único arquivo YAML toda a infraestrutura que foi construída com múltiplos comandos neste artigo. O ambiente inteiro sobe com um único docker compose up.
Referências para Aprofundamento
Documentação oficial
- Docker Volumes — docs.docker.com — Guia completo sobre volumes, incluindo drivers de volume para armazenamento em nuvem e NFS.
- Docker Networking — docs.docker.com — Documentação completa sobre redes Docker, cobrindo todos os drivers disponíveis e casos de uso.
Leitura técnica
- Networking in Compose — docs.docker.com — Explica como o Docker Compose gerencia redes automaticamente, complementando o que será visto no próximo artigo.
- Use Bind Mounts — docs.docker.com — Documentação específica sobre bind mounts com boas práticas e diferenças em relação a volumes gerenciados.
Prática
- Play with Docker — O ambiente permite criar múltiplos nós e praticar redes entre containers sem nenhuma instalação local.