VPS diz que o disco está cheio, mas ainda tem espaço livre? Como investigar inodes e Docker

Ilustração de servidor VPS com ícone de disco cheio ao lado do logo do Docker

Fala aí, beleza? Sabe aquela cena em que o container cai com No space left on device, tu abre o terminal e o disco ainda tem espaço sobrando? 🙂

Esse erro tem mais de uma origem: inodes esgotados, dados do Docker gravados numa partição diferente da que você está olhando, ou log de container crescendo sem rotação

A ideia aqui é diagnosticar ANTES de apagar qualquer coisa

Limpeza no modo "roda tudo com -a e -f e vê no que dá" pode levar junto o volume do seu banco de dados, e aí não tem Ctrl+Z que salve

Inodes esgotados: o df mostra espaço, mas não dá para criar arquivos

Se o df mostra espaço livre e mesmo assim a gravação falha, a primeira suspeita é: acabaram os inodes

Que inode? É a estrutura que guarda as informações de um arquivo, como dono, permissões, datas e localização no sistema de arquivos, segundo o manual do GNU coreutils

Ou seja, cada arquivo consome um inode, independente do tamanho dele

Por isso uma montanha de arquivos pequenos (cache, sessão, arquivos temporários e por aí vai) pode esgotar os inodes sem ocupar quase nada de espaço

Como conferir:

  1. Veja o uso de blocos, que é o que o df mostra por padrão:
df
  1. Agora veja o uso de inodes da mesma máquina:
df -i

A forma longa também funciona:

df --inodes
  1. Compare as duas saídas partição por partição e procure a que está com a coluna IUse% alta

Se a partição tem espaço livre em blocos e IUse% lá em cima, achou o culpado: o problema é quantidade de arquivos, não tamanho

Erro comum: olhar só o uso de blocos, ver espaço sobrando e concluir que o disco está ok, sem checar os inodes

Isso costuma gerar investigação na direção errada, porque o sintoma (gravação falhando) não bate com o que o df padrão mostra

Como prevenir: coloque o df -i na sua checagem de rotina, junto com o df normal

Docker ocupando o disco: como ler o docker system df

Se a partição onde o Docker guarda dados está cheia, a causa costuma ser acúmulo: imagens, containers, volumes e cache de build que foram ficando

E isso é esperado, porque o Docker é conservador na limpeza: nada sem uso é removido se você não pedir explicitamente

O ponto de partida é este comando, que mostra quanto espaço o daemon está usando:

docker system df

A saída traz as colunas TYPE, TOTAL, ACTIVE, SIZE e RECLAIMABLE, separadas em Images, Containers e Local Volumes

Vale um aviso antes de colocar isso numa rotina automatizada: a documentação do Docker alerta que esse comando pode consumir bastante recursos, porque ele percorre o sistema de arquivos de todas as imagens, containers e volumes. Em sistemas com muitos objetos ou onde a performance é crítica, vale rodar com atenção, não em todo intervalo de 1 minuto num monitoramento, por exemplo

Pra ver o detalhe item por item:

docker system df -v

E se tu quer jogar isso num script de monitoramento, tem a saída em JSON:

docker system df --format json

E o que significa a coluna RECLAIMABLE?

É o espaço que o Docker aponta como recuperável, mas a referência oficial não detalha exatamente qual critério ele usa pra chegar nesse número

Por isso, trate essa coluna como PISTA pra investigar, não como ordem de apagar

Um valor alto em RECLAIMABLE pode incluir, por exemplo, o volume do banco de dados de um container que você parou ontem pra manutenção 😛

Onde o Docker guarda os dados?

No Linux, o padrão é /var/lib/docker, e esse diretório pode ser trocado pela opção data-root, como flag (--data-root) ou no arquivo de configuração do daemon (veja a documentação do Docker Engine)

Só que tem um detalhe novo: no Docker Engine 29.0 ou mais recente, em instalação nova, o padrão é o containerd image store

