StackPractices
intermediate Por Mathias Paulenko

Monitorear Uso de Disco con Bash

Alerta cuando el espacio en disco cruza umbrales con scripts bash.

Temas: devops

Visión General

Los problemas de espacio en disco causan crashes de aplicación, writes fallidos y bases de datos corruptas. Un script de monitoreo que verifica el uso de disco y alerta antes de que se llene previene estos problemas. Esta recipe cubre alertas basadas en umbrales, notificaciones por email y limpieza automática de consumidores comunes de espacio.

Cuándo Usar

  • For alternatives, see AWS CLI Automation with Bash.

  • Administras servidores Linux y necesitas alertas proactivas de espacio en disco

  • Quieres automatizar la limpieza de logs viejos, archivos temp o caches de paquetes

  • Necesitas umbrales de alerta diferentes para distintas particiones

  • Estás configurando una solución de monitoreo ligera sin herramientas externas

Solución

Verificación básica de uso de disco

#!/bin/bash

THRESHOLD=80
ALERT_EMAIL="admin@example.com"

df -H | grep -vE '^Filesystem|tmpfs|cdrom' | while read -r line; do
    usage=$(echo "$line" | awk '{print $5}' | sed 's/%//')
    partition=$(echo "$line" | awk '{print $6}')

    if [ "$usage" -ge "$THRESHOLD" ]; then
        echo "WARNING: Partition $partition is at ${usage}% capacity"
    fi
done

Alerta por email con detalles

#!/bin/bash

THRESHOLD=80
ALERT_EMAIL="admin@example.com"
HOSTNAME=$(hostname)

df -H | grep -vE '^Filesystem|tmpfs|cdrom' | while read -r line; do
    usage=$(echo "$line" | awk '{print $5}' | sed 's/%//')
    partition=$(echo "$line" | awk '{print $6}')
    size=$(echo "$line" | awk '{print $2}')
    used=$(echo "$line" | awk '{print $3}')
    avail=$(echo "$line" | awk '{print $4}')

    if [ "$usage" -ge "$THRESHOLD" ]; then
        SUBJECT="[ALERT] Disk space on ${HOSTNAME}: ${partition} at ${usage}%"
        BODY="Disk space alert on ${HOSTNAME}

Partition: ${partition}
Usage: ${usage}%
Size: ${size}
Used: ${used}
Available: ${avail}

Action required: free up space on this partition."

        echo "$BODY" | mail -s "$SUBJECT" "$ALERT_EMAIL"
        echo "Alert sent for $partition"
    fi
done

Umbrales por partición

#!/bin/bash

# Formato: "mountpoint:threshold"
PARTITIONS=(
    "/:80"
    "/var:90"
    "/home:75"
    "/tmp:85"
)

ALERT_EMAIL="admin@example.com"

for entry in "${PARTITIONS[@]}"; do
    partition="${entry%%:*}"
    threshold="${entry##*:}"

    usage=$(df -H "$partition" | tail -1 | awk '{print $5}' | sed 's/%//')

    if [ "$usage" -ge "$threshold" ]; then
        echo "ALERT: $partition at ${usage}% (threshold: ${threshold}%)"
        echo "Partition $partition at ${usage}%" | \
            mail -s "Disk alert: $partition" "$ALERT_EMAIL"
    fi
done

Limpieza automática con uso alto

#!/bin/bash

THRESHOLD=85
LOG_DIR="/var/log"
TMP_DIR="/tmp"
CACHE_DIR="/var/cache/apt/archives"

# Obtener uso de partición root
usage=$(df -H / | tail -1 | awk '{print $5}' | sed 's/%//')

if [ "$usage" -lt "$THRESHOLD" ]; then
    exit 0
fi

echo "Disk usage at ${usage}%. Starting cleanup..."

# Limpiar logs comprimidos viejos (mantener 7 días)
find "$LOG_DIR" -name "*.gz" -type f -mtime +7 -delete
echo "Cleaned old compressed logs"

