Monitorear Uso de Disco
Alerta cuando el espacio en disco cruza umbrales usando un script de Bash que verifica mount points y notifica operadores.
Visión General
El espacio en disco es un asesino silencioso de servicios productivos. Cuando un log, caché o base de datos llena el disco, las aplicaciones se caen, las escrituras fallan y la recuperación se vuelve urgente. Un simple script de Bash que verifica mount points y alerta cuando el uso cruza un umbral te da advertencia temprana y puede disparar limpieza antes de que la situación se vuelva crítica.
Cuándo Usar
Usa este recurso cuando:
- Quieras monitoreo ligero sin instalar un agente completo.
- Necesites alertar por email, Slack o archivo de log cuando el uso de disco sea alto.
- Ejecutes contenedores, VMs o servidores bare-metal con disco limitado.
- Quieras disparar limpieza automática cuando el uso cruza un umbral.
Solución
Script de monitoreo de uso de disco
#!/usr/bin/env bash
set -euo pipefail
THRESHOLD="${1:-80}"
EMAIL="${2:-admin@example.com}"
# Verificar todos los mount points locales
df -Hl | awk 'NR>1 && /^\/dev/{print $1, $5, $6}' | while read -r fs usage mount; do
usage_val="${usage%%}"
if (( usage_val >= THRESHOLD )); then
echo "WARNING: $mount ($fs) is at $usage"
# Enviar alerta (ejemplo con mail)
echo "Disk usage on $mount is $usage" | mail -s "Disk alert: $mount" "$EMAIL"
else
echo "OK: $mount is at $usage"
fi
done
# Opcional: disparar limpieza para mounts específicos
# if (( usage_val >= 90 )); then
# /usr/local/bin/cleanup-logs.sh
# fi
Explicación
El script usa df -Hl para listar filesystems locales y sus porcentajes de uso. awk filtra el encabezado y las entradas que no son dispositivos. Para cada mount point, elimina el signo de porcentaje, compara el valor numérico con el umbral e imprime una advertencia o mensaje OK. Si se excede el umbral, envía un alerta por email. El bloque de limpieza está comentado porque el borrado automático debe revisarse cuidadosamente antes de habilitarse.
Variantes
| Canal de alerta | Herramienta | Mejor para |
|---|---|---|
mail | Servidores simples con MTA local | |
| Slack | webhook curl | Equipos que ya usan Slack |
| PagerDuty | event API | Escalación on-call en producción |
| Log de archivo | redirect a syslog | Agregación centralizada de logs |
Lo que funciona
- Configura umbrales por debajo del 100%. Alerta al 80% y actúa al 90% para tener tiempo de responder.
- Monitorea mount points, no solo el disco total. Un
/tmpo/var/logpequeño puede llenarse independientemente del disco raíz. - Incluye el filesystem en la alerta. Saber qué partición está llena acelera la respuesta.
- Ejecuta desde cron cada pocos minutos. El uso de disco puede crecer rápido durante incidentes.
- Empareja monitoreo con limpieza. Una alerta de uso alto sin plan de limpieza es solo media solución.
Errores Comunes
- Usar
df -hsin cuidado en el parsing. La columna de porcentaje puede estar vacía para filesystems especiales; filtra entradas/dev/. - Alertar demasiado tarde. Esperar al 95% deja casi ningún tiempo para reaccionar.
- Ignorar mounts efímeros.
/tmpy volúmenes de docker pueden llenarse rápido y colapsar servicios. - Enviar alertas a individuos. Usa un alias de equipo o rotación on-call para que las vacaciones no rompan el alerting.
- No manejar fallos de correo. Si el MTA está caído, la alerta nunca llega; registra en un segundo canal.
Mejores Prácticas Adicionales
- For a deeper guide, see Backup Rotation Script.
-
Monitorea el uso de inodos por separado. Un disco puede tener espacio libre pero quedarse sin inodos (slots de archivos). Esto pasa con workloads que crean millones de archivos pequeños — servidores de mail, directorios de caché, almacenamiento de sesiones. Verifica los inodos con
df -iy alerta con los mismos umbrales. -
Usa alertas predictivas. En lugar de alertar sobre el uso actual, alerta sobre el uso predicho. Prometheus
predict_linear()puede pronosticar cuándo se llenará un disco basándose en la tasa de cambio. Esto te da horas o días de advertencia en lugar de minutos. -
Excluye mounts de solo lectura y tmpfs. Filtra
tmpfs,devtmpfs,overlayy filesystems de solo lectura del monitoreo. O no se pueden limpiar o los gestiona el kernel:
# Monitorear solo dispositivos de bloque reales, excluyendo tmpfs y overlays
df -Hl -x tmpfs -x devtmpfs -x overlay -x squashfs | awk 'NR>1 && /^\/dev/{print $1, $5, $6}'
- Registra tendencias de uso de disco. Loguea el uso diario a un archivo o base de datos. Las tendencias revelan qué mounts crecen más rápido y ayudan a planificar upgrades de capacidad antes de que las alertas se disparen:
# Agregar uso diario a un CSV para análisis de tendencias
echo "$(date -Iseconds),$(hostname),$mount,$usage" >> /var/log/disk-usage-trends.csv
Errores Comunes Adicionales
-
No monitorear el almacenamiento de Docker. Docker usa
/var/lib/dockerque puede crecer rápidamente con imágenes, contenedores y volúmenes. Monitorea esta ruta por separado y programa jobs regulares dedocker system prune. Una partición de almacenamiento Docker llena impide que nuevos contenedores arranquen. -
Olvidar mounts de red montados. NFS y SMB mounts pueden llenarse en el servidor remoto, causando que las escrituras locales se cuelguen. Monitorea mounts de red con timeouts más cortos y alerta sobre latencia además de uso. Usa
timeoutcondfpara evitar colgarse en servidores NFS no responsivos:
timeout 10 df -Hl "$NFS_MOUNT" || echo "NFS mount $NFS_MOUNT no responde"
- Usar umbrales de porcentaje en discos muy grandes o muy pequeños. En un disco de 100TB, 80% significa 20TB libres — mucho espacio. En un disco de 10GB, 80% significa 2GB libres — crítico. Usa umbrales absolutos en bytes para discos pequeños y umbrales de porcentaje para grandes:
# Alertar si el espacio libre es menor a 5GB O el uso es mayor a 90%
avail_bytes=$(df -B1 "$mount" | awk 'NR>1 {print $4}')
if (( avail_bytes < 5368709120 )) || (( usage_val >= 90 )); then
echo "WARNING: $mount tiene solo $((avail_bytes / 1073741824))GB libres"
fi Preguntas frecuentes
Integración de alertas por Slack
#!/usr/bin/env bash
set -euo pipefail
SLACK_WEBHOOK="${SLACK_WEBHOOK:-https://hooks.slack.com/services/XXX}"
THRESHOLD="${1:-80}"
HOSTNAME=$(hostname)
send_slack_alert() {
local mount="$1" usage="$2" fs="$3"
local payload
payload=$(cat <<EOF
{
"text": "Alerta de disco en ${HOSTNAME}",
"attachments": [{
"color": "danger",
"fields": [
{"title": "Mount", "value": "${mount}", "short": true},
{"title": "Uso", "value": "${usage}", "short": true},
{"title": "Filesystem", "value": "${fs}", "short": true},
{"title": "Host", "value": "${HOSTNAME}", "short": true}
]
}]
}
EOF
)
curl -s -X POST -H 'Content-Type: application/json' -d "$payload" "$SLACK_WEBHOOK"
}
df -Hl | awk 'NR>1 && /^\/dev/{print $1, $5, $6}' | while read -r fs usage mount; do
usage_val="${usage%\%}"
if (( usage_val >= THRESHOLD )); then
send_slack_alert "$mount" "$usage" "$fs"
echo "[$(date -Iseconds)] WARNING: $mount ($fs) at $usage — alerta Slack enviada"
fi
done
Monitoreo de inodos (el disco puede tener espacio pero no inodos)
#!/usr/bin/env bash
set -euo pipefail
INODE_THRESHOLD="${1:-80}"
df -i | awk 'NR>1 && /^\/dev/{print $1, $5, $6}' | while read -r fs iusage mount; do
iusage_val="${iusage%\%}"
if (( iusage_val >= INODE_THRESHOLD )); then
echo "WARNING: $mount ($fs) uso de inodos en $iusage"
# Encontrar directorios con más archivos
top_dirs=$(find "$mount" -xdev -type d -exec sh -c 'echo $(find "$0" -maxdepth 1 -type f | wc -l) "$0"' {} \; 2>/dev/null | sort -rn | head -5)
echo "Directorios con más archivos:"
echo "$top_dirs"
fi
done
Timer de systemd para monitoreo de disco (reemplaza cron)
# /etc/systemd/system/disk-monitor.service
[Unit]
Description=Monitoreo de uso de disco
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/disk-monitor.sh 80 admin@example.com
StandardOutput=journal
StandardError=journal
# /etc/systemd/system/disk-monitor.timer
[Unit]
Description=Ejecutar monitor de disco cada 5 minutos
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
AccuracySec=30s
[Install]
WantedBy=timers.target
# Habilitar e iniciar el timer
sudo systemctl daemon-reload
sudo systemctl enable --now disk-monitor.timer
systemctl list-timers disk-monitor.timer
Alertas de disco con Prometheus node_exporter
# prometheus-alerts.yml
groups:
- name: disk_usage
rules:
- alert: HighDiskUsage
expr: |
(1 - node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "Uso de disco alto en {{ $labels.instance }}"
description: "{{ $labels.mountpoint }} está al {{ printf \"%.1f\" $value }}% de uso"
- alert: CriticalDiskUsage
expr: |
(1 - node_filesystem_avail_bytes / node_filesystem_size_bytes) * 100 > 90
for: 2m
labels:
severity: critical
annotations:
summary: "Uso de disco crítico en {{ $labels.instance }}"
description: "{{ $labels.mountpoint }} está al {{ printf \"%.1f\" $value }}% de uso"
- alert: HighInodeUsage
expr: |
(1 - node_filesystem_files_free / node_filesystem_files) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "Uso de inodos alto en {{ $labels.instance }}"
description: "{{ $labels.mountpoint }} tiene {{ printf \"%.1f\" $value }}% de uso de inodos"
- alert: DiskWillFillIn24h
expr: |
predict_linear(node_filesystem_avail_bytes[1h], 24 * 3600) < 0
for: 10m
labels:
severity: critical
annotations:
summary: "El disco se llenará en 24h en {{ $labels.instance }}"
description: "{{ $labels.mountpoint }} predicho a llenarse según la tasa actual"
Limpieza automática con trigger de rotación de logs
#!/usr/bin/env bash
set -euo pipefail
CLEANUP_THRESHOLD="${1:-90}"
LOG_DIR="${2:-/var/log/app}"
ARCHIVE_DIR="${3:-/var/log/archive}"
df -Hl | awk 'NR>1 && /^\/dev/{print $1, $5, $6}' | while read -r fs usage mount; do
usage_val="${usage%\%}"
if (( usage_val >= CLEANUP_THRESHOLD )); then
echo "[$(date -Iseconds)] CRITICAL: $mount at $usage — disparando limpieza"
# Comprimir logs con más de 7 días
find "$LOG_DIR" -name "*.log" -mtime +7 -exec gzip -9 {} \;
# Mover logs comprimidos a archivo
find "$LOG_DIR" -name "*.gz" -mtime +1 -exec mv {} "$ARCHIVE_DIR/" \;
# Eliminar archivos con más de 90 días
find "$ARCHIVE_DIR" -name "*.gz" -mtime +90 -delete
# Limpiar caché del gestor de paquetes
if command -v apt-get &>/dev/null; then
apt-get clean
elif command -v yum &>/dev/null; then
yum clean all
fi
# Limpiar Docker si está presente
if command -v docker &>/dev/null; then
docker system prune -f --volumes
fi
# Reportar espacio liberado
new_usage=$(df -Hl "$mount" | awk 'NR>1 {print $5}')
echo "[$(date -Iseconds)] Limpieza completa. $mount ahora en $new_usage"
fi
done
Recursos Relacionados
Script de Rotación de Backups
Automatiza backups con políticas de retención usando un script de Bash que rota snapshots diarios, semanales y mensuales.
RecipeScripting en Bash para Automatizacion DevOps y Tareas de
Como escribir scripts Bash robustos para automatizar despliegues, monitoreo de sistemas, rotacion de logs y tareas de mantenimiento rutinarias
RecipeRotación y Compresión de Logs
Rota y comprime logs de aplicaciones con Bash para evitar que el disco se llene y simplificar la retención.
RecipeLoop Sobre Archivos en Bash
Cómo iterar de forma segura sobre archivos y directorios en Bash, manejando espacios, globs y listas grandes de archivos con patrones correctos.
RecipeEjecución Paralela en Bash
Cómo ejecutar comandos de shell en paralelo con xargs, GNU parallel y trabajos en segundo plano de Bash controlando la concurrencia y recolectando resultados.
RecipeConfigurar Reglas de Firewall con iptables
Configura reglas de firewall básicas usando iptables en Bash para filtrar tráfico, bloquear puertos y proteger servidores Linux.