Uso de disco al 100%: las causas reales (y las soluciones reales)

¿Te fue útil?

Sucede siempre en el peor momento: ventana de despliegue, el teléfono de guardia suena, los paneles alertan y alguien dice: “El disco está al 100%.” Esa afirmación es a la vez útil e incompleta. ¿Qué disco? ¿Qué sistema de archivos? ¿Espacio real, espacio reservado, inodos, pools con thin provisioning, o un montaje engañoso que ni siquiera es donde escribe tu app?

Equivocarse aquí no solo hace perder tiempo. Crea nuevos incidentes: borrar los archivos equivocados, corromper bases de datos o “arreglarlo” lo justo para que te vuelvan a avisar en una hora. Hagamos la versión adulta: identifica qué está realmente lleno, por qué se llenó y cómo arreglarlo sin apostar con tus datos.

Cuando “100% de disco” no significa lo que crees

“Uso de disco 100%” puede significar al menos ocho cosas distintas. Algunas son directas (“el sistema de archivos no tiene bloques libres”). Otras son traicioneras (“hay bloques libres pero no puedes usarlos”). Otras más son engañosas (“el espacio está libre, pero el kernel lo sigue reteniendo porque un proceso tiene el archivo abierto”). Si no distingues esto, harás el movimiento clásico: borrar un archivo, no ver espacio liberado, entrar en pánico y borrar más. Eso no es ingeniería. Es aleteo.

Empieza con la unidad de verdad: sistema de archivos vs dispositivo de bloque vs pool

Como mínimo, necesitas saber qué capa está llena:

  • Sistema de archivos (ext4/xfs/btrfs/dataset ZFS): archivos y directorios, inodos, bloques reservados, snapshots, cuotas.
  • Dispositivo de bloque (LVM LV, NVMe, volumen EBS): la capacidad subyacente; puede estar bien mientras el sistema de archivos no lo está (o viceversa).
  • Pool de almacenamiento (pool ZFS, thin pool LVM, Ceph): thin provisioning, metadatos, snapshots y la contabilidad “lógico vs físico”.
  • Capa de contenedores/overlay: Docker overlay2, snapshotters de containerd, almacenamiento efímero de Kubernetes; las escrituras no están donde crees.

Las tres lecturas erróneas más comunes

  1. Espacio vs inodos: “df dice lleno” es diferente de “df -i dice lleno.” Las soluciones son distintas.
  2. Archivos eliminados pero abiertos: borraste el archivo, pero el espacio no se libera hasta que el proceso que lo mantiene lo cierre.
  3. Snapshots y copy-on-write: “borraste” datos pero los snapshots siguen referenciando los bloques, así que el pool permanece lleno.

Broma #1: El disco es como un hotel. “Tenemos habitaciones vacías” no ayuda si todas las llaves siguen entregadas.

Guía de diagnóstico rápido (primero/segundo/tercero)

Esta es la versión para guardia. Prioriza: detener la hemorragia, identificar la verdadera restricción, evitar empeorar las cosas.

Primero: confirma qué está lleno y en qué capa

  1. Revisa uso del sistema de archivos en los montajes sospechosos: df -hT.
  2. Revisa uso de inodos: df -i.
  3. Revisa el dispositivo de bloque subyacente: lsblk -f y pvs/vgs/lvs si hay LVM implicado.
  4. Si es ZFS: revisa dataset y pool: zfs list, zpool list.
  5. Si hay contenedores: revisa almacenamiento overlay/contenedor: docker system df o crictl df.

Segundo: encuentra al consumidor rápido (¿qué creció?)

  1. Tamaños de directorios de primer nivel: du -xhd1 /mount (mantente en un solo sistema de archivos).
  2. Crecimiento reciente: ordena por tiempo de modificación: find ... -printf '%T@ %s %p\n'.
  3. Registros: journalctl --disk-usage, revisa /var/log y los directorios de logs de la aplicación.
  4. Fuga por archivos eliminados pero abiertos: lsof +L1.

Tercero: elige una solución segura según el modo de fallo

  • Archivos que realmente ocupan espacio: elimina/rota/mueve datos de forma segura, luego añade capacidad o reduce retención.
  • Inodos agotados: elimina millones de archivos pequeños (cache/temp), rediseña o reconstruye el sistema de archivos con más inodos (raramente agradable).
  • Snapshots: poda snapshots o cambia la política de snapshots. No borrres “archivos al azar” esperando magia.
  • Pool thin lleno: extiende el pool o elimina snapshots; trátalo como un evento de alto riesgo.
  • Eliminado pero abierto: reinicia/rota el servicio afectado limpiamente (o mátalo, si te gustan los postmortems).

