Disco Lleno: Cómo Encontrar y Limpiar Espacio

Introducción

Un disco lleno es uno de los problemas más comunes y críticos que afectan a los servidores Linux. Cuando los sistemas de archivos alcanzan el 100% de capacidad, las aplicaciones fallan al escribir datos, los logs dejan de registrarse, las bases de datos se corrompen y los servicios se caen. Comprender cómo identificar rápidamente qué está consumiendo espacio en disco y cómo recuperarlo de forma segura es esencial para cada administrador de sistemas.

Esta guía completa proporciona herramientas prácticas de línea de comandos y metodologías sistemáticas para diagnosticar y resolver problemas de espacio en disco. Aprenderás cómo encontrar archivos grandes, identificar directorios que consumen espacio, limpiar datos innecesarios e implementar medidas preventivas para evitar futuros problemas de espacio en disco.

Los problemas de espacio en disco a menudo escalan rápidamente, especialmente en servidores con registro intensivo o procesamiento de datos. Esta guía te enseñará a reconocer señales de advertencia temprana, realizar análisis detallados e implementar procedimientos de limpieza automatizados para mantener una utilización de disco saludable en tu infraestructura.

Comprendiendo los Problemas de Espacio en Disco

Causas Comunes de Disco Lleno

Archivos de Log: Logs de aplicación, sistema o servidor web que crecen rápidamente Archivos Temporales: Archivos acumulados en /tmp, /var/tmp y directorios de caché Crecimiento de Base de Datos: Archivos de base de datos en expansión y logs de transacciones Respaldos: Archivos de respaldo antiguos que no se rotan Core Dumps: Archivos de volcado grandes de aplicaciones caídas Caché de Paquetes: Paquetes descargados que no se limpian Datos de Usuario: Archivos cargados, adjuntos de correo, directorios home de usuario Archivos Huérfanos: Archivos de aplicaciones desinstaladas Agotamiento de Inodos: Demasiados archivos pequeños consumiendo todos los inodos

Umbrales Críticos

Comprendiendo umbrales de uso de disco:

  • 0-70%: Rango saludable normal
  • 70-85%: Monitorear de cerca
  • 85-95%: Advertencia - tomar acción pronto
  • 95-98%: Crítico - acción inmediata necesaria
  • 98-100%: Emergencia - degradación de servicio probable

Importante: Algunos sistemas de archivos (como ext4) reservan 5% para root, por lo que 95% puede aparecer como 100% para usuarios regulares.

Evaluación Inicial del Espacio en Disco

Verificación Rápida del Estado del Disco

Comienza con estos comandos de evaluación rápida:

# Vista general de todos los sistemas de archivos
df -h

# Legible por humanos con tipo de sistema de archivos
df -hT

# Uso de inodos
df -i

# Sistema de archivos específico
df -h /

# Excluir tipos específicos de sistema de archivos
df -h -x tmpfs -x devtmpfs

# Ordenar por uso
df -h | sort -k5 -rh

# Alertar en alto uso
df -h | awk '$5+0 > 85 {print $0}'

Interpretación rápida:

# Si Use% > 95%
# ENTONCES acción inmediata requerida

# Si IUse% > 90%
# ENTONCES demasiados archivos pequeños (agotamiento de inodos)

# Si /var, /var/log lleno
# ENTONCES probable problema de archivos de log

# Si /home lleno
# ENTONCES acumulación de datos de usuario

Comprendiendo la Salida de df

df -hT

Filesystem     Type      Size  Used Avail Use% Mounted on
/dev/sda1      ext4       50G   47G  1.5G  97% /
/dev/sda2      ext4      100G   15G   80G  16% /home
tmpfs          tmpfs     7.8G     0  7.8G   0% /dev/shm

Columnas clave:

  • Filesystem: Dispositivo o partición
  • Type: Tipo de sistema de archivos (ext4, xfs, etc.)
  • Size: Capacidad total
  • Used: Espacio actualmente usado
  • Avail: Espacio disponible
  • Use%: Porcentaje usado
  • Mounted on: Punto de montaje