Com ele, o conteúdo das imagens e os snapshots dos containers vão pra /var/lib/containerd, e o resto (volumes, configs) continua em /var/lib/docker

A opção data-root NÃO move esse conteúdo de /var/lib/containerd: pra trocar esse caminho é preciso configurar o root em /etc/containerd/config.toml

Em instalações que foram atualizadas (upgrade) e continuam usando overlay2, tudo fica em /var/lib/docker, sem esse caminho separado

Por isso o df pode apontar uma partição que parece a "errada": as imagens estão num caminho e os volumes em outro, dependendo de como o Engine foi instalado

Erro comum: procurar só em /var/lib/docker numa instalação nova do Engine 29+ e não entender pra onde foi o espaço

Imagens e cache de build x volumes: o que dá para limpar com segurança

A regra é simples: imagem e cache de build dá pra baixar ou gerar de novo, volume guarda dado persistente

Então os dois grupos merecem tratamento diferente, beleza?

Limpando imagens:

Por padrão, o docker image prune só apaga imagens dangling (sem tag e não referenciadas por nenhum container):

docker image prune

Com -a, ele apaga também todas as imagens que nenhum container usa

Dá pra limitar por idade com o filtro until:

docker image prune -a --filter "until=24h"

O prompt de confirmação não mostra a lista do que vai ser removido, então, se você usar -f, nem tem a chance de revisar antes

Limpando o cache de build:

O docker builder prune apaga o cache de build, e com -a remove todo o cache sem uso, não só o dangling

Ele também aceita --filter (como until=24h) e --keep-storage, que define quanto espaço de cache manter:

docker builder prune --filter "until=24h"

E o docker system prune?

Por padrão, ele remove containers parados, redes sem uso, imagens dangling e cache de build sem uso de uma vez

Imagens com tag que não estão em uso só saem se você usar -a (ou --all)

Com --volumes, ele remove APENAS volumes anônimos sem uso: volumes nomeados não entram nessa flag, mesmo que estejam sem container algum usando eles

Volumes: liste antes de qualquer coisa

Volumes nunca são removidos automaticamente justamente porque isso poderia destruir dados (guia oficial de pruning)

Primeiro, veja quais volumes nenhum container referencia:

docker volume ls -f dangling=true

O docker volume ls também aceita filtros por driver, label e name, o que ajuda a separar o que é de cada projeto

Depois, entenda o comportamento do prune de volumes:

  • docker volume prune por padrão só apaga volumes anônimos sem uso
  • docker volume prune -a (ou --all) inclui também os volumes NOMEADOS sem container, e aí pode ir embora o banco de dados do projeto que estava parado

Erro comum: confundir docker system prune --volumes (que só afeta volumes anônimos sem uso) com docker volume prune -a, que inclui os volumes nomeados sem container: é esse segundo comando que pode levar embora um banco de dados que você deixou parado de propósito

E se liga: a flag -f pula a confirmação em ambos, então você nem tem a chance de ler a lista antes de apagar

Como prevenir: antes de qualquer limpeza que envolva docker volume prune -a, faça um snapshot manual da VPS

Na VPS da Hostinger, por exemplo, você tem backups semanais automáticos e gratuitos, além de snapshots manuais pra restaurar o servidor (este artigo contém links de afiliado da Hostinger). Vale notar que, na Hostinger, só um snapshot manual fica guardado por vez: um novo substitui o anterior, e o snapshot também é apagado se você reinstalar o sistema operacional ou restaurar um backup. Por isso, trate-o como uma rede de segurança rápida antes de uma limpeza mais arriscada, não como arquivo de longo prazo

Um snapshot recente antes do prune reduz bastante o risco desse tipo de operação, mas não substitui conferir a lista de volumes antes de rodar o comando

Logs de container sem rotação enchendo o disco

Se o disco continua crescendo sem nenhuma imagem ou volume novo, desconfie dos logs

O driver de log padrão do Docker é o json-file, e ele vem SEM rotação: o log cresce enquanto o container estiver rodando

