17 min de leitura · Guia técnico
Vazamento de memória no Docker ocorre quando um container consome RAM de forma crescente e contínua sem liberá-la, mesmo sem aumento de carga. Para detectar o problema antes que ele derrube serviços em produção, siga este checklist:
- Monitore o consumo em tempo real com
docker stats - Inspecione os limites e o uso atual com
docker inspect - Analise os logs do container em busca de erros de alocação
- Acesse o container em execução e inspecione processos internos com
topoups aux - Configure limites de memória com a flag
--memorypara isolar o impacto - Integre métricas com Prometheus e cAdvisor para alertas automáticos
Pré-requisitos para detectar vazamento de memória no Docker
- Docker Engine instalado (versão 24.x ou superior recomendada) — veja o artigo Como Instalar e Configurar o Docker no VPS Linux para Hospedar Aplicações se precisar configurar o ambiente
- Acesso SSH ao servidor com permissões de root ou usuário no grupo
docker - Sistema operacional: Ubuntu 24.04 LTS, Debian 12 ou Rocky Linux 9
- Pelo menos um container em execução para análise
- Opcional: Prometheus, cAdvisor e Alertmanager para monitoramento contínuo
- Familiaridade básica com linha de comando Linux
Como detectar vazamento de memória no Docker com docker stats
O primeiro passo para identificar consumo anormal de memória em containers é usar o comando nativo docker stats, que exibe métricas em tempo real de todos os containers em execução. Diferente de ferramentas externas, ele não exige instalação adicional e fornece dados imediatos sobre uso de CPU, memória, rede e I/O.
Execute o comando abaixo no terminal do servidor:
docker stats
Você verá uma saída semelhante a esta, atualizada a cada segundo:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
a1b2c3d4e5f6 app-web 2.3% 412MiB / 512MiB 80.5% 1.2GB / 800MB 0B / 0B
f6e5d4c3b2a1 app-worker 0.1% 1.8GiB / 2GiB 90.0% 200MB / 50MB 0B / 0B
O campo MEM USAGE / LIMIT é o mais importante. Se o valor de uso crescer continuamente ao longo do tempo sem estabilizar — mesmo com tráfego constante ou baixo — isso é um sinal claro de vazamento de memória. Para monitorar um container específico e registrar os dados em arquivo para análise posterior, use:
docker stats --no-stream --format "{{.Name}}: {{.MemUsage}}" >> /var/log/docker-mem.log
Execute esse comando periodicamente via cron para criar um histórico de consumo. Se o valor de MemUsage crescer de forma linear ao longo de horas ou dias, o vazamento está confirmado.
Para filtrar apenas um container específico:
docker stats --no-stream nome-do-container
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
a1b2c3d4e5f6 nome-do-container 1.8% 380MiB / 512MiB 74.2% 500MB / 200MB 0B / 0B
Inspecionando limites e configurações de memória com docker inspect
Após identificar um container suspeito com docker stats, o próximo passo é verificar se limites de memória foram configurados corretamente. Containers sem limite definido podem consumir toda a RAM do host, causando instabilidade em outros serviços.
Execute o comando abaixo substituindo CONTAINER_ID pelo ID ou nome do container:
docker inspect CONTAINER_ID | grep -i memory
"Memory": 536870912,
"MemorySwap": 1073741824,
"MemoryReservation": 0,
"KernelMemory": 0,
O valor "Memory": 536870912 corresponde a 512 MB (536870912 bytes ÷ 1048576). Se o campo retornar 0, significa que nenhum limite foi definido — o container pode consumir toda a memória disponível no host. Isso é especialmente perigoso em servidores com múltiplos containers.
Para ver todas as configurações de recursos de uma vez:
docker inspect --format='{{json .HostConfig}}' CONTAINER_ID | python3 -m json.tool | grep -E "Memory|Cpu"
Verifique também o campo MemorySwap. Se ele for igual ao dobro do valor de Memory, o Docker está permitindo uso de swap além da RAM. Para entender melhor como o swap funciona no Linux e seu impacto em containers, consulte o artigo Entenda o que é Swap no Linux: como funciona e quando usar.
Analisando processos internos do container sem reiniciá-lo
Uma das vantagens do Docker é a possibilidade de inspecionar processos em execução dentro de um container sem interrompê-lo. Isso é fundamental para diagnosticar vazamentos de memória em ambientes de produção onde reiniciar o container causaria downtime.
Acesse o shell do container em execução:
docker exec -it CONTAINER_ID sh
Se a imagem usar bash:
docker exec -it CONTAINER_ID bash
Dentro do container, execute top para visualizar o consumo por processo:
top
PID USER TIME COMMAND
1 root 0:00 node server.js
42 root 0:12 node worker.js
87 root 0:00 sh
Observe a coluna RES (memória residente) e %MEM. Se um processo específico — como node server.js — estiver com %MEM crescendo continuamente, ele é o candidato principal ao vazamento.
Para uma visão mais detalhada sem interface interativa:
ps aux --sort=-%mem | head -20
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 1.2 35.4 1234567 720000 ? Ss 08:00 0:45 node server.js
root 42 0.3 12.1 456789 246000 ? S 08:00 0:12 node worker.js
O campo RSS (Resident Set Size) mostra a memória física real usada por cada processo em kilobytes. Valores crescentes ao longo do tempo confirmam o vazamento.
Para verificar o consumo de memória do cgroup do container diretamente no host (sem entrar no container):
cat /sys/fs/cgroup/memory/docker/CONTAINER_ID_COMPLETO/memory.usage_in_bytes
432013312
Esse valor em bytes representa o consumo atual do container no nível do kernel, sem overhead de ferramentas de monitoramento.
Analisando logs do container para identificar erros de alocação
Os logs do container frequentemente revelam erros de alocação de memória antes que o consumo se torne crítico. Mensagens como out of memory, cannot allocate memory ou heap allocation failed são indicadores diretos de problemas.
Visualize os logs do container:
docker logs CONTAINER_ID --tail 200
Para monitorar logs em tempo real enquanto observa o comportamento:
docker logs -f CONTAINER_ID 2>&1 | grep -iE "memory|heap|oom|allocation|killed"
Verifique também os logs do sistema no host para identificar ações do OOM Killer:
dmesg | grep -i "oom\|killed process\|out of memory"
[123456.789] Out of memory: Kill process 4521 (node) score 892 or sacrifice child
[123456.790] Killed process 4521 (node) total-vm:2048000kB, anon-rss:1024000kB, file-rss:0kB
Se você encontrar mensagens como essa, o OOM Killer já atuou — o container provavelmente reiniciou. Verifique o histórico de reinicializações:
docker inspect --format='{{.RestartCount}}' CONTAINER_ID
7
Um RestartCount alto combinado com logs de OOM Killer confirma que o container está sendo encerrado repetidamente por esgotamento de memória.
Para verificar o status de saída do último encerramento:
docker inspect --format='{{.State.ExitCode}} {{.State.OOMKilled}}' CONTAINER_ID
137 true
O código de saída 137 e o campo OOMKilled: true confirmam que o container foi encerrado pelo OOM Killer do kernel Linux.
Configurando limites de memória para isolar o impacto no host
Definir limites de memória é uma medida preventiva essencial para evitar que um container com vazamento comprometa todo o servidor. Sem limites, um único container pode consumir toda a RAM disponível, derrubando outros serviços.
Para criar um novo container com limite de memória:
docker run -d --name minha-app --memory=512m --memory-swap=512m minha-imagem
A flag --memory-swap=512m igual ao valor de --memory desabilita o uso de swap pelo container, forçando o OOM Killer a agir antes que o swap seja consumido.
Para atualizar o limite de um container já em execução sem reiniciá-lo:
docker update --memory=512m --memory-swap=512m CONTAINER_ID
CONTAINER_ID
No Docker Compose, defina os limites no arquivo docker-compose.yml:
version: "3.8"
services:
app:
image: minha-imagem
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
Atenção: a seção deploy.resources só é respeitada no modo Swarm. Para uso com docker-compose up padrão (sem Swarm), use:
version: "3.8"
services:
app:
image: minha-imagem
mem_limit: 512m
memswap_limit: 512m
Após aplicar os limites, confirme com:
docker inspect --format='{{.HostConfig.Memory}}' CONTAINER_ID
536870912
Monitoramento contínuo com Prometheus e cAdvisor
Para ambientes com múltiplos containers em produção, o monitoramento manual com docker stats não é escalável. A combinação de Prometheus com cAdvisor permite coletar métricas detalhadas de memória por container e configurar alertas automáticos.
Inicie o cAdvisor como container:
docker run -d \
--name cadvisor \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
gcr.io/cadvisor/cadvisor:latest
Acesse http://IP-DO-SERVIDOR:8080 para visualizar métricas em tempo real. O cAdvisor expõe automaticamente um endpoint Prometheus em http://IP-DO-SERVIDOR:8080/metrics.
Configure o Prometheus para coletar as métricas adicionando ao prometheus.yml:
scrape_configs:
- job_name: "cadvisor"
static_configs:
- targets: ["localhost:8080"]
scrape_interval: 15s
As métricas mais relevantes para detectar vazamento de memória são:
- container_memory_usage_bytes: uso total de memória do container
- container_memory_rss: memória residente (sem cache de página)
- container_memory_working_set_bytes: memória ativa em uso
- container_oom_events_total: número de eventos OOM registrados
Configure uma regra de alerta no Alertmanager para notificar quando o uso ultrapassar 80% do limite:
groups:
- name: docker-memory
rules:
- alert: ContainerMemoryHigh
expr: (container_memory_usage_bytes / container_spec_memory_limit_bytes) > 0.8
for: 5m
labels:
severity: warning
annotations:
summary: "Container {{ $labels.name }} com uso de memória acima de 80%"
Essa abordagem permite detectar tendências de crescimento de memória antes que o container seja encerrado pelo OOM Killer, dando tempo para investigar e corrigir o problema.
Problemas comuns e como resolver
Sintoma: docker stats mostra MEM USAGE crescendo continuamente
Causa: A aplicação dentro do container tem um vazamento de memória real — objetos são alocados mas nunca liberados pelo garbage collector ou pelo código da aplicação. Comum em aplicações Node.js, Java e Python com referências circulares ou listeners de eventos não removidos.
Solução: Acesse o container com docker exec -it CONTAINER_ID bash e use ferramentas de profiling específicas da linguagem. Para Node.js, habilite o flag --inspect e conecte o Chrome DevTools. Para Java, use jmap -heap PID dentro do container. Enquanto investiga, aplique um limite de memória com docker update --memory=512m CONTAINER_ID para proteger o host.
Sintoma: container reinicia repetidamente com ExitCode 137
Causa: O OOM Killer do kernel Linux encerrou o processo principal do container por esgotamento de memória. O código 137 (128 + sinal SIGKILL) confirma encerramento forçado. Isso ocorre quando não há limite definido e a RAM do host é esgotada, ou quando o limite definido é muito baixo para a carga real da aplicação.
Solução: Verifique o consumo histórico com docker stats --no-stream e ajuste o limite com docker update --memory=NOVO_VALOR CONTAINER_ID. Confirme com docker inspect --format='{{.State.OOMKilled}}' CONTAINER_ID. Se o valor retornar true, aumente o limite gradualmente até estabilizar.
Sintoma: host fica sem memória mesmo com containers aparentemente normais
Causa: Containers sem limite de memória definido (Memory: 0 no docker inspect) podem consumir toda a RAM disponível. O problema é agravado quando múltiplos containers competem pelos mesmos recursos sem restrições.
Solução: Execute docker inspect --format='{{.Name}}: {{.HostConfig.Memory}}' $(docker ps -q) para listar todos os containers e seus limites. Qualquer container com valor 0 está sem restrição. Aplique limites imediatamente com docker update e revise o docker-compose.yml para incluir mem_limit em todos os serviços.
Sintoma: cAdvisor não exibe métricas de memória para alguns containers
Causa: O cAdvisor precisa de acesso ao sistema de arquivos do host e aos cgroups do Docker. Se o container do cAdvisor foi iniciado sem os volumes corretos ou sem permissões adequadas, algumas métricas ficam indisponíveis.
Solução: Verifique se o container do cAdvisor foi iniciado com todos os volumes obrigatórios (/sys, /var/lib/docker, /var/run). Em sistemas com cgroup v2 (Ubuntu 22.04+, Debian 12), adicione o volume --volume=/sys/fs/cgroup:/sys/fs/cgroup:ro ao comando de inicialização do cAdvisor.
Perguntas frequentes sobre vazamento de memória no Docker
Como saber se um container Docker está com vazamento de memória?
Execute docker stats para monitorar o consumo em tempo real. Se o campo MEM USAGE de um container crescer continuamente sem estabilizar, mesmo sem aumento de tráfego, isso indica vazamento. Confirme com docker inspect e análise dos logs do processo interno. Um crescimento linear ao longo de horas, sem picos relacionados a carga, é o sinal mais confiável de vazamento real.
O que acontece quando um container Docker esgota a memória disponível?
O kernel Linux aciona o OOM Killer (Out-Of-Memory Killer), que encerra o processo com maior consumo dentro do container. O container pode reiniciar automaticamente se houver política de restart configurada, mas a aplicação perde estado e conexões ativas são interrompidas. Você pode confirmar que o OOM Killer atuou verificando docker inspect --format='{{.State.OOMKilled}}' CONTAINER_ID — se retornar true, o encerramento foi forçado por falta de memória.
Como limitar a memória de um container Docker para evitar impacto no host?
Use a flag --memory ao criar o container, por exemplo: docker run --memory=512m minha-imagem. Você também pode definir mem_limit no Docker Compose. Para containers já em execução, use docker update --memory=512m CONTAINER_ID sem precisar reiniciá-lo. Isso impede que um único container consuma toda a RAM do servidor e afete outros serviços em execução no mesmo host.
É possível detectar vazamento de memória em container sem reiniciá-lo?
Sim. Use docker exec -it <id> sh para acessar o container em execução e inspecionar processos com top ou ps aux. Ferramentas como Valgrind podem ser usadas dentro do container se instaladas na imagem, sem necessidade de reinicialização. Você também pode ler diretamente os dados do cgroup em /sys/fs/cgroup/memory/docker/CONTAINER_ID/memory.usage_in_bytes no host para obter o consumo atual sem interagir com o container.
Como configurar alertas automáticos para consumo de memória em containers Docker?
Integre o Docker com Prometheus e cAdvisor para coletar métricas de memória por container. Configure alertas no Alertmanager para disparar notificações quando o uso ultrapassar um limiar definido, como 80% do limite configurado para o container. A métrica container_memory_usage_bytes dividida por container_spec_memory_limit_bytes fornece o percentual de uso, que pode ser usado diretamente em regras de alerta do Prometheus.
Conclusão
- Monitore proativamente: use
docker statscom cron para criar histórico de consumo e identificar tendências de crescimento antes que o OOM Killer atue. - Defina limites sempre: todo container em produção deve ter
--memoryconfigurado — containers sem limite podem derrubar o host inteiro em caso de vazamento. - Automatize alertas: implante cAdvisor com Prometheus e Alertmanager para receber notificações quando o consumo ultrapassar 80% do limite, permitindo investigação antes do impacto nos usuários.
Leia também
- Checklist: como configurar Traefik como proxy reverso para Docker
- Guia Docker + Portainer no mesmo servidor: conflitos e soluções
- Comparativo: Portainer vs CLI Docker para gerenciar containers
Precisa de ajuda com Docker e infraestrutura de containers?
Gerenciar containers em produção exige um servidor com recursos adequados e suporte técnico disponível. Na AviraHost, os planos de VPS Linux oferecem ambiente otimizado para Docker, com acesso root completo e suporte especializado para configuração de limites de memória e monitoramento.