Tareas prácticas: comandos, salidas, decisiones

Esto no es “prueba esto”. Cada tarea incluye: un comando ejecutable, qué te dice la salida y qué decisión tomar después. Asume Linux salvo que se indique lo contrario. Ejecuta como root cuando haga falta, pero no conviertas cada problema de disco lleno en un pasatiempo de escalada de privilegios.

Tarea 1: Identificar el sistema de archivos lleno (y su tipo)

cr0x@server:~$ df -hT
Filesystem                        Type   Size  Used Avail Use% Mounted on
/dev/mapper/vg0-root              ext4    80G   79G  0.6G  99% /
/dev/nvme0n1p1                    vfat   511M  7.2M  504M   2% /boot/efi
tmpfs                            tmpfs   32G   96M   32G   1% /run
/dev/mapper/vg0-var               xfs    200G  200G   20M 100% /var

Qué significa: /var está lleno y es XFS. Tus logs de base de datos, capas de contenedores y journals a menudo viven ahí.

Decisión: Enfócate en /var. No borres en / esperando que ayude. Toma nota también del tipo de sistema de archivos: XFS se comporta distinto a ext4 (no se encoje, comportamiento distinto en bloques reservados).

Tarea 2: Revisar agotamiento de inodos (el asesino silencioso)

cr0x@server:~$ df -i /var
Filesystem                 Inodes   IUsed   IFree IUse% Mounted on
/dev/mapper/vg0-var       13107200 13107190      10  100% /var

Qué significa: Básicamente no quedan inodos. Puedes tener bytes libres y estar muerto. Muchos archivos diminutos provocaron esto.

Decisión: Deja de buscar “archivos grandes”. Encuentra directorios con millones de entradas (caches, temp, colas de mail, capas de contenedor) y elimínalos de forma segura.

Tarea 3: Encontrar los directorios más grandes sin cruzar montajes

cr0x@server:~$ sudo du -xhd1 /var | sort -h
12M	/var/tmp
220M	/var/lib
1.6G	/var/cache
48G	/var/log
150G	/var/lib/docker

Qué significa: /var/lib/docker es enorme. Eso no es raro. También suele subestimarse.

Decisión: Investiga el almacenamiento de contenedores antes de borrar logs. Los logs pueden ser el síntoma y las capas Docker la causa, o al revés.

Tarea 4: Obtener la versión de la verdad de Docker

cr0x@server:~$ sudo docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          47        12        62.3GB    44.8GB (71%)
Containers      36        8         9.1GB     7.9GB (86%)
Local Volumes   18        11        81.4GB    12.6GB (15%)
Build Cache     119       0         24.7GB    24.7GB (100%)

Qué significa: El build cache es totalmente recuperable. Imágenes y contenedores detenidos también son recuperables. Los volúmenes son donde se esconde “datos que te importan”.

Decisión: Limpia primero el build cache (seguro), luego imágenes/contenedores no usados, y toca volúmenes solo si estás seguro de que son desechables.

Tarea 5: Recuperar de forma segura cache de Docker y artefactos no usados

cr0x@server:~$ sudo docker builder prune -af
Deleted build cache objects:
m1r4nd4d1g3st:sha256:0c5b...  215.3MB
m1r4nd4d1g3st:sha256:8e21...  112.9MB
Total reclaimed space: 24.7GB

Qué significa: Recuperaste espacio real sin tocar volúmenes persistentes.

Decisión: Revisa df de nuevo. Si sigue justo, procede con docker image prune y docker container prune. Programa una política de retención de imágenes para no repetir esto semanalmente.

Tarea 6: Encontrar archivos eliminados pero abiertos (el espacio no se libera)

cr0x@server:~$ sudo lsof +L1 | head
COMMAND   PID  USER   FD   TYPE DEVICE   SIZE/OFF NLINK  NODE NAME
java     2214  app    12w  REG  253,1  4294967296     0 90122 /var/log/app/server.log (deleted)
rsyslogd  912  syslog  7w  REG  253,1   2147483648     0 72311 /var/log/syslog (deleted)

Qué significa: Procesos mantienen abiertos archivos de log eliminados. El sistema de archivos no puede liberar bloques hasta que esos FD se cierren.

Decisión: Reinicia los servicios afectados o activa la rotación de logs de forma correcta. Matar procesos es el instrumento contundente; úsalo solo cuando no quede otra.