A rotação só acontece se você configurar max-size e max-file no daemon.json, como neste exemplo didático:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Fora do Kubernetes, a documentação de logging do Docker recomenda o driver local, que já faz rotação por padrão

Vale avaliar antes de ficar ajustando o json-file

Erro comum: escrever 3 em vez de "3"

Os valores de log-opts precisam ir entre aspas, como strings, mesmo sendo números

E um detalhe que pega muita gente: mudar o driver ou as opções de log no daemon.json só vale depois de reiniciar o Docker (sudo systemctl restart docker) e só pra containers criados depois disso. Os que já existem mantêm a config antiga e precisam ser recriados

Como prevenir: defina a política de log ANTES de subir os containers, e não depois que o disco já encheu

Quando o problema é falta de espaço de verdade

Depois de todo esse diagnóstico, pode ser que a resposta seja chata: o espaço acabou mesmo

Se os dados legítimos (volumes ativos, imagens em uso pelos containers) não cabem no disco, apagar mais não resolve, só adia o problema ou destrói o que importa

Aí o caminho é dimensionar o disco pro tamanho real do projeto

Pra quem roda Docker em VPS, a recomendação da Hora de Codar é a Hostinger, pelos recursos que casam com essa tarefa:

  • Armazenamento SSD NVMe e processadores AMD EPYC nos planos de VPS
  • Acesso root, que é o que você precisa pra rodar df -i e mexer no daemon.json
  • Data center no Brasil disponível na criação da VPS
  • Uma página de hospedagem voltada especificamente pra Docker
  • Backups semanais automáticos gratuitos e snapshots manuais, que ajudam nas limpezas arriscadas

O disco NVMe por plano KVM fica assim:

Plano Disco NVMe
KVM 1 50 GB
KVM 2 100 GB
KVM 4 200 GB
KVM 8 400 GB

Use o docker system df -v pra somar o que é realmente persistente e escolher com folga entre os planos de VPS da Hostinger, em vez de chutar

Isso é recomendação editorial, não benchmark: a escolha certa depende do tamanho dos seus volumes e imagens

Vídeo de apoio

Se a sua VPS também roda outras coisas além dos containers da aplicação, como agentes de IA, tem um vídeo no canal sobre o Hermes Desktop 😀

Conteúdo complementar do Hora de Codar para conhecer o canal; não é uma demonstração específica desta notícia ou versão.

Próximo passo: transformar o diagnóstico em rotina

O erro de disco cheio quase nunca avisa antes, então o melhor momento pra agir é agora, com o servidor saudável

Uma rotina simples e verificável:

  1. Agende a checagem de df -i e docker system df (a saída em --format json facilita pra script e alerta), com atenção ao custo do system df em sistemas com muitos objetos
  2. Fixe a política de log no daemon.json ou adote o driver local antes de subir novos containers
  3. Faça um snapshot da VPS antes de qualquer docker volume prune -a, sempre, lembrando que na Hostinger só fica guardado um snapshot manual por vez, e o próximo substitui o anterior, então ele não serve como backup de longo prazo

Essa mesma lógica de medir antes de mexer vale pra memória também, como no caso de NestJS consumindo muita memória numa VPS

E deixa a documentação oficial do Docker Engine nos favoritos: é ela que diz o que cada prune apaga de fato

Até o próximo post! 🙂

Perguntas frequentes

Preciso parar os containers para rodar docker system df?

Não há essa exigência documentada: o docker system df é um comando de leitura, não remove nada. A documentação do Docker alerta, porém, que ele pode consumir bastante recursos, porque percorre o sistema de arquivos de imagens, containers e volumes. Em sistemas com muitos objetos ou onde a performance é crítica, vale rodar com atenção, principalmente se for automatizar essa checagem numa rotina.


Quer aprender mais sobre inteligência artificial e programação na prática? Conheça o canal Hora de Codar no YouTube e acompanhe os próximos vídeos.

Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Claude Code

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 48min

Blog | Mais populares