Paso 1: Identificar Directorios Grandes

Usando el Comando du

El comando du (disk usage - uso de disco) muestra tamaños de directorios:

# Tamaño del directorio actual
du -sh .

# Todos los subdirectorios
du -sh *

# Directorios de nivel superior desde raíz
du -sh /* 2>/dev/null

# Ordenar por tamaño
du -sh /* 2>/dev/null | sort -rh

# Top 10 directorios más grandes
du -h / 2>/dev/null | sort -rh | head -10

# Análisis de directorio específico
du -h /var/log | sort -rh | head -20

# Mostrar solo directorios mayores a 1GB
du -h / 2>/dev/null | grep "^[0-9\.]*G"

# Excluir ciertas rutas
du -h --exclude=/proc --exclude=/sys / 2>/dev/null | sort -rh | head -20

# Profundidad máxima
du -h --max-depth=1 /var | sort -rh

Analizando Directorios Comunes

# Directorio de logs
du -sh /var/log/*  | sort -rh | head -10

# Directorios home
du -sh /home/* | sort -rh

# Directorios temporales
du -sh /tmp /var/tmp /dev/shm

# Caché de paquetes
du -sh /var/cache/apt/archives  # Debian/Ubuntu
du -sh /var/cache/yum           # CentOS/RHEL

# Docker
du -sh /var/lib/docker

# Base de datos
du -sh /var/lib/mysql
du -sh /var/lib/postgresql

# Directorios web
du -sh /var/www/*

# Directorios de correo
du -sh /var/mail/*

Script Automatizado de Análisis de Directorio

cat > /tmp/disk-analysis.sh << 'EOF'
#!/bin/bash

echo "Disk Space Analysis - $(date)"
echo "========================================"
echo ""

echo "Filesystem Usage:"
df -hT | grep -v "tmpfs\|devtmpfs"
echo ""

echo "Largest Directories in /:"
du -sh /* 2>/dev/null | sort -rh | head -10
echo ""

echo "Largest Directories in /var:"
du -sh /var/* 2>/dev/null | sort -rh | head -10
echo ""

echo "Log Files:"
du -sh /var/log/* 2>/dev/null | sort -rh | head -10
echo ""

echo "Largest Users:"
du -sh /home/* 2>/dev/null | sort -rh | head -10
echo ""

echo "Temporary Files:"
du -sh /tmp /var/tmp 2>/dev/null
EOF

chmod +x /tmp/disk-analysis.sh
/tmp/disk-analysis.sh

Paso 2: Encontrar Archivos Grandes

Usando el Comando find

Localizar archivos grandes específicos:

# Archivos mayores a 100MB
find / -type f -size +100M -exec ls -lh {} \; 2>/dev/null

# Archivos mayores a 1GB con detalles
find / -type f -size +1G -exec ls -lh {} \; 2>/dev/null | sort -k5 -rh

# Top 20 archivos más grandes
find / -type f -printf '%s %p\n' 2>/dev/null | sort -nr | head -20 | awk '{print $1/1024/1024 "MB", $2}'

# Archivos grandes en directorio específico
find /var -type f -size +50M -exec ls -lh {} \; 2>/dev/null

# Archivos grandes modificados en los últimos 7 días
find / -type f -size +100M -mtime -7 -exec ls -lh {} \; 2>/dev/null

# Archivos mayores a 500MB ordenados
find / -type f -size +500M -printf '%s %p\n' 2>/dev/null | sort -rn | awk '{printf "%.2f GB  %s\n", $1/1024/1024/1024, $2}'

# Archivos de log grandes
find /var/log -type f -size +50M -exec ls -lh {} \; 2>/dev/null

# Archivos core dump
find / -name "core.*" -o -name "*.core" 2>/dev/null -exec ls -lh {} \;

Encontrar Archivos por Antigüedad

# Archivos mayores a 30 días
find / -type f -mtime +30 -size +10M 2>/dev/null

# Archivos no accedidos en 90 días
find / -type f -atime +90 -size +50M 2>/dev/null

# Archivos grandes creados recientemente
find / -type f -size +100M -mtime -1 -exec ls -lh {} \; 2>/dev/null

# Archivos temporales antiguos
find /tmp -type f -mtime +7 -exec ls -lh {} \; 2>/dev/null
find /var/tmp -type f -mtime +30 -exec ls -lh {} \; 2>/dev/null

Script Rápido de Búsqueda de Archivos Grandes

cat > /tmp/find-large-files.sh << 'EOF'
#!/bin/bash

SIZE_MB=${1:-100}
echo "Finding files larger than ${SIZE_MB}MB..."
echo ""

find / -type f -size +${SIZE_MB}M 2>/dev/null -printf '%s %p\n' |
sort -rn |
head -20 |
while read size path; do
    size_mb=$(echo "scale=2; $size/1024/1024" | bc)
    printf "%8.2f MB  %s\n" $size_mb "$path"
done
EOF

chmod +x /tmp/find-large-files.sh

# Encontrar archivos > 100MB
/tmp/find-large-files.sh 100

# Encontrar archivos > 500MB
/tmp/find-large-files.sh 500

Paso 3: Analizar Áreas Problemáticas Específicas

Análisis de Archivos de Log

Los logs son la causa más común de problemas de espacio en disco:

# Tamaño del directorio de logs
du -sh /var/log
du -sh /var/log/* | sort -rh | head -10

# Archivos de log más grandes
find /var/log -type f -printf '%s %p\n' | sort -rn | head -20 | awk '{print $1/1024/1024 "MB", $2}'

# Logs que crecen activamente
ls -lth /var/log/*.log | head -10

# Encontrar logs no rotados
find /var/log -name "*.log" -size +100M

# Tamaño de logs de journal
du -sh /var/log/journal
journalctl --disk-usage

# Verificar configuración de rotación de logs
cat /etc/logrotate.conf
ls -la /etc/logrotate.d/

# Probar logrotate
logrotate -d /etc/logrotate.conf

Caché del Gestor de Paquetes

Las cachés de paquetes pueden consumir espacio significativo:

# Caché APT de Debian/Ubuntu
du -sh /var/cache/apt/archives
ls -lh /var/cache/apt/archives/*.deb 2>/dev/null | wc -l

# Limpiar caché APT
apt clean
apt autoclean

# Caché YUM de CentOS/RHEL
du -sh /var/cache/yum
yum clean all

# Caché DNF (sistemas más nuevos)
du -sh /var/cache/dnf
dnf clean all

# Listar paquetes en caché
ls -lh /var/cache/apt/archives/*.deb 2>/dev/null

Limpieza de Docker

Docker puede acumular almacenamiento significativo:

# Uso de disco de Docker
docker system df

# Desglose detallado
docker system df -v

# Eliminar contenedores no usados
docker container prune -f

# Eliminar imágenes no usadas
docker image prune -a -f

# Eliminar volúmenes no usados
docker volume prune -f

# Eliminar todo lo no usado
docker system prune -a -f --volumes

# Verificar tamaño del directorio raíz de Docker
du -sh /var/lib/docker
du -sh /var/lib/docker/overlay2

Archivos de Base de Datos

Los archivos de base de datos pueden crecer rápidamente:

# Directorio de datos MySQL/MariaDB
du -sh /var/lib/mysql
du -sh /var/lib/mysql/* | sort -rh

# Logs binarios MySQL
du -sh /var/lib/mysql/mysql-bin.*
mysql -e "SHOW BINARY LOGS;"

# Purgar logs binarios antiguos (mantener últimos 3 días)
mysql -e "PURGE BINARY LOGS BEFORE DATE(NOW() - INTERVAL 3 DAY);"

# PostgreSQL
du -sh /var/lib/postgresql
du -sh /var/lib/postgresql/*/main/base/* | sort -rh

# MongoDB
du -sh /var/lib/mongodb

# Verificar tamaños de base de datos
mysql -e "SELECT table_schema AS 'Database', ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)' FROM information_schema.tables GROUP BY table_schema ORDER BY SUM(data_length + index_length) DESC;"

Archivos de Servidor Web

# Directorios web
du -sh /var/www/* | sort -rh

# Directorios de uploads
find /var/www -name uploads -o -name files | xargs du -sh

# Archivos subidos antiguos
find /var/www -name uploads -type d -exec find {} -type f -mtime +90 \; | wc -l

# Archivos temporales web
find /var/www -name "*.tmp" -o -name "*.cache" | xargs du -ch

Paso 4: Agotamiento de Inodos

Verificar Uso de Inodos

# Uso de inodos
df -i

# Encontrar directorios con más archivos
for dir in /*; do
    echo "$dir: $(find $dir -type f 2>/dev/null | wc -l) files"
done | sort -t: -k2 -rn

# Contar archivos en subdirectorios
find /var -maxdepth 2 -type d -exec sh -c 'echo "{}: $(find "{}" -type f | wc -l)"' \; | sort -t: -k2 -rn | head -20

# Encontrar directorios con archivos pequeños excesivos
du -a / 2>/dev/null | sort -n -r | head -n 50 | awk '{if($1 < 100) print $0}'

# Archivos de sesión
ls /tmp | wc -l
ls /var/tmp | wc -l
ls /var/lib/php/sessions 2>/dev/null | wc -l

Limpieza de Problemas de Inodos

# Eliminar sesiones PHP antiguas
find /var/lib/php/sessions -type f -mtime +7 -delete

# Eliminar archivos temporales antiguos
find /tmp -type f -mtime +7 -delete
find /var/tmp -type f -mtime +30 -delete

# Limpiar cola de correo
postqueue -p | wc -l
postsuper -d ALL deferred

Paso 5: Procedimientos de Limpieza Segura

Limpieza de Archivos de Log

# Truncar logs grandes (preservar archivo)
truncate -s 0 /var/log/large.log

# Alternativa: vaciar log manteniendo archivo
> /var/log/large.log

# Eliminar logs rotados antiguos
find /var/log -name "*.log.*" -mtime +30 -delete
find /var/log -name "*.gz" -mtime +30 -delete

# Limpiar logs de journal (mantener 2 días)
journalctl --vacuum-time=2d

# Limpiar logs de journal (mantener 1GB)
journalctl --vacuum-size=1G

# Rotar logs manualmente
logrotate -f /etc/logrotate.conf

# Eliminar archivos kern.log antiguos
find /var/log -name "kern.log.*" -mtime +7 -delete

Limpieza de Archivos Temporales

# Limpiar /tmp (archivos mayores a 7 días)
find /tmp -type f -atime +7 -delete

# Limpiar /var/tmp (mayores a 30 días)
find /var/tmp -type f -atime +30 -delete

# Limpiar caché de usuario
rm -rf ~/.cache/*

# Limpiar caché de miniaturas
rm -rf ~/.thumbnails/*

# Archivos temporales del sistema
rm -rf /tmp/*
rm -rf /var/tmp/*
# Advertencia: Solo si no hay procesos activos usando estos archivos

Limpieza de Paquetes

# Debian/Ubuntu
apt autoremove -y
apt autoclean
apt clean

# Eliminar kernels antiguos (mantener actual y uno anterior)
apt autoremove --purge -y

# Listar kernels instalados
dpkg --list | grep linux-image

# CentOS/RHEL
yum autoremove -y
yum clean all

# Eliminar kernels antiguos
package-cleanup --oldkernels --count=2

# Listar kernels instalados
rpm -qa kernel

Limpieza de Datos de Usuario

# Encontrar archivos grandes de usuario
du -sh /home/* | sort -rh

# Descargas antiguas
find /home/*/Downloads -type f -mtime +30

