Docker Compose em Produção: Guia de Redes e Volumes

Levar um ambiente de desenvolvimento local para o docker compose em produção exige uma mudança drástica de mentalidade. O comando docker-compose up que funciona perfeitamente na sua máquina não possui, por padrão, o isolamento, a segurança ou a resiliência exigidos por um servidor exposto à internet.

Neste artigo, vamos detalhar as melhores práticas para arquitetar a rede (networking) e a persistência de dados (volumes) de forma profissional e segura.

1. Redes no Docker: Isolamento é a Primeira Linha de Defesa

O maior erro de deployments iniciantes é deixar todos os containers na rede bridge padrão. Ao arquitetar seu docker compose em produção, a regra de ouro é aplicar o princípio do menor privilégio: serviços não devem se enxergar a menos que precisem se comunicar.

Separe suas Redes: Frontend e Backend

A topologia mais segura divide a sua stack em pelo menos duas redes customizadas:

  • Frontend (Pública/Proxy): Onde fica o seu Reverse Proxy (Nginx, Traefik, LiteSpeed). Esta rede tem contato com o mundo externo, recebendo as requisições HTTP/HTTPS.
  • Backend (Privada/Dados): Onde residem o banco de dados (MariaDB, PostgreSQL), sistemas de cache (Redis) e a aplicação em si. A internet nunca toca nesta rede.

O proxy reverso é o único serviço configurado para participar de ambas as redes, atuando como um filtro rigoroso.

A Armadilha das Portas: expose vs. ports

Entender a diferença entre essas duas diretivas evita o vazamento acidental do seu banco de dados para a internet:

  • ports (Exposição Externa): Faz o bind de uma porta do container diretamente com uma interface do servidor host (ex: 80:80). Use apenas no seu proxy reverso.
  • expose (Exposição Interna): Declara que o container escuta em uma porta, mas ela só fica acessível para outros containers na mesma rede interna. Esta é a escolha correta para bancos de dados.

2. Persistência de Dados: Evitando a Perda de Estado

Containers são efêmeros. Se um container for recriado, os dados gravados em sua camada temporária desaparecem. A escolha correta do tipo de montagem no docker compose em produção evita a perda catastrófica de informações.

Named Volumes vs. Bind Mounts

Saber quando usar cada abordagem garante performance e estabilidade:

  • Named Volumes (Volumes Nomeados): Gerenciados pelo próprio Docker (armazenados em /var/lib/docker/volumes/). São a escolha oficial para dados reais, como o diretório /var/lib/mysql. Eles oferecem melhor performance de I/O e evitam problemas complexos de permissão (UID/GID) entre o host e o container.
  • Bind Mounts (Mapeamento de Host): Apontam para um caminho exato no seu servidor (ex: /etc/nginx/conf.d/). Devem ser usados exclusivamente para arquivos estáticos, como injetar configurações ou certificados SSL.

Segurança com Montagens Somente Leitura (Read-Only)

Se o seu container precisa apenas ler um arquivo de configuração via Bind Mount, bloqueie o acesso de escrita adicionando :ro (read-only) ao final do mapeamento. Isso impede que uma vulnerabilidade na aplicação altere arquivos críticos do servidor.

3. Exemplo Prático: docker-compose.yml Seguro

Abaixo, um modelo base aplicando todas as regras discutidas:

services:
  # PROXY REVERSO (Acessível externamente)
  proxy:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # Bind mount em Read-Only para configurações
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
    networks:
      - rede_frontend 

  # APLICAÇÃO (Isolada da internet direta)
  app:
    image: minha-app:latest
    restart: unless-stopped
    expose:
      - "9000" # Comunica apenas com o proxy na rede interna
    networks:
      - rede_frontend
      - rede_backend 

  # BANCO DE DADOS (Máximo isolamento)
  db:
    image: mariadb:10.11
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
      MYSQL_DATABASE: app_db
    volumes:
      # Named volume para os dados (performance e segurança)
      - db_data:/var/lib/mysql
    # SEM DIRETIVA "ports" AQUI
    networks:
      - rede_backend

# DEFINIÇÃO DAS REDES
networks:
  rede_frontend:
    driver: bridge
  rede_backend:
    driver: bridge
    internal: true # Impede roteamento externo para esta rede

# DEFINIÇÃO DOS VOLUMES
volumes:
  db_data:

Conclusão

Rodar o docker compose em produção com segurança não precisa ser complexo, desde que você abandone os atalhos do ambiente de desenvolvimento. Segmentar suas redes, proteger as portas do banco de dados e escolher o tipo certo de volume formam a base de uma infraestrutura resiliente. Lembre-se: persistência de volume não é backup. Implemente sempre rotinas externas de dump e envio para storage remoto.

FAQ

Qual a diferença entre expose e ports no Docker Compose?

A diretiva ports mapeia a porta do container diretamente para o servidor host (expondo para a internet, útil para Proxy Reverso). Já o expose apenas libera a porta para a comunicação interna entre os containers da mesma rede, sendo a opção segura para bancos de dados.

Por que não devo usar a rede padrão (bridge) do Docker em produção?

A rede bridge padrão não oferece isolamento de segurança adequado e depende de links de containers legados em vez de resolução de nomes DNS interna moderna. Criar redes customizadas (como frontend e backend) garante que serviços expostos não tenham acesso direto a serviços críticos.

Devo usar Named Volumes ou Bind Mounts para o banco de dados?

Para bancos de dados, utilize sempre Named Volumes (Volumes Nomeados). Eles são gerenciados de forma eficiente pelo próprio Docker, evitam problemas complexos de permissão de pastas do host e oferecem desempenho superior de I/O em comparação aos Bind Mounts.

Como proteger arquivos de configuração injetados em containers?

Ao utilizar Bind Mounts para injetar configurações (como um nginx.conf), adicione a flag :ro (read-only) ao final do mapeamento no docker-compose.yml. Isso impede que o container tenha permissão de escrita sobre o arquivo original no servidor.

Veja Mais:

Docker para SysAdmins: Serviços Isolados sem Complicação

Como instalar Portainer para gerenciamento Docker com Nginx Proxy Manager no Ubuntu

Otimização de Código vs Servidor: Decisão Prática para Alta Performance

O que ninguém te conta sobre gerenciar servidores em produção

How to Install Portainer for Docker Management with Nginx Proxy Manager on Ubuntu

Mailcow Docker: Vale a Pena Rodar E-mail Próprio? Análise Completa