Tarea 7: Medir uso de journal de systemd y vaciarlo

cr0x@server:~$ sudo journalctl --disk-usage
Archived and active journals take up 18.0G in the file system.
cr0x@server:~$ sudo journalctl --vacuum-size=2G
Deleted archived journal /var/log/journal/4c.../system@0005b1d2....journal (8.0G).
Deleted archived journal /var/log/journal/4c.../system@0005b1d9....journal (6.0G).
Vacuuming done, freed 16.0G of archived journals.

Qué significa: Journald estaba acumulando historial. Ocurre en nodos ocupados y no es una falla moral.

Decisión: Establece una política persistente (SystemMaxUse= en la configuración de journald) una vez apagado el fuego. No sigas vaciando manualmente como estilo de vida.

Tarea 8: Encontrar archivos top rápidamente (por tamaño)

cr0x@server:~$ sudo find /var -xdev -type f -size +1G -printf '%s %p\n' | sort -nr | head
8589934592 /var/lib/docker/containers/1b.../1b...-json.log
4294967296 /var/log/app/server.log
2147483648 /var/lib/postgresql/15/main/pg_wal/000000010000000A000000FE

Qué significa: Los logs JSON de contenedores son enormes, además de un directorio de WAL de PostgreSQL que crece. Múltiples consumidores.

Decisión: Añade límites de log para el driver de logging de Docker; para PostgreSQL, revisa replicación/archivado y retención. No borres archivos WAL salvo que disfrutes reconstruir desde backups.

Tarea 9: Revisar presión en WAL de PostgreSQL y archivado

cr0x@server:~$ sudo -u postgres psql -c "select now(), pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(),'0/0')) as wal_since_boot;"
              now              | wal_since_boot
------------------------------+---------------
 2026-02-05 12:44:19.121+00   | 87 GB
(1 row)

Qué significa: Se han generado muchos WAL. No es automáticamente malo, pero es una pista.

Decisión: Comprueba si el archivado/replicación está atascado y provocando retención de WAL. Si no lo sabes, para y trae al DBA. Disco lleno más “improvisar con WAL” es la receta para incidentes emocionantes.

Tarea 10: Verificar salud del thin pool LVM (thin provisioning puede morder)

cr0x@server:~$ sudo lvs -a -o +devices,seg_monitor,metadata_percent,data_percent
  LV              VG   Attr       LSize   Pool  Origin Data%  Meta%  Move Log Cpy%Sync Convert Devices
  thinpool        vg0  twi-aotz--  500.00g             99.80  92.10                            /dev/sdb(0)
  vm-01           vg0  Vwi-aotz--   80.00g thinpool     74.20                                  thinpool(0)
  vm-02           vg0  Vwi-aotz--  120.00g thinpool     68.15                                  thinpool(0)

Qué significa: El thin pool está prácticamente lleno. Cuando un thin pool llega al 100%, las escrituras fallan de forma fea y sorprendente.

Decisión: Extiende inmediatamente el thin pool o libera espacio dentro de él (elimina snapshots/volúmenes thin no usados). Trátalo como urgente; no es “solo mantenimiento”.

Tarea 11: Confirmar restricciones en pool/dataset ZFS (cuotas, snapshots, reserva)

cr0x@server:~$ sudo zpool list
NAME   SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
tank   3.62T  3.55T  72.0G        -         -    39%    98%  1.00x  ONLINE  -

cr0x@server:~$ sudo zfs list -o name,used,avail,refer,mountpoint
NAME              USED  AVAIL  REFER  MOUNTPOINT
tank              3.55T  72.0G   128K  /tank
tank/app          2.40T  20.0G  2.10T  /tank/app
tank/app@daily-1   300G      -  2.10T  -

Qué significa: El pool está al 98%. El dataset tank/app solo tiene 20G disponibles. Existe un snapshot que puede estar fijando espacio.

Decisión: Evalúa retención de snapshots y elimina snapshots de forma segura si son la razón por la que el espacio no se libera. Además: no mantengas pools ZFS al 98% si te gustan los precipicios de rendimiento.

Tarea 12: Revisar bloques reservados en ext4 (root tiene espacio, usuarios no)

cr0x@server:~$ sudo tune2fs -l /dev/mapper/vg0-root | egrep 'Block count|Reserved block count|Reserved block percentage'
Block count:              20971520
Reserved block count:     1048576
Reserved block percentage: 5%