# Archivos de correo grandes
du -sh /var/mail/*

# Limpiar historial de bash
history -c
> ~/.bash_history

# Eliminar volcados de core antiguos
find /home -name "core.*" -delete
find / -name "core" -type f -delete 2>/dev/null

Paso 6: Técnicas Avanzadas de Limpieza

Encontrar Archivos Eliminados pero Abiertos

Archivos eliminados pero aún mantenidos abiertos por procesos:

# Listar archivos eliminados aún abiertos
lsof | grep deleted

# Vista detallada
lsof +L1

# Tamaño de archivos eliminados abiertos
lsof +L1 | awk '{sum+=$7} END {print "Total:", sum/1024/1024 "MB"}'

# Matar proceso manteniendo archivo eliminado
kill -9 $(lsof +L1 | grep filename | awk '{print $2}')

# Alternativa: reiniciar servicio
systemctl restart service-name

Detección de Archivos Sparse

# Encontrar archivos sparse
find / -type f -printf "%S %p\n" 2>/dev/null | awk '$1 < 1.0 {print}'

# Verificar si archivo es sparse
du --apparent-size -h file.img
du -h file.img
# Si son diferentes, el archivo es sparse

Encontrar Duplicados

# Encontrar archivos duplicados con fdupes
apt install fdupes
fdupes -r /home

# Eliminar duplicados interactivamente
fdupes -rd /home

# Encontrar archivos duplicados manualmente
find /path -type f -exec md5sum {} + | sort | uniq -w32 -dD

Soluciones y Prevención

Implementar Rotación de Logs

# Configurar logrotate para aplicación personalizada
cat > /etc/logrotate.d/myapp << 'EOF'
/var/log/myapp/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
    create 0640 www-data www-data
    sharedscripts
    postrotate
        systemctl reload myapp >/dev/null 2>&1 || true
    endscript
}
EOF

# Probar configuración
logrotate -d /etc/logrotate.d/myapp

# Forzar rotación
logrotate -f /etc/logrotate.d/myapp

Scripts de Limpieza Automatizada

cat > /usr/local/bin/disk-cleanup.sh << 'EOF'
#!/bin/bash

LOG_FILE="/var/log/disk-cleanup.log"

echo "$(date): Starting disk cleanup" >> "$LOG_FILE"

# Limpiar caché de paquetes
apt autoclean -y >> "$LOG_FILE" 2>&1
apt autoremove -y >> "$LOG_FILE" 2>&1

# Limpiar logs antiguos
find /var/log -name "*.log.*" -mtime +30 -delete
find /var/log -name "*.gz" -mtime +30 -delete

# Limpiar archivos temporales
find /tmp -type f -atime +7 -delete
find /var/tmp -type f -atime +30 -delete

# Limpiar journal
journalctl --vacuum-time=7d >> "$LOG_FILE" 2>&1

# Limpiar Docker (si está instalado)
if command -v docker &> /dev/null; then
    docker system prune -f >> "$LOG_FILE" 2>&1
fi

# Reportar uso de disco
echo "$(date): Disk cleanup completed" >> "$LOG_FILE"
df -h >> "$LOG_FILE"
EOF

chmod +x /usr/local/bin/disk-cleanup.sh

# Programar limpieza semanal
echo "0 2 * * 0 /usr/local/bin/disk-cleanup.sh" | crontab -

Monitoreo de Uso de Disco

cat > /usr/local/bin/disk-monitor.sh << 'EOF'
#!/bin/bash

THRESHOLD=85
ALERT_EMAIL="[email protected]"

df -H | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{print $5 " " $1 " " $6}' | while read output;
do
    usage=$(echo $output | awk '{print $1}' | cut -d'%' -f1)
    partition=$(echo $output | awk '{print $2}')
    mount=$(echo $output | awk '{print $3}')

    if [ $usage -ge $THRESHOLD ]; then
        echo "Alert: Disk usage on $partition ($mount) is ${usage}%" | \
            mail -s "Disk Space Alert on $(hostname)" "$ALERT_EMAIL"

        # Registrar principales consumidores de espacio
        echo "Top consumers in $mount:" | mail -s "Disk Details" "$ALERT_EMAIL"
        du -sh $mount/* 2>/dev/null | sort -rh | head -10 | \
            mail -s "Disk Usage Details" "$ALERT_EMAIL"
    fi
done
EOF

chmod +x /usr/local/bin/disk-monitor.sh

# Ejecutar cada hora
echo "0 * * * * /usr/local/bin/disk-monitor.sh" | crontab -

Implementación de Cuotas

# Instalar herramientas de cuota
apt install quota

# Editar /etc/fstab, agregar usrquota,grpquota
/dev/sda2  /home  ext4  defaults,usrquota,grpquota  0  2

# Remontar
mount -o remount /home

# Crear archivos de cuota
quotacheck -cum /home
quotacheck -cgm /home

# Habilitar cuotas
quotaon -v /home

# Establecer cuota de usuario (1GB soft, 1.5GB hard)
setquota -u username 1000000 1500000 0 0 /home

# Establecer cuota de grupo
setquota -g groupname 5000000 6000000 0 0 /home

# Verificar cuota
quota -u username
repquota -a

Configurar Alertas

cat > /etc/cron.hourly/disk-alert << 'EOF'
#!/bin/bash

USAGE=$(df / | tail -1 | awk '{print $5}' | cut -d'%' -f1)

if [ $USAGE -gt 90 ]; then
    echo "Critical: Root filesystem is ${USAGE}% full on $(hostname)" | \
        mail -s "CRITICAL: Disk Space Alert" [email protected]
elif [ $USAGE -gt 80 ]; then
    echo "Warning: Root filesystem is ${USAGE}% full on $(hostname)" | \
        mail -s "WARNING: Disk Space Alert" [email protected]
fi
EOF

chmod +x /etc/cron.hourly/disk-alert

Procedimientos de Emergencia

Cuando el Disco Está 100% Lleno

# 1. Liberar algo de espacio inmediatamente
rm -f /var/log/*.log.1 /var/log/*.log.*.gz

# 2. Truncar log más grande
largest_log=$(find /var/log -type f -printf '%s %p\n' | sort -rn | head -1 | awk '{print $2}')
truncate -s 0 "$largest_log"

# 3. Limpiar caché de paquetes
apt clean
yum clean all

# 4. Limpiar archivos temporales
rm -rf /tmp/*
rm -rf /var/tmp/*

# 5. Verificar y reiniciar servicios afectados
systemctl status
systemctl restart failing-service

Partición de Boot Llena

# Listar kernels instalados
dpkg --list | grep linux-image

# Eliminar kernels antiguos (mantener actual + 1)
apt autoremove --purge -y

# Eliminar manualmente kernel antiguo
apt remove linux-image-VERSION-generic

# Limpiar /boot
rm -f /boot/*.old-dkms
update-grub

Conclusión

La gestión del espacio en disco es crucial para la estabilidad del sistema y requiere monitoreo y mantenimiento proactivos. Conclusiones clave:

  1. Monitorear proactivamente: No esperar hasta llegar al 100% para tomar acción
  2. Implementar rotación de logs: Prevenir que los logs consuman todo el espacio
  3. Automatizar limpieza: Programar tareas de mantenimiento regulares
  4. Configurar alertas: Ser notificado antes de umbrales críticos
  5. Usar cuotas: Prevenir que usuarios individuales consuman todo el espacio
  6. Conocer tus datos: Comprender qué debería y no debería estar en el sistema
  7. Documentar procedimientos: Mantener scripts y procedimientos de limpieza listos

El monitoreo regular, procedimientos de limpieza automatizados y la comprensión de estas herramientas de diagnóstico te ayudarán a prevenir emergencias de espacio en disco y resolver rápidamente problemas cuando ocurran. Mantén estos comandos fácilmente disponibles para solución rápida de problemas cuando surjan problemas de espacio en disco.