# Limpiar archivos tmp viejos de 7 días
find "$TMP_DIR" -type f -mtime +7 -delete
echo "Cleaned /tmp"

# Limpiar apt cache
if [ -d "$CACHE_DIR" ]; then
    apt-get clean
    echo "Cleaned apt cache"
fi

# Verificar uso después de limpieza
new_usage=$(df -H / | tail -1 | awk '{print $5}' | sed 's/%//')
echo "Disk usage after cleanup: ${new_usage}%"

Encontrar archivos y directorios más grandes

#!/bin/bash

echo "=== Top 10 largest directories ==="
du -sh /* 2>/dev/null | sort -rh | head -10

echo ""
echo "=== Top 10 largest files ==="
find / -type f -exec du -h {} + 2>/dev/null | sort -rh | head -10

echo ""
echo "=== Disk usage by partition ==="
df -h

Configuración cron para monitoreo continuo

# Agregar a crontab

# Verificar cada hora
0 * * * * /opt/scripts/disk-monitor.sh >> /var/log/disk-monitor.log 2>&1

# Limpieza diaria a las 3 AM
0 3 * * * /opt/scripts/disk-cleanup.sh

Alerta por webhook de Slack

#!/bin/bash

THRESHOLD=80
SLACK_WEBHOOK="https://hooks.slack.com/services/XXX/YYY/ZZZ"
HOSTNAME=$(hostname)

df -H | grep -vE '^Filesystem|tmpfs|cdrom' | while read -r line; do
    usage=$(echo "$line" | awk '{print $5}' | sed 's/%//')
    partition=$(echo "$line" | awk '{print $6}')

    if [ "$usage" -ge "$THRESHOLD" ]; then
        curl -X POST -H 'Content-type: application/json' \
            --data "{\"text\":\"Disk alert on ${HOSTNAME}: ${partition} at ${usage}%\"}" \
            "$SLACK_WEBHOOK"
    fi
done

Explicación

df -H reporta el uso de disco en formato legible (potencias de 1000). El script filtra filesystems virtuales (tmpfs, cdrom) y verifica cada partición restante contra el umbral.

El script de limpieza ataca consumidores comunes de espacio: logs comprimidos viejos, archivos temp stale y caches de paquetes. Solo corre cuando el uso supera el umbral, evitando trabajo innecesario.

Los umbrales por partición te permiten ser más flexible con /var (los logs se espera que crezcan) y más estricto con / (que la partición root se llene es crítico).

Variantes

EnfoqueMétodo de AlertaLimpiezaUsar Cuando
Verificación básicaConsolaNoChequeos manuales rápidos
Alerta por emailcomando mailNoServidores con mail configurado
Por particiónEmailNoTamaños mixtos de particiones
Limpieza autoConsolaServidores self-healing
Webhook SlackHTTP POSTNoEquipos que usan Slack

Pautas

  • Setea umbrales realistas. 80% warning, 90% crítico es un patrón común.
  • Excluye filesystems virtuales (tmpfs, devtmpfs, cdrom) del monitoreo.
  • Testea scripts de limpieza en un entorno no productivo primero.
  • Loguea todas las acciones de limpieza para auditoría.
  • Monitorea el uso de inodos por separado. Un disco puede tener espacio libre pero sin inodos.

Errores Comunes

  • Setear el umbral muy bajo (50%) y recibir alertas falsas constantes.
  • No excluir tmpfs y filesystems virtuales. Estos reportan 100% de uso pero no son discos reales.
  • Ejecutar limpieza sin verificar qué se va a borrar. find -delete es irreversible.
  • Olvidar configurar cron. El script corre una vez y nunca se vuelve a verificar.
  • Monitorear solo la partición root. /var o /home pueden llenarse independientemente.

Lectura Adicional

  • Documentación oficial: consulta la referencia actualizada del framework o herramienta utilizada.
  • Guías relacionadas: explora las guías de bash y infrastructure para profundizar.
  • Patrones complementarios: revisa los patrones de diseño aplicables a tu stack tecnológico.
  • Postmortems públicos: estudia incidentes reales de equipos que enfrentaron problemas similares en producción.

Notas de Producción

  • Despliega gradualmente usando canary o blue-green para detectar regresiones temprano.
  • Configura alertas para errores, latencia p99 y tasa de fallos antes de habilitar en producción.
  • Documenta el rollback en el runbook; prueba el procedimiento en staging al menos una vez por trimestre.
  • Revisa logs estructurados con correlation IDs para trazar requests end-to-end en incidentes.

Puntos Clave

  • Aplica monitorear uso de disco con bash cuando necesites una solución práctica para tu caso de uso.
  • Monitorea el rendimiento después de implementar; mide latencia, errores y uso de recursos antes y después.
  • Revisa la sección de Troubleshooting ante errores comunes; la mayoría tienen causa raíz documentada con solución.
  • Mantén dependencias actualizadas y ejecuta tests en CI para prevenir regresiones en producción.

Troubleshooting

  • Pipeline fails silently: enable verbose logging and store pipeline artifacts between stages so you can inspect the exact state that failed.
  • Container crashes on startup: check that environment variables, secrets, and config files are mounted correctly. Read the first 50 lines of logs before scaling replicas.
  • Deployment rolls back repeatedly: verify health checks, resource limits, and startup probes. A failing readiness probe is a common cause of rolling restarts.
  • Slow CI builds: cache dependencies and docker layers. Split large test suites into parallel jobs to reduce wall-clock time.
  • Drift between environments: use infrastructure-as-code and immutable artifacts.

Errores Comunes en Producción

  • Copiar el ejemplo sin adaptarlo a volúmenes y modos de fallo reales.
  • Saltar tests de carga e inyección de errores antes del primer despliegue productivo.
  • Codificar valores fijos que deberían ser configurables por entorno.
  • Olvidar agregar logging y monitoreo en cada paso.
  • Desplegar sin plan de rollback ni estrategia de backup probada.
  • Asumir que el ejemplo mínimo escalará sin agregar caché o procesamiento por lotes.
  • No documentar la versión y configuración usadas en producción.
  • Dejar la receta sin cambios cuando evolucionan las dependencias o la escala.

Preguntas frecuentes

¿Cómo monitoreo el uso de inodos en vez de espacio en disco?
df -i | grep -vE '^Filesystem|tmpfs' | while read -r line; do
    iuse=$(echo "$line" | awk '{print $5}' | sed 's/%//')
    partition=$(echo "$line" | awk '{print $6}')
    if [ "$iuse" -ge 80 ]; then
        echo "Inode alert: $partition at ${iuse}%"
    fi
done
¿Cómo encuentro qué está consumiendo espacio en disco?

Usa du para encontrar directorios grandes y find para localizar archivos grandes:

# Directorios más grandes
du -sh /var/* 2>/dev/null | sort -rh | head -10

# Archivos más grandes
find /var -type f -size +100M -exec ls -lh {} +
¿Puedo usar esto con contenedores Docker?

Sí. Monitorea el directorio de datos de Docker (/var/lib/docker) y ejecuta docker system prune en el script de limpieza:

if [ "$usage" -ge "$THRESHOLD" ]; then
    docker system prune -af --volumes
fi
¿Cómo evito la fatiga de alertas?

Usa un archivo de estado para trackear qué particiones ya fueron alertadas:

STATE_FILE="/tmp/disk-alert-state"

# Solo alertar si no está ya en estado
if [ "$usage" -ge "$THRESHOLD" ] && ! grep -q "$partition" "$STATE_FILE" 2>/dev/null; then
    # Enviar alerta
    echo "$partition" >> "$STATE_FILE"
fi

# Limpiar estado cuando el uso baja
if [ "$usage" -lt "$THRESHOLD" ]; then
    sed -i "/$partition/d" "$STATE_FILE"
fi