Qué significa: 5% del sistema de archivos está reservado (históricamente para proteger root y reducir fragmentación). En volúmenes grandes, eso pueden ser muchos GB.

Decisión: Si este es un volumen de datos (no root del sistema), considera reducir bloques reservados, pero hazlo deliberadamente. No “liberes espacio” quitando protecciones en volúmenes críticos sin un plan.

Tarea 13: Identificar creación desbocada de archivos (consumo de inodos) por directorio

cr0x@server:~$ sudo find /var -xdev -type d -printf '%p\n' | while read -r d; do echo "$(find "$d" -maxdepth 1 -type f 2>/dev/null | wc -l) $d"; done | sort -nr | head
1200345 /var/cache/myapp
410221 /var/lib/docker/overlay2
99521 /var/spool/postfix/maildrop

Qué significa: Un directorio de cache está generando un número absurdo de archivos. Ese es tu culpable de inodos.

Decisión: Purga la caché y arregla la política de caché de la aplicación (TTL, máximo de entradas, hashing de directorios). Considera también mover caches a tmpfs si es seguro, o a un sistema de archivos dedicado con planificación de inodos.

Tarea 14: Verificar puntos de montaje (evita limpiar el lugar equivocado)

cr0x@server:~$ mount | egrep ' /var | /var/lib/docker | / '
/dev/mapper/vg0-root on / type ext4 (rw,relatime)
/dev/mapper/vg0-var on /var type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,noquota)

Qué significa: Docker está bajo /var en este host. Si asumiste que vivía en otro LV, limpiarías el sistema de archivos equivocado y no aprenderías nada.

Decisión: Confirma montajes antes de actuar. Así evitas “borré 20G y no ayudó” porque borraste en el montaje equivocado.

Tarea 15: Rastrear qué está creciendo ahora mismo (cuando el disco se llena en vivo)

cr0x@server:~$ sudo bash -lc 'while true; do date; df -h /var; du -xhd1 /var/log | sort -h | tail -n 5; sleep 10; done'
Thu Feb  5 12:46:00 UTC 2026
Filesystem                Size  Used Avail Use% Mounted on
/dev/mapper/vg0-var       200G  199G  380M 100% /var
1.3G	/var/log/apt
4.8G	/var/log/nginx
16G	/var/log/journal
48G	/var/log
Thu Feb  5 12:46:10 UTC 2026
Filesystem                Size  Used Avail Use% Mounted on
/dev/mapper/vg0-var       200G  200G  120M 100% /var

Qué significa: El uso sigue aumentando. Esto no es “limpieza y listo”. Algo está escribiendo activamente.

Decisión: Identifica el escritor (logs, BD, uploads). Considera detener temporalmente el servicio o limitar la tasa de ingestión. Limpiar sin detener la fuente es la guerra de la fregona contra la inundación.

Las causas reales (con soluciones que perduran)

Causa 1: Los logs crecieron porque tu sistema es lo bastante saludable para seguir funcionando

Los logs son el comilón clásico porque están diseñados para no bloquear la carga principal. Eso está bien… hasta que no lo está. Disparadores comunes:

  • Logging en nivel debug activado tras un incidente.
  • Logs de acceso en un endpoint público durante una tormenta de escaneo.
  • Aplicaciones que registran cuerpos completos de peticiones (sí, hay quien lo hace en producción).
  • Systemd journal sin límite en nodos muy ocupados.

Soluciones reales:

  • Establece retención y límites de tamaño (logrotate, journald SystemMaxUse).
  • Envía logs fuera del host, pero no uses “los envío” como excusa para mantener logs infinitos en disco.
  • Haz los niveles de log configurables en tiempo de ejecución y por defecto con verbosidad sensata.

Causa 2: Archivos eliminados no liberaron espacio (descriptores abiertos)

La semántica Unix es elegante: quitar un nombre de archivo no borra el archivo subyacente hasta que nadie lo esté usando. En hosts ocupados, “nadie” puede tardar mucho.

Soluciones reales:

  • Usa lsof +L1 para encontrar archivos eliminados pero abiertos.
  • Reinicia el proceso de forma limpia (o forzadamente si es necesario).
  • Arregla la rotación de logs: asegúrate de que el servicio vuelva a abrir los logs (por ejemplo, con SIGHUP) tras la rotación.

Causa 3: Se agotaron los inodos (hay espacio pero no puedes crear archivos)

