13 min de leitura · Guia técnico
Otimizar Docker Compose no Debian 12 significa ajustar rede, volumes e limites de RAM para que múltiplos containers convivam no mesmo host sem desperdiçar recursos nem causar gargalos de I/O. Para alcançar performance real em produção, siga estes passos:
- Instale o plugin oficial
docker-compose-plugin(V2) no Debian 12. - Defina redes bridge customizadas para isolar grupos de serviços.
- Substitua bind mounts por named volumes em produção.
- Aplique
mem_limitemem_reservationem cada serviço. - Configure rotação de logs e
healthcheckspara evitar containers zumbis. - Valide com
docker statse ajuste conforme o consumo real.
Pré-requisitos para otimizar Docker Compose no Debian 12
- VPS ou servidor dedicado com Debian 12 (Bookworm) atualizado via
apt update && apt upgrade. - Acesso root ou usuário no grupo
docker. - Docker Engine 24+ e plugin
docker-compose-plugin(V2) instalados. - Mínimo de 2 GB de RAM e 20 GB de disco para ambientes pequenos; 4 GB+ para múltiplos serviços.
- Conhecimento básico de YAML e comandos como
docker ps,docker logs. - Porta 22 (SSH) liberada e firewall UFW ou nftables configurado conforme o tráfego dos serviços.
Instalação correta do Docker Compose V2 no Debian 12
A primeira otimização começa pela versão certa. O binário docker-compose em Python foi descontinuado em 2023, e usar a V2 (Go) reduz tempo de parsing do YAML e consumo de memória do CLI. No Debian 12, evite o pacote docker.io dos repositórios oficiais, que costuma ficar desatualizado, e use o repositório upstream da Docker.
sudo apt remove docker docker-engine docker.io containerd runc
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian bookworm stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verifique a instalação:
docker compose version
Output esperado:
Docker Compose version v2.27.x
A partir daqui, todos os comandos usam docker compose (sem hífen). Evite scripts antigos com docker-compose, pois forçam fallback para a V1 caso ainda esteja instalada.
Otimização de rede no Docker Compose: bridges, isolamento e DNS
A camada de rede impacta diretamente a latência entre containers. Por padrão, o Compose cria uma bridge automática chamada nomedoprojeto_default, mas em ambientes com múltiplos serviços (proxy reverso, banco, aplicação, cache) é melhor segmentar redes para reduzir broadcast e melhorar segurança.
Redes customizadas para otimizar Docker Compose no Debian 12
Defina redes nomeadas no arquivo docker-compose.yml. Containers só enxergam serviços na mesma rede, então o banco fica isolado da internet enquanto a aplicação se conecta a ambos.
services:
nginx:
image: nginx:1.26-alpine
networks:
- frontend
ports:
- "80:80"
app:
image: minha-app:latest
networks:
- frontend
- backend
db:
image: mariadb:11.4
networks:
- backend
environment:
MARIADB_ROOT_PASSWORD: senha_forte
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
O atributo internal: true impede que a rede backend tenha rota para a internet, blindando o MariaDB contra exposição acidental. Para inspecionar a rede em uso:
docker network ls
docker network inspect projeto_backend
MTU e DNS interno
Em VPS com tunelamento (WireGuard, OpenVPN), o MTU padrão de 1500 pode causar fragmentação. Ajuste em /etc/docker/daemon.json:
{
"mtu": 1450,
"dns": ["1.1.1.1", "8.8.8.8"]
}
Reinicie o serviço com sudo systemctl restart docker. O DNS configurado é herdado por todos os containers, evitando timeouts em resoluções externas — problema comum quando o resolver do host está sobrecarregado.
Volumes em Docker Compose: bind mount vs named volume
Volumes mal escolhidos são uma das causas mais frequentes de lentidão e corrupção de dados. Em produção, named volumes superam bind mounts em performance de I/O e gerenciamento de permissões, especialmente em filesystems ext4 do Debian 12.
Quando usar named volumes
Use volumes nomeados para dados persistentes do banco, uploads de usuários e caches que sobrevivem a recriações. O Docker armazena tudo em /var/lib/docker/volumes com permissões controladas, e o backup é direto:
services:
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: senha_forte
volumes:
pgdata:
driver: local
Para fazer backup sem parar o container:
docker run --rm -v projeto_pgdata:/data -v $(pwd):/backup alpine tar czf /backup/pgdata-$(date +%F).tar.gz -C /data .
Quando bind mount ainda faz sentido
Bind mounts são justificáveis em desenvolvimento (hot reload de código) e quando você precisa que arquivos sejam editáveis pelo host, como certificados Let's Encrypt compartilhados com o Nginx. Nesse caso, fixe UID/GID para evitar conflitos:
services:
nginx:
image: nginx:1.26-alpine
volumes:
- ./certs:/etc/nginx/certs:ro
- ./conf.d:/etc/nginx/conf.d:ro
user: "101:101"
O sufixo :ro (read-only) reduz risco de gravação acidental e melhora cache de leitura. Para diretórios voláteis (sessões PHP, cache temporário), prefira tmpfs, que vive em RAM e não toca o disco:
services:
app:
image: php:8.3-fpm-alpine
tmpfs:
- /tmp:size=128m
- /var/cache:size=64m
Se você gerencia múltiplos sites com volumes compartilhados, vale conferir o artigo Dicas de Otimização de Servidores Linux para ajustes de kernel que complementam essa configuração.
Limitar RAM por container: evitando OOM e swap excessivo
Sem limites, um único container com vazamento de memória derruba o host inteiro. O kernel Linux dispara o OOM killer e mata processos arbitrariamente — incluindo o próprio Docker daemon em casos extremos. A política correta é definir tetos por serviço.
Sintaxe moderna com deploy.resources
services:
app:
image: node:20-alpine
deploy:
resources:
limits:
cpus: '1.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
restart: unless-stopped
Atenção: a chave deploy só é honrada por padrão no Docker Swarm. Para Compose standalone, use a sintaxe legada mem_limit e mem_reservation, que funcionam diretamente:
services:
app:
image: node:20-alpine
mem_limit: 512m
mem_reservation: 128m
cpus: 1.5
restart: unless-stopped
Validação com docker stats
Após subir o stack, monitore o consumo real:
docker stats --no-stream
Output esperado:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM %
a3f1b2c4d5e6 projeto_app_1 2.34% 142.3MiB / 512MiB 27.79%
b7g8h9i0j1k2 projeto_db_1 0.87% 89.5MiB / 256MiB 34.96%
Se um container está consistentemente acima de 80% do limite, aumente o teto ou investigue vazamento. Se está abaixo de 30%, reduza o limite para liberar RAM para outros serviços.
Rotação de logs e healthchecks
Logs sem rotação ocupam GBs em poucos dias. Configure no daemon.json ou por serviço:
services:
app:
image: node:20-alpine
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
Containers com healthcheck falho podem ser reiniciados automaticamente combinando com restart: unless-stopped, evitando que serviços travados consumam RAM sem responder requisições.
Problemas comuns e como resolver
Sintoma: container reinicia em loop após aplicar mem_limit
Causa: o limite definido é menor que o consumo mínimo do processo, e o OOM killer mata o container assim que ele inicia.
Solução: remova temporariamente o mem_limit, rode docker stats por alguns minutos sob carga real e defina o teto em pelo menos 1,5x o pico observado. Para Java/Node.js, considere também ajustar flags como -Xmx ou --max-old-space-size.
Sintoma: lentidão extrema em volumes com muitos arquivos pequenos
Causa: bind mounts em diretórios com milhares de inodes (node_modules, vendor) sofrem overhead do overlay filesystem.
Solução: mova esses diretórios para named volumes ou use delegated/cached em ambientes de desenvolvimento. Em produção, faça npm install ou composer install dentro do Dockerfile para que os arquivos vivam na imagem, não em volume.
Sintoma: containers não conseguem se comunicar entre si
Causa: serviços em redes diferentes ou rede internal: true sem rota externa quando precisa baixar pacotes.
Solução: verifique com docker network inspect nome_rede se ambos os containers aparecem na mesma rede. Se um serviço precisa acessar a internet apenas durante build, use --network host no estágio de build do Dockerfile e mantenha a rede interna em runtime.
Sintoma: docker compose up demora minutos no Debian 12
Causa: resolução DNS lenta ao baixar imagens ou configuração de IPv6 sem rota.
Solução: desabilite IPv6 no daemon ou configure DNS estático em /etc/docker/daemon.json. Outra causa comum é o systemd-resolved competindo com o resolver do Docker — configure "dns": ["1.1.1.1"] explicitamente.
Perguntas frequentes sobre otimizar Docker Compose no Debian 12
Qual a diferença entre docker-compose e docker compose no Debian 12?
O comando docker-compose (com hífen) é a versão V1 escrita em Python, descontinuada em 2023. Já docker compose (sem hífen) é a V2, escrita em Go e instalada como plugin oficial do Docker. No Debian 12, instale via pacote docker-compose-plugin para ter a versão V2, que é mais rápida e compatível com a especificação Compose atual.
Como definir limite de memória RAM por container no Docker Compose?
Use as diretivas deploy.resources.limits.memory e deploy.resources.reservations.memory dentro do serviço. Por exemplo, mem_limit: 512m define o teto de RAM, e quando o container ultrapassa, o kernel aciona o OOM killer. Sempre teste com docker stats para confirmar o consumo real antes de definir limites apertados.
É seguro usar volumes bind mount em produção com Docker Compose?
Bind mounts são úteis para desenvolvimento, mas em produção prefira named volumes gerenciados pelo Docker. Volumes nomeados oferecem melhor performance no I/O, isolamento de permissões e facilidade de backup com docker volume. Bind mounts dependem do filesystem do host e podem causar conflitos de UID/GID entre container e host.
Como reduzir o uso de RAM do Docker Compose com múltiplos serviços?
Aplique mem_limit em cada serviço, use imagens slim ou alpine como base, ative healthchecks para reiniciar containers travados e configure restart: unless-stopped para evitar loops. Combine com tmpfs para diretórios voláteis e desabilite logs verbosos com logging.options.max-size para evitar consumo de disco e memória de cache.
Como aplicar mudanças no docker-compose.yml sem derrubar todos os serviços?
Execute docker compose up -d --no-deps --build nome_do_servico para recriar apenas o container alterado, mantendo os demais em execução. O Docker Compose detecta as diferenças e substitui o container com downtime mínimo. Para mudanças de rede ou volume, será necessário um docker compose down seguido de up -d.
Conclusão
- Use sempre Docker Compose V2 via
docker-compose-plugine segmente serviços em redes bridge nomeadas cominternal: truepara o backend. - Padronize
named volumesem produção, reserve bind mounts para configuração read-only e usetmpfspara dados voláteis que dispensam disco. - Defina
mem_limit, healthchecks e rotação de logs em todos os serviços, validando o consumo real comdocker statsantes de apertar tetos.
Leia também
- Otimizar Docker Compose: portas só para serviços internos
- Otimizar Docker Compose e Nginx no mesmo servidor AlmaLinux 9
- Comparativo: Portainer vs CLI Docker para gerenciar containers
Precisa de ajuda com Docker Compose no Debian 12?
Containers exigem CPU dedicada, RAM previsível e I/O consistente — recursos que hospedagem compartilhada não entrega. Um VPS bem dimensionado garante o ambiente correto para rodar stacks Compose em produção sem surpresas.