Disco cheio por journals do systemd: diagnóstico e limpeza

O alerta de disco cheio dispara, o df mostra /var quase cheio e o du dos directórios óbvios não justifica nada. O suspeito, em servidores com systemd, é o journal: /var/log/journal/ acumula os logs de todos os serviços, o default do journald autoriza-o a crescer até 10% do sistema de ficheiros (com um tecto de 4GB) e o default só encolhe ficheiros arquivados quando escreve logs novos. Numa PME com uma aplicação ruidosa, o journal chega aos gigabytes e empurra /var contra o limite. Este guia mostra a sequência completa: medir, limpar, fixar um tecto e travar o serviço que regista demasiado.

Nota

o diagnóstico que aqui interessa é o espaço em disco. Para ler e filtrar os logs por unidade, prioridade e padrão, o caminho é o artigo do journalctl, que cobre a análise de conteúdo.

O sintoma: disco cheio sem ficheiros grandes

Comece por confirmar o sistema de ficheiros afectado:


df -h /var

Saída típica num servidor de 40G com o disco quase cheio:


Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        40G   37G  1.2G  97% /

O passo seguinte mede os directórios de primeiro nível de /var (o -x impede o du de descer para outros sistemas de ficheiros montados por dentro):


du -xh --max-depth=1 /var | sort -rh | head -6

31G    /var
18G    /var/lib
8.6G   /var/www
2.9G   /var/log
1.5G   /var/cache
9.1M   /var/spool

Se /var/lib pesa 18G — dado real, nada que se toque. Os 8,6G de /var/www também não: são ficheiros do site. O /var/log é o único bloco que se liberta de imediato e sem risco — e aos 97% de ocupação, os 2,6G de journal compram o respiro. Desça um nível: /var/log, desça um nível:


du -xh --max-depth=1 /var/log | sort -rh | head -6

2.9G   /var/log
2.6G   /var/log/journal
110M   /var/log/nginx
18M    /var/log/dnf.log
8.9M   /var/log/sa

Porquê

o journal cresce: o journald guarda os logs com rotação automática e, por default, autoriza-se a usar até 10% do sistema de ficheiros (tecto de 4GB), deixando 15% livre para o resto do disco. Só encolhe ficheiros arquivados quando escreve logs novos, pelo que o histórico cresce até ao tecto e não recua por si.

Etapa 1: medir o que o journal ocupa

O du mostra o directório, mas o journald tem o seu próprio contador, que distingue ficheiros activos e arquivados:


sudo journalctl --disk-usage

Archived and active journals take up 2.6G in the file system.

A distinção interessa: os ficheiros activos são os que o journald está a escrever, os arquivados são os já rotados. A limpeza manual só actua sobre os arquivados, e este facto explica o erro comum da secção final. Para ver os ficheiros concretos:


sudo ls -lh /var/log/journal/*/ | tail -5

-rw-r----- 1 root systemd-journal 128M Oct 12 07:44 [email protected]
-rw-r----- 1 root systemd-journal 128M Oct 12 08:31 [email protected]
-rw-r----- 1 root systemd-journal  96M Oct 12 08:55 [email protected]
-rw-r----- 1 root systemd-journal  64M Oct 12 09:01 system.journal

Num servidor com semanas de uptime, a lista de ficheiros arquivados chega às dezenas de entradas. O tamanho de cada uma tem tecto próprio: por defeito, 1/8 do SystemMaxUse, com um máximo de 128M — serviços ruidosos multiplicam o número de ficheiros, não o tamanho de cada.

Etapa 2: limpar com vacuum

Antes de apagar, considere guardar: copie os ficheiros para outro disco (cp -a /var/log/journal /backup/logs/) se os registos históricos têm valor. Depois, a sequência correcta é fazer a rotação primeiro e o vacuum depois. A rotação arquiva o ficheiro activo (e abre um novo), para que o vacuum possa actuar sobre tudo:


sudo journalctl --rotate

⚠ Atenção

os comandos seguintes apagam logs arquivados de forma definitiva. Não há confirmação nem recuperação, o que passar não volta. Verifique o que quer manter (--vacuum-time ou --vacuum-size) antes de correr, e confirme no output do journalctl --disk-usage depois.

O vacuum por tamanho remove os arquivos mais antigos até o total arquivado cair abaixo do valor pedido (o ficheiro activo não é tocado):


sudo journalctl --vacuum-size=200M

Deleted archived journal /var/log/journal/4c1f.../[email protected] (128M)
Deleted archived journal /var/log/journal/4c1f.../[email protected] (128M)
Vacuuming done, freed 2.4G of archived journals from /var/log/journal/4c1f....

Variantes úteis por tempo e por contagem de ficheiros:


sudo journalctl --vacuum-time=30days
sudo journalctl --vacuum-files=20

A man page permite combinar rotação e limpeza numa só linha, que fica bem num runbook de manutenção:


sudo journalctl --rotate --vacuum-time=30days

💡 Dica

se os logs arquivados são um activo para a PME (auditoria, investigação de incidentes), não use o vacuum como rotina de limpeza. Exporte para um servidor de logs central antes de apagar: o artigo de logs centralizados mostra o caminho com rsyslog, Loki e ELK.

Etapa 3: fixar um tecto no journald.conf

A limpeza manual resolve o sintoma, mas volta a acontecer. A solução permanente é fixar o tamanho do journal. Escreva um drop-in (não edite o journald.conf principal: os drop-ins sobrevivem a updates do pacote e o sistema ordena-os de forma previsível):


sudo mkdir -p /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/60-limite-journal.conf <<'EOF'
[Journal]
SystemMaxUse=512M
SystemKeepFree=2G
EOF
sudo systemctl restart systemd-journald

As directivas, com os defaults da man page:

Directiva Efeito Default
SystemMaxUse tecto do journal em /var/log/journal 10% do sistema de ficheiros, tecto 4GB
SystemKeepFree espaço livre a deixar no disco 15% do sistema de ficheiros, tecto 4GB
RateLimitIntervalSec janela de avaliação do rate limit global 30s
RateLimitBurst mensagens máximas por serviço na janela 10000
MaxRetentionSec tempo de retenção dos logs 0 (desligado)

Os dois limites valem em simultâneo: o SystemMaxUse limita o total do journal e o SystemKeepFree é o espaço que o disco mantém livre. Num disco de 40G confortável, é o SystemMaxUse=512M que manda. Quando o espaço livre desce abaixo do SystemKeepFree — os 1,2G do sintoma inicial já violam os 2G do exemplo —, a man page descreve o efeito: o journald levanta o limite, deixa de crescer o journal e não apaga nada para se auto-recuperar. É por isso que o vacuum da Etapa 2 vem antes do restart: fixar o tecto não recupera um disco já em pressão. Em discos pequenos (10 a 20G), reduza o SystemKeepFree — o default de 15% em 20G são 3G —, senão o tecto é inalcançável.

Verifique depois do restart:


sudo journalctl --disk-usage

Os limites aplicam-se à medida que o journald escreve; o uso que já está no disco pode não descer com o restart. Confirme com journalctl --disk-usage antes e depois de reiniciar o serviço: se o valor se mantiver, é o vacuum da Etapa 2 que faz o trabalho. Num servidor com o disco já em 97%, a prática sensata é fixar o tecto na Etapa 3 e correr o vacuum da Etapa 2 no mesmo dia: o primeiro evita o regresso do problema, o segundo liberta a pressão já instalada.

Etapa 4: limitar o serviço que enche o journal

Quando um serviço regista sem parar, o tecto da Etapa 3 só adiará o sintoma: o volume chega ao limite mais depressa. O comando seguinte conta entradas, não bytes — um serviço com muitas mensagens curtas também aqui se revela. Descubra quem é o responsável:


sudo journalctl -b -o verbose | grep -oE '(^|[[:space:]])_SYSTEMD_UNIT=[^[:space:]]+' | sort | uniq -c | sort -rn | head -5

Com o serviço identificado, aplique um rate limit próprio à unidade, com LogRateLimitIntervalSec e LogRateLimitBurst. Os valores por serviço sobrepõem-se aos globais do journald.conf:


sudo mkdir -p /etc/systemd/system/NOME_DO_SERVICO.service.d
sudo tee /etc/systemd/system/NOME_DO_SERVICO.service.d/60-logs.conf <<'EOF'
[Service]
LogRateLimitIntervalSec=30s
LogRateLimitBurst=200
EOF
sudo systemctl daemon-reload
sudo systemctl restart NOME_DO_SERVICO

Com o rate limit, o serviço continua a registar e o journald descarta dentro da janela as mensagens acima do limite, com uma nota no log sobre o número descartado. Atenção ao perfil de ruído: um serviço a registar uma linha por segundo soma 30 mensagens na janela de 30s — nunca chega às 10 000 do default, e o LogRateLimitBurst=200 quase não dispara. Para esse caso — debug constante que despeja linhas legítimas — o corte certo é pelo nível de severidade, com LogLevelMax na mesma unidade:


sudo mkdir -p /etc/systemd/system/NOME_DO_SERVICO.service.d
sudo tee /etc/systemd/system/NOME_DO_SERVICO.service.d/70-loglevel.conf <<'EOF'
[Service]
LogLevelMax=4
EOF
sudo systemctl daemon-reload
sudo systemctl restart NOME_DO_SERVICO

Com LogLevelMax=4, o journald guarda o que o serviço escreve até warning: as linhas info e debug são descartadas à entrada, sem tocar em disco.

Erro comum: o vacuum não liberta espaço

Causa 1: o comando só actua sobre arquivos. O --disk-usage inclui ficheiros activos, o vacuum não os toca. Faça a rotação primeiro (--rotate) e o vacuum depois.

Causa 2: o disco encheu por outra causa e passou o limite de espaço livre. O journald nessas condições levanta o limite: deixa de usar mais espaço — não deixa de escrever logs —, e também não encolhe ficheiros antigos para recuperar espaço. Corrija a causa no disco e faça o vacuum manualmente.

Causa 3: /var/log/journal vazio. O Storage= do journald.conf decide: auto grava em /var/log/journal quando o directório existe, em /run/log/journal caso contrário; volatile só em memória. Mudar de persistent para volatile não apaga os dados persistentes que já lá estão, apenas deixa de os usar.

Causa 4: journal só em /run. Em servidores onde /var/log/journal nunca foi criado, os logs vivem em /run/log/journal e desaparecem no reboot. Para activar o modo persistente, crie o directório com os modos correctos e faça flush:


sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
sudo journalctl --flush

Veredicto

Numa PME, o journal do systemd não devia ser a variável que enche o disco: fixe o SystemMaxUse (512M num servidor pequeno, 1 a 2G num com muitos serviços), deixe o SystemKeepFree num valor que o disco real permita e trate os serviços ruidosos com o rate limit por unidade da Etapa 4. O vacuum da Etapa 2 é o gesto único de manutenção quando o disco já está cheio, e a combinação de rotação com vacuum fica num runbook. O journal é uma ferramenta de diagnóstico, e o vacuum troca histórico por espaço livre: até onde recuar é decisão de retenção de cada operação — pondere a auditoria contra o risco do disco e fixe a escolha no runbook. Para ler e filtrar o que o journal guarda, siga para o artigo do journalctl.

Artigos Relacionados

Fontes oficiais