Los inodos son las “ranuras de archivo” del sistema de archivos. Si creas millones de archivos diminutos —fragmentos de cache, artefactos temporales, capas de imagen, colas de correo— puedes llegar al 100% de inodos mientras df -h sigue pareciendo bien. El síntoma suele ser “No space left on device” con un uso de bytes ridículamente bajo.

Soluciones reales:

  • Elimina directorios con conteo alto de archivos (cache, temp) y corrige al productor.
  • Usa menos archivos: empaqueta objetos, usa SQLite/LMDB o rediseña el layout de caché.
  • En casos extremos: reconstruye el sistema de archivos con más inodos (planificar con ext4 -N) o cambia a un FS más adecuado para la carga.

Causa 4: Snapshots fijaron bloques (especialmente en sistemas CoW)

En ZFS y btrfs, los snapshots no son “gratuitos”. Son baratos, pero no gratis. Borrar un archivo no libera necesariamente sus bloques si un snapshot los referencia. Esto es comportamiento correcto. También es confuso a las 3 a.m.

Soluciones reales:

  • Revisa políticas de snapshot: frecuencia, retención y qué datasets incluyen.
  • Poda snapshots para liberar espacio.
  • Mantén margen libre; los sistemas CoW se vuelven quisquillosos cuando están casi llenos (presión de metadatos, fragmentación).

Causa 5: Thin provisioning agotó el espacio real

Los thin pools LVM, datastores de VM y muchos SAN permiten asignar más espacio “virtual” del que físicamente tienes. Está bien hasta que no lo está. Cuando el pool choca contra el muro, las escrituras fallan de formas que las aplicaciones interpretan como corrupción, timeouts o “disco lleno” en el lugar equivocado.

Soluciones reales:

  • Monitorea uso de datos y metadatos del thin pool y alerta con antelación.
  • Extiende el pool antes de que llegue al 100%. Al 99% ya estás tarde.
  • Limita la proliferación de snapshots. Los snapshots son un instrumento de deuda con interés compuesto.

Causa 6: El almacenamiento overlay/contenerizado creció en silencio

Los contenedores hacen que el uso de disco se sienta abstracto. Imágenes, capas, caches de build y logs JSON se apilan. Kubernetes empeora esto al repartir la responsabilidad entre nodos, namespaces y “no es mi problema”.

Soluciones reales:

  • Establece límites de tamaño para los drivers de logs de contenedores.
  • Haz garbage collect de imágenes y caches de build en un horario.
  • Usa particiones dedicadas para almacenamiento de contenedores para que no asfixien al SO.
  • Configura requests/limits de almacenamiento efímero en Kubernetes y hazlos cumplir.

Causa 7: Espacio reservado y cuotas (está lleno para ti, no para root)

En ext4 existen bloques reservados por buenas razones. En ZFS, cuotas y reservas pueden hacer que un dataset parezca lleno mientras el pool tiene espacio, o viceversa. En XFS, las cuotas por proyecto pueden limitar directorios silenciosamente. No es un bug. Es política.

Soluciones reales:

  • Revisa configuraciones de cuotas y espacio reservado antes de borrar nada.
  • Ajusta la política con intención: quién puede llenar el disco y quién debe estar protegido.

Causa 8: “df dice lleno” pero “du no lo encuentra” (desajuste de contabilidad)

Este es el caso de dolor de cabeza: df informa bloques usados, pero du no muestra archivos correspondientes. Razones comunes:

  • Archivos eliminados pero abiertos (otra vez).
  • Metadatos del sistema de archivos y crecimiento de journal.
  • Snapshots (ZFS/btrfs).
  • Asignación de bloques en archivos sparse o archivos de BD prealocados.

Solución real: Usa la herramienta correcta para la capa correcta. Si tratas todo el uso de disco como “archivos en directorios”, estás ciego a la mitad del sistema.

Una cita, porque pertenece aquí: Todo falla, todo el tiempo. — Werner Vogels

Tres micro-historias corporativas desde el terreno

Micro-historia 1: El incidente causado por una suposición equivocada

Tenían una flota de servidores de aplicación con un “disco grande de datos” adjunto. Todos sabían la regla: los logs van al disco grande. El runbook incluso lo decía. El equipo hizo lo sensato durante un incidente: hicieron tail de logs, vieron una tormenta de errores y rotaron un log masivo. El disco siguió al 100%.

Alguien escaló a storage. Storage miró df -hT y suspiró. El disco grande estaba montado en /data, pero el archivo de servicio de la aplicación se había actualizado meses antes. La ruta de logs cambió silenciosamente a /var/log/app—en el filesystem root. El “disco grande” estaba inactivo e inocente.

La suposición equivocada fue social, no técnica: “la configuración no puede derivar porque existe el runbook.” Derivó de todas formas. La solución no fue un script heroico. Fue: corregir la configuración del servicio, reiniciar limpiamente y añadir una comprobación de arranque que se niegue a ejecutar si el montaje esperado no está presente.

También cambiaron el runbook: el primer paso pasó a ser “verificar montajes y rutas”, no “rotar logs”. La próxima vez el síntoma apareció, el diagnóstico tomó minutos, no una tarde de conjeturas confiadas.

Micro-historia 2: La optimización que salió mal

Un ingeniero orientado al rendimiento decidió acelerar builds cacheando todo en los runners de CI. Cache de build de Docker, caches de paquetes de lenguajes, artefactos de test—si se podía cachear, se cacheaba. Las builds se hicieron más rápidas. Todos celebraron. Luego los runners empezaron a fallar en oleadas.

No era CPU. No era memoria. Era disco. Pero no “archivos grandes”. Inodos. Millones de objetos de cache diminutos repartidos en directorios diseñados por gente que nunca tuvo que correr una granja de runners compartida.

La primera respuesta fue predecible: “Añade discos más grandes.” Ayudó una semana. Luego los inodos llegaron al 100% otra vez, porque el conteo de inodos no escala automáticamente con “simplemente añade un volumen más grande” como la gente asume. Estaban subiendo capacidad y seguían hambrientos de ranuras de archivo.

La optimización fallida enseñó una lección aburrida: el caching necesita presupuestos. La solución eventual fue poco glamorosa y efectiva—tamaños de cache acotados, pruning periódico y mover ciertos caches a tarballs en lugar de crear una tormenta de archivos. Las builds siguieron siendo suficientemente rápidas y los runners dejaron de morir por mil cortes pequeños.

Micro-historia 3: La práctica aburrida pero correcta que salvó el día

Otra organización manejaba un clúster de bases de datos donde los discos estaban dimensionados con conservadurismo y las alertas se configuraron al 70%, 80% y 85%. La gente se quejaba de que las alertas eran ruidosas. La dirección quería que fueran “menos sensibles”. El equipo SRE no cedió.

Un fin de semana, un consumidor downstream se quedó atascado y la réplica acumuló lag. Empezaron a acumularse WAL. La alerta del 70% saltó. El on-call miró, vio la tendencia y abrió un incidente antes de que los clientes notaran nada.

El equipo tuvo tiempo para hacer las cosas seguras: diagnosticar por qué el consumidor estaba atascado, aumentar capacidad temporalmente y ajustar los knobs de retención sin improvisar. Nadie borró archivos aleatorios de base de datos. Nadie “liberó espacio” borrando la única copia de algo importante.

Cuando el disco habría llegado al 100%, el sistema ya estaba estable. La política de alertas se veía aburrida en un dashboard. En la práctica, fue la diferencia entre una respuesta controlada y un seminario nocturno sobre recuperación de datos.

Errores comunes: síntoma → causa raíz → solución

1) “Borré 20 GB, pero df no cambió”

Síntoma: du muestra menos, pero df sigue reportando lleno.

Causa raíz: Archivos eliminados pero abiertos (o snapshots en sistemas CoW).

Solución: lsof +L1, reinicia el proceso que lo mantiene; para snapshots, poda snapshots y valida la liberación de espacio a nivel de pool/dataset.

2) “No space left on device” pero df muestra espacio suficiente

Síntoma: Escrituras fallan; df -h muestra GB libres.

Causa raíz: Inodos agotados, o cuota alcanzada.

Solución: df -i; identifica directorios con muchos archivos; limpia caches; revisa y ajusta cuotas.

3) “Solo / está lleno, pero el disco de datos está vacío”

Síntoma: El filesystem raíz llega al 100%; el almacenamiento adjunto tiene espacio.

Causa raíz: Ruta equivocada, montaje faltante o aplicación escribiendo en la ubicación por defecto tras fallo de montaje.

Solución: Verifica montajes (mount, findmnt), exige montajes al iniciar servicios, usa rutas absolutas y prueba el comportamiento al reiniciar.

4) “El uso de disco salta durante backups/snapshots y nunca baja”

Síntoma: El uso aumenta tras backups basados en snapshots.

Causa raíz: Retención de snapshots demasiado larga, o backups fijando snapshots; retención de bloques CoW.

Solución: Audita calendario/retención de snapshots, asegúrate de que los backups expiran snapshots, mantén margen y monitorea referenciado vs usado (las propiedades de ZFS ayudan).

5) “Después de activar debug, los discos empezaron a llenarse cada día”

Síntoma: Crecimiento sostenido de logs; la aplicación por lo demás estable.

Causa raíz: Volumen de logging sin límites; rotación de logs faltante o mal configurada.

Solución: Limita logs, implementa rotación y centraliza envío de logs con retención local sensata.

6) “Extendimos el volumen pero sigue al 100%”

Síntoma: Volumen en la nube redimensionado; df sin cambios.

Causa raíz: El dispositivo de bloque creció pero no se expandió el sistema de archivos, o se redimensionó la capa equivocada (por ejemplo, PV pero no LV, LV pero no FS).

Solución: Confirma con lsblk; expande PV/LV/FS apropiadamente (p. ej., pvresize, lvextend, xfs_growfs / resize2fs).

7) “Un pool thin-provisioned llegó al 100% y todo se puso raro”

Síntoma: Fallos de escritura aleatorios, errores de sistema de archivos, pausas de VMs.

Causa raíz: Thin pool sin datos o metadatos.

Solución: Extiende el thin pool inmediatamente; reduce snapshots; implementa alertas mucho antes del 90%.

Broma #2: Si ejecutas un sistema de archivos al 100% y “está bien”, es solo porque aún no ha mirado su correo.

Listas de verificación / plan paso a paso

Checklist A: Incidente en vivo (el disco está al 100% ahora mismo)

  1. Detén la hemorragia: Si un solo servicio escribe sin control, limita su tasa o deténlo. Mantén vivo el host.
  2. Confirma el objetivo lleno: df -hT y df -i en el montaje.
  3. Identifica la capa: sistema de archivos vs thin pool vs pool ZFS vs overlay de contenedores.
  4. Encuentra los mayores consumidores: du -xhd1 y find dirigido para archivos grandes.
  5. Revisa archivos eliminados pero abiertos: lsof +L1.
  6. Aplica la recuperación más segura primero:
    • Vaciar journals
    • Podar build cache
    • Rotar/comprimir logs correctamente
    • Eliminar caches conocidos y seguros
  7. Revisa de nuevo: df y salud de servicios tras cada cambio.
  8. Sólo entonces considera ampliar capacidad o mover datos.

Checklist B: Después del incidente (prevenir la secuela)

  1. Escribe qué llenó el disco en una frase (ejemplo: “Build cache de Docker y logs JSON, sin límites”).
  2. Añade monitorización y alertas para:
    • Espacio e inodos de sistemas de archivos
    • Datos y metadatos de thin pool
    • Capacidad y fragmentación de pools ZFS
    • Uso de almacenamiento de contenedores
  3. Establece presupuestos de retención: logs, artefactos, backups, snapshots, caches.
  4. Haz montajes exigibles: el servicio se niega a iniciar si el filesystem requerido no está montado.
  5. Ejecuta un game day: simula presión de disco y valida el runbook.

Checklist C: Decisiones de diseño de almacenamiento que reducen incidentes de disco lleno

  • Pon /var, almacenamiento de contenedores y bases de datos en filesystems separados cuando sea posible. El radio de impacto importa.
  • Prefiere rutas de crecimiento predecibles: planificación de capacidad vence a la limpieza de emergencia.
  • Mantén margen: apunta a 20–30% libre en filesystems ocupados; más para CoW y workloads pesados en metadatos.
  • Asume que los snapshots son datos de producción. Trátalos con la misma seriedad que los backups.
  • No uses thin provisioning sin monitorización de primera clase y procedimientos de expansión probados.

Datos interesantes y contexto histórico

  • Bloques reservados en sistemas ext se introdujeron para mantener el sistema utilizable para root y reducir la fragmentación cuando los discos se llenan.
  • Los inodos se prealocan en muchos sistemas de archivos tradicionales (como ext4). Puedes quedarte sin entradas de archivo independientemente de los bytes.
  • El comportamiento “eliminado pero abierto” es una decisión de diseño core de Unix: los nombres son entradas de directorio; el archivo vive hasta la última referencia.
  • XFS se diseñó para hierro grande (alto throughput, sistemas de archivos grandes). Es rápido, pero encogerlo no es algo que hagas un martes.
  • Snapshots copy-on-write (ZFS/btrfs) cambian snapshots fáciles por una contabilidad de espacio más compleja bajo presión.
  • La rotación de logs existe porque los discos son finitos, algo tan cierto en discos de 40 MB como en volúmenes de varios terabytes.
  • El thin provisioning llegó a mainstream porque mejoró la utilización, pero transformó “capacidad” en un problema de monitorización y gobernanza.
  • El comportamiento de un filesystem lleno es no lineal: el rendimiento y las tasas de fallo pueden degradarse bruscamente cerca del full, especialmente con espacio libre fragmentado y churn de metadatos.

Preguntas frecuentes

¿Por qué mi sistema se ralentiza cuando el disco está casi lleno?

El espacio libre se fragmenta, las operaciones de metadatos se vuelven más costosas y los sistemas CoW pueden amplificar las escrituras. Casi lleno es donde las suposiciones del “caso promedio” mueren.

¿Por qué du no suma lo que muestra df?

du recorre árboles de directorios y suma tamaños de archivos que puede ver. df reporta bloques asignados. Archivos eliminados pero abiertos, snapshots y metadatos pueden hacer que no coincidan.

¿Es seguro borrar archivos en /var/log?

A veces. Prefiere rotar y comprimir mediante las herramientas de logging del sistema. Si borras un log que un proceso está manteniendo abierto, puede que no recuperes espacio hasta que el proceso lo reabra.

¿Puedo simplemente borrar archivos WAL de PostgreSQL para liberar espacio?

No, no como táctica operativa normal. WAL forma parte de la durabilidad y replicación. La aproximación segura es arreglar archivado/replicación, ajustar retención o añadir capacidad. Si ya estás en desastre, trae a expertos en BD.

¿Cuál es la forma más rápida y segura de recuperar espacio en un host Docker?

Empieza con el build cache: docker builder prune -af. Luego podar imágenes y contenedores no usados. Ten cuidado con los volúmenes; a menudo contienen datos reales.

¿Cómo sé si es un problema de inodos?

Ejecuta df -i en el montaje afectado. Si IUse% está cerca del 100%, necesitas eliminar muchos archivos pequeños o rediseñar la carga, no buscar archivos grandes.

¿Por qué ZFS muestra espacio usado incluso después de borrar directorios grandes?

Los snapshots pueden seguir referenciando esos bloques, así que el pool no puede liberarlos. Revisa la lista y retención de snapshots. Además mantén margen; ZFS rinde mal cuando está muy lleno.

¿Qué umbrales de alerta deberíamos usar para uso de disco?

Depende de la tasa de crecimiento y tiempo de recuperación. Un baseline práctico: advertir al 70–80%, alertar al 85–90% en sistemas críticos. Los CoW y pools thin merecen alertas más tempranas.

¿Debemos separar /var de /?

Sí, en la mayoría de hosts de producción. /var es donde ocurre el crecimiento (logs, caches, datos de contenedores). Separarlo reduce la probabilidad de que una carga ruidosa deje el SO inservible.

¿Cuál es el objetivo de borrado de emergencia más “seguro”?

Caches recuperables que puedas regenerar: build cache, caches de paquetes, archivos temporales, logs rotados antiguos, journals viejos. Evita tocar archivos de bases de datos en vivo o directorios desconocidos bajo presión.

Siguientes pasos para evitar reincidencias

Arreglar uso de disco al 100% no es cuestión de heroísmo. Es identificar la capa que está llena, usar las herramientas correctas para encontrar el consumidor real y aplicar cambios que no reboten.

  1. Adopta la guía de diagnóstico rápido y hazla memoria muscular: df -hT, df -i, du -x, lsof +L1, luego chequeos específicos de capa (Docker/ZFS/LVM thin).
  2. Pon presupuestos en todas partes: retención de logs, límites de journal, retención de snapshots, tamaños de cache, políticas de ciclo de vida de imágenes.
  3. Diseña pensando en el radio de impacto: filesystems separados para SO, logs, contenedores y BDs; exige montajes al inicio.
  4. Monitorea lo que importa temprano: espacio, inodos, datos/metadatos de thin pool, crecimiento de snapshots y directorios top por uso.
  5. Mantén margen deliberadamente: “Correr al 95% todo el tiempo” no es ahorro; es respuesta a incidentes pospuesta.

Los incidentes por disco lleno rara vez son misteriosos. Normalmente son deuda operativa impaga, que llega con intereses y exige pago inmediato.

← Anterior
Bucle OOBE / «Algo salió mal»: Soluciones rápidas para desastres de configuración
Siguiente →
Arreglar DNS en Windows: deja de usar “flushdns” como un ritual

Deja un comentario