Limpieza de Overlay2 de Docker: Recupera Espacio en Disco con Seguridad (2026)
Limpieza de overlay2 de Docker: recupera espacio en disco con docker system prune, límites de logs y comprobaciones del store de containerd. Evita que /var/lib/docker/overlay2 llene tu disco.
Actualizado Publicado 27 min de lectura

No borres carpetas de overlay2 a mano
Nunca borres nada dentro de /var/lib/docker/overlay2 o /var/lib/containerd manualmente. Esas carpetas con nombres hash son los metadatos vivos de Docker. Borrarlas a mano corrompe imágenes y rompe contenedores en ejecución. Si te preguntas “¿es seguro borrar /var/lib/docker/overlay2?”, la respuesta es no. Usa los comandos de limpieza de Docker soportados en esta guía, y solo toma acciones de “resetear el directorio de datos de Docker” si entiendes por completo el radio de explosión.
La limpieza de overlay2 de Docker es lo que necesitas cuando /var/lib/docker/overlay2 se come el disco y Docker empieza a fallar en las escrituras. Esta guía muestra cómo recuperar espacio en disco de forma segura: la familia docker system prune, límites de logs de contenedores, y un checkpoint del backend de almacenamiento que no deberías saltarte. Desde Docker Engine 29, las instalaciones nuevas guardan las imágenes en /var/lib/containerd, así que puede que el directorio que llena tu disco ni siquiera sea overlay2. Abajo está el camino completo: identifica el backend, mide, poda, arregla los logs, diagnostica restos, previene que vuelva a crecer.
Paso 0: ¿Qué backend de almacenamiento? (overlay2 vs store de imágenes containerd)
Antes de cualquier limpieza, averigua dónde guarda Docker sus datos realmente. Es una comprobación de solo lectura:
docker info -f '{{ .DriverStatus }}'Dos resultados posibles:
- La salida contiene
[[driver-type io.containerd.snapshotter.v1]]→ estás en el store de imágenes containerd. Tus datos viven bajo/var/lib/containerd. - La salida muestra un estado de driver overlay2 normal → estás en el store overlay2 heredado. Tus datos viven bajo
/var/lib/docker/overlay2.
Docker Engine 29 cambió el almacenamiento por defecto
Docker Engine 29.0 (octubre de 2025) convirtió el store de imágenes containerd en el default en instalaciones nuevas. Los daemons actualizados mantienen el graphdriver overlay2 heredado hasta que cambies explícitamente. Los hosts con userns-remap están excluidos del nuevo default. Últimas versiones al escribir: Engine v29.9.0 (08-10-2026), buildx v0.38.0 (07-10-2026).
Si estás a punto de montar una máquina nueva y quieres los defaults actuales documentados de principio a fin, instala Docker y Docker Compose en Ubuntu ARM primero, luego vuelve aquí.
Store overlay2 heredado
# what to watch
du -sh /var/lib/docker/overlay2
# what Docker reports
docker system dfLa mayor parte de esta guía apunta a este store. Los comandos de poda de abajo funcionan igual, pero los nombres de directorio en overlay2 son los que mapearás después.
Store de imágenes containerd
# what to watch
du -sh /var/lib/containerd
# what Docker reports (still authoritative)
docker system dfdocker system df sigue siendo la fuente de verdad para las categorías. containerd mantiene tanto blobs comprimidos como snapshots desempaquetados, así que las mismas imágenes cuestan más disco que en el store heredado. Los docs de Docker dicen “usa más espacio en disco” sin un multiplicador, y no voy a inventarme uno.
Verifica: pega la salida real de docker info -f '{{ .DriverStatus }}' en tus notas antes de podar. Quieres una línea base de qué store está activo.
Modo de fallo: “Podé overlay2 y no se recuperó nada.” En un host con store containerd estabas mirando el store inactivo. Los comandos de poda del store activo no tocan los datos del otro backend (mira la sección del store oculto más abajo).
Contexto de versiones, corto: el mundo viejo se ha ido. AuFS y el driver overlay heredado se eliminaron en Engine v24, devicemapper en v25, los plugins de graphdriver en v28 (consejo oficial de reemplazo: usa el store de imágenes containerd). Engine v29 requiere API v1.44 o más nueva. Si tus notas de limpieza son anteriores a 2023, reléelas antes de ejecutar nada.
Qué hay dentro de /var/lib/docker/overlay2
overlay2 es el filesystem copy-on-write de Docker para Linux. El directorio contiene:
- Directorios de capas: carpetas direccionadas por contenido con los diffs reales del filesystem
- Datos “upperdir” de contenedores: las capas escribibles donde los contenedores escriben archivos. Esto es normalmente lo que crece
- Metadatos y enlaces: estructuras que Docker usa para rastrear qué capas pertenecen a qué imágenes
Los nombres de las carpetas son hashes aleatorios, no identificadores legibles. No puedes mirar el nombre de una carpeta y saber a qué imagen pertenece. Usa comandos Docker en vez de adivinar por nombres de directorio. Docker mantiene este layout deliberadamente sin documentar.
En hosts con store containerd los internos equivalentes viven bajo /var/lib/containerd como un content store más snapshots overlayfs. Misma regla: mide con comandos Docker y du, no navegando carpetas hash.
Ese mapa vale la pena tenerlo en la cabeza. El resto de esta guía recorre cada caja: mídela, límpiala, y luego evita que vuelva.
Por qué /var/lib/docker/overlay2 crece tanto
El directorio crece por un puñado de razones predecibles:
- Imágenes y contenedores sin usar: los contenedores parados y las imágenes viejas siguen ocupando espacio si no los eliminas.
- Caché de build: Docker cachea capas para hacer los builds más rápidos. En una máquina que construye a menudo, esta caché es el principal culpable.
- Imágenes y contenedores grandes: algunas imágenes traen binarios o archivos de datos grandes. Cuatro copias de una imagen base de 1,5 GB suman.
- Capas de imagen ineficientes: imágenes con demasiadas capas o basura de build sobrante desperdician espacio. Si controlas el Dockerfile, copia múltiples archivos en una capa con un Docker COPY en vez de apilar un
COPYpor archivo. - Logs de contenedores sin límite: este es el escurridizo. El driver de logs json-file crece sin límite por defecto, y los archivos no están en overlay2. Viven en
/var/lib/docker/containers/. Hay una sección dedicada abajo.
En hosts con store containerd, añade una más: los blobs más los snapshots desempaquetados hacen que el mismo conjunto de imágenes cueste más disco que el store heredado.
Si quieres ver qué categoría crece realmente con el tiempo, monitoriza recursos del servidor y Docker (CPU, memoria, disco) en vez de correr du a mano cada semana.
Nota de ops: un filesystem lleno no solo rompe los pulls de Docker. Los contenedores de bases de datos también pierden escrituras, y algunos de esos fallos son silenciosos hasta que la app da error. Apunta a un 15-20% de espacio libre en cualquier host que corra contenedores con estado.
Comprueba primero el uso de disco de Docker
Haz esto antes de tocar nada. Es de solo lectura.
docker system df
docker system df -vdocker system df muestra el uso de espacio para imágenes, contenedores, volúmenes y caché de build. El flag -v añade detalle por objeto. Para scripts de monitorización, añade --format json (o una plantilla Go) para parsear en vez de raspar tablas.
Luego comprueba el filesystem real:
df -h /var/lib/docker
du -sh /var/lib/docker/overlay2 /var/lib/docker/containers /var/lib/containerd 2>/dev/nullPara ver qué subdirectorios de overlay2 son los más grandes, solo para investigación, nunca para borrado:
du -sh /var/lib/docker/overlay2/* 2>/dev/null | sort -hr | head -10Cómo leer la salida:
- Un uso grande de
overlay2suele significar escrituras de contenedores o caché de build, no solo imágenes sin usar. - Céntrate en la categoría que crece en
docker system df -v(imágenes, contenedores, volúmenes, caché de build), no en IDs específicos. - Guarda la salida de
docker system df -vantes de limpiar. Esa es tu línea base; compararás contra ella después.
Síntoma → causa probable → primer comando
| Síntoma | Causa probable | Primer comando |
|---|---|---|
| overlay2 enorme en un host Docker 29 | store heredado oculto tras un cambio de backend | docker info -f '{{ .DriverStatus }}', luego evalúa o mueve el store viejo |
Archivos *-json.log enormes |
logging json-file sin límite | du -sh /var/lib/docker/containers/* | sort -hr | head |
docker system df muestra 0% recuperable |
capas escribibles activas e imágenes en uso | docker ps -s: escala el disco, no podes más fuerte |
| la poda corrió, poco recuperado | volúmenes nombrados; caché viviendo en buildx | docker system df -v, luego apunta a las filas de volúmenes y caché de build |
builder prune: flag desconocido --keep-storage |
tutoriales viejos vs buildx nuevo | docker builder prune --help, luego usa --max-used-space |
Limpieza de Overlay2 de Docker: el playbook de poda
Esta es la limpieza ordenada, de más segura primero. Cada comando dice qué elimina. Ejecuta uno, comprueba docker system df, luego decide si necesitas el siguiente. Es más lento que lanzarlo todo a la vez y mucho más fácil de explicar cuando desaparece algo que querías.
Victoria rápida: docker system prune (y -a)
Empieza con el informe de solo lectura otra vez para tener números frescos:
docker system df -vElimina contenedores parados, redes sin usar, imágenes colgantes y caché de build:
docker system prune -fQué hace: limpia objetos que nada referencia. Qué no hace: tocar volúmenes nombrados, y mantiene imágenes a las que algún contenedor (incluso parado) todavía apunta.
Si también quieres eliminar todas las imágenes no usadas por ningún contenedor, que es el paso más agresivo:
docker system prune -a -fModo de fallo: -a elimina imágenes que un contenedor parado-pero-deseado necesita en su próximo arranque. Nada se corrompe, pero pagas el tiempo de re-pull en el peor momento. En hosts con contenedores que guardas para rollback, sáltate -a o córrelo dentro de una ventana de mantenimiento.
Para mantenimiento programado en máquinas de build, los filtros mantienen la poda honesta:
docker system prune -af --filter until=168huntil= acepta timestamps RFC3339, fechas, o duraciones Go como 10m y 24h. label= selecciona por etiqueta. Múltiples filtros entre claves distintas se combinan con AND. Un cron semanal con until=168h es un default aburrido y fiable para runners de CI.
Si quieres el playbook de demolición completo para imágenes, volúmenes, redes y discos, mira cómo limpiar todas las imágenes Docker con discos y todo.
Verifica: docker system df tras cada comando. En hosts con store containerd, ten en cuenta que builds viejos de Engine 29 sub-reportaban el espacio recuperado porque ignoraban los datos de imagen desempaquetados (moby#52905, corregido en un patch posterior de v29). Los números confusos ahí eran un bug, no un error tuyo.
Volúmenes: anónimos vs nombrados (docker volume prune -a)
Esta es la parte que las guías viejas hacen mal, y es por lo que la gente busca “docker volume prune no recupera espacio”.
Desde Docker Engine 23.0 / API 1.42, docker volume prune elimina solo volúmenes anónimos. Los volúmenes nombrados necesitan el flag -a:
docker volume prune -f # anonymous volumes only
docker volume prune -a -f # ALSO unused named volumes, check first!Misma advertencia para docker system prune --volumes: el aviso oficial dice que elimina “todos los volúmenes anónimos no usados por al menos un contenedor”. Los volúmenes nombrados sobreviven.
Comprueba antes de borrar nada:
docker volume ls
docker system df -vLos volúmenes nombrados contienen datos reales
docker volume prune -a elimina volúmenes nombrados sin usar. Bases de datos, subidas y estado viven ahí. Si un proyecto compose está parado y podas volúmenes nombrados, esos datos se han ido. Haz backup del volumen o confirma que es desechable antes de correr -a. Esta es la clásica historia de “borramos datos de producción”.
Verifica: docker volume ls antes, docker system df después. Si la fila de volúmenes apenas se movió tras docker volume prune -f, es esperado: tu espacio está en volúmenes nombrados, y solo -a los recuperará.
Caché de build: docker builder prune con topes de capacidad
Si construyes imágenes en el host, la caché de BuildKit es a menudo la categoría individual más grande. Pódala directamente:
docker builder prune -f # dangling cache
docker builder prune -af # all unused cacheEl buildx más nuevo (v0.38.0 a 10-2026) añade topes de capacidad, que son mejores que esperar a las alarmas de disco lleno:
docker builder prune -f --max-used-space 10gb # LRU-evict down to 10 GB
docker builder prune -f --min-free-space 20gb # keep 20 GB free on the filesystem
docker builder prune -f --reserved-space 5gb # never evict the last 5 GB of cache
docker builder prune -f --filter until=168h # cache older than 7 days
docker buildx prune -a --max-used-space 10gb # also internal/frontend imagesLos tamaños son legibles y no distinguen mayúsculas (10gb, 500MB). Los filtros incluyen type=, type!=exec.cachemount (mantén cache mounts, normalmente lo que quieres), until=, description=, y parent=. Múltiples flags --filter se combinan con AND.
Si self-hosteas CI, self-hostea tu Git y CI/CD con Forgejo y Woodpecker CI y pon la poda --max-used-space en un timer semanal en el runner. Ahí es donde la caché de build se vuelve salvaje.
Modo de fallo: unknown flag: --keep-storage. Los tutoriales viejos lo usan; la tabla actual de opciones de buildx prune no lo lista. Ejecuta docker builder prune --help en tu host y usa el flag de capacidad que tu versión tenga realmente (--max-used-space en buildx reciente). No recuperar nada en una máquina fresca es normal, no un bug.
Verifica:
docker builder prune --help | grep -E 'max-used|keep-storage'Luego re-ejecuta docker system df y compara la fila de Build Cache contra tu línea base.
El verdadero asesino de disco: los logs de contenedores Docker
Los logs de contenedores son el problema de disco que ninguna limpieza de overlay2 arreglará. El driver de logs json-file por defecto escribe en /var/lib/docker/containers/<id>/<id>-json.log y crece sin límite (max-size va por defecto a -1, max-file a 1). Una app habladora en un VPS pequeño puede llenar el disco en días mientras docker system df parece casi limpio.
Encuentra a los culpables:
du -sh /var/lib/docker/containers/* 2>/dev/null | sort -hr | head
docker ps -sdocker ps -s muestra el tamaño de la capa escribible de cada contenedor, lo que te dice si el bulto son logs o escrituras de la app.
Emergencia (ahora)
Trunca, no borres. Borrar el archivo rompe el file handle y el espacio no se libera hasta que el contenedor se reinicia. Truncar es práctica común en el campo (no está en los docs oficiales, así que prueba en tu host primero):
truncate -s 0 /var/lib/docker/containers/*/*-json.logLa recuperación es inmediata. El contenedor sigue escribiendo al mismo handle.
Permanente (daemon.json)
Pon rotación de logs en /etc/docker/daemon.json. Los valores deben ser strings:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}Luego reinicia Docker:
sudo systemctl restart dockerCada contenedor mantiene como máximo 3 archivos de 10 MB. Cambia los números a tu gusto; solo pónles un tope.
los log-opts aplican solo a contenedores nuevos
Reiniciar el daemon aplica las nuevas opciones de logs solo a contenedores recién creados. Los contenedores existentes mantienen logging ilimitado hasta que los recrees. Para apps Compose, actualiza un contenedor con Docker Compose (docker compose up -d --force-recreate) para que los nuevos log-opts hagan efecto.
Si prefieres enviar los logs a un sitio central en vez de rotarlos localmente, redirige los logs de Docker a un único archivo con un driver de logs distinto.
Verifica:
du -sh /var/lib/docker/containers
docker inspect <container> --format '{{ json .HostConfig.LogConfig }}'Un contenedor nuevo debería mostrar "max-size":"10m" y "max-file":"3".
Modo de fallo: editaste daemon.json, reiniciaste Docker, y los logs siguen creciendo. Los contenedores viejos nunca fueron recreados. Comprueba docker inspect en uno de ellos; si la config de logs sigue vacía, el archivo no se re-leyó para ese contenedor.
Mapear directorios overlay2 a objetos Docker
A veces necesitas saber qué contenedor posee una capa escribible gigante. Usa la propia salida de Docker antes de cualquier scripting:
docker ps -s
docker inspect -f '{{ .Name }} {{ .GraphDriver.Data.UpperDir }}' $(docker ps -aq)GraphDriver.Data.UpperDir es la ruta de la capa escribible directamente de docker inspect. Es un mapeo soportado, y la forma más rápida de casar un directorio enorme con un nombre de contenedor.
Para imágenes versus directorios de capas, tengo un script auxiliar que visualiza el uso de disco de overlay2:
curl -sSL https://utils.bitdoze.com/scripts/docker-overlay2-view.sh | bashTodos los scripts están en utils.bitdoze.com.
Guía, no una lista de borrado
Este mapeo es best-effort. overlay2 es una estructura interna, y no todo directorio tiene una relación limpia de “esto pertenece a la imagen X”. El script cubre solo el store overlay2 heredado. En un host con store containerd docker inspect no devuelve rutas overlay2, así que una salida vacía ahí es esperada, no rota. Usa la salida como guía de qué investigar vía comandos Docker, nunca como una lista de directorios a borrar.
Por qué los subdirectorios overlay2 no coinciden con los IDs de imagen
Podaste todo y todavía hay directorios hash que no coinciden con ninguna imagen. Normal. He aquí por qué:
- Capas escribibles de contenedores: los contenedores corriendo o parados tienen cada uno una capa escribible en
overlay2. Si tienes contenedores, tienes datos overlay. - Caché de build: los builds modernos (BuildKit) crean datos de caché.
docker system prune -ano siempre lo elimina todo. Apúntale condocker builder prune. - Capas compartidas o referenciadas: las imágenes comparten capas, y Docker no eliminará nada aún referenciado. El nombre del directorio no coincidirá con lo que ves en
docker image ls. - Capas init y metadatos internos: los directorios
*-inity las estructuras de metadatos son parte de cómo Docker prepara los contenedores. - Datos filtrados u huérfanos (raro): cortes de luz, crashes del daemon o corrupción de almacenamiento pueden dejar restos. Comprueba
docker system df -vy los logs del daemon antes de asumir que es tu caso. - Store heredado oculto tras un cambio de backend: este es nuevo. Si te moviste al store de imágenes containerd (o al revés), los datos del store inactivo se quedan en disco pero son invisibles para los comandos de poda del store activo. La poda no reporta nada que recuperar mientras
dfmuestra un disco lleno. Detéctalo condocker info -f '{{ .DriverStatus }}'y compara contradu -sh /var/lib/docker/overlay2 /var/lib/containerd.
Incluso si un directorio parece sin usar, borrar directorios overlay2 a mano puede corromper el estado de Docker. Si de verdad necesitas un comienzo fresco, haz el reset controlado de abajo con Docker parado y tus datos respaldados.
Evita que /var/lib/docker/overlay2 vuelva a llenarse
La limpieza es una victoria única. Estos cinco hábitos mantienen el disco sano:
- Pon tope al tamaño de logs. Los
log-optsdedaemon.jsonde la sección de logs son el cambio de mayor palanca en cualquier host que corra contenedores habladores. - Programa mantenimiento en máquinas de build. Un timer semanal gana a una alarma de disco lleno:
docker system prune -af --filter until=168h
docker builder prune -af --max-used-space 10gb- Mueve el data dir de Docker a un volumen más grande. Los discos raíz pequeños son la razón habitual por la que Docker llena la partición del SO. En
/etc/docker/daemon.json:
{
"data-root": "/mnt/volume/docker"
}El flag también es --data-root en la línea de comandos de dockerd (los viejos flags -g/--graph se eliminaron en Engine v23). Si la máquina necesita el hardware, añade un nuevo disco a Ubuntu LVM y móntalo permanentemente primero. En máquinas VPS estilo Hetzner donde el disco raíz es pequeño y un volumen separado es barato, los planes cloud optimizados en coste de Hetzner combinan bien con este montaje, y un Hetzner Cloud VPS con un volumen montado resuelve el problema de “Docker se comió el disco del SO” sin mover datos después. Un VPS de Hostinger con almacenamiento NVMe es la alternativa si quieres un único disco local grande en su lugar. El margen de almacenamiento es más barato que el downtime.
Aviso: data-root no migra datos existentes. Planea una copia o movimiento con el daemon parado, luego verifica con docker info | grep 'Docker Root Dir' antes de borrar nada de la ruta vieja.
- Alerta sobre uso de filesystem. Mantén un 15-20% libre y que te pagen antes del 80%, no después de que fallen las escrituras. Monta Beszel y Uptime Kuma para monitorización de servidor y alertas de disco si quieres una ruta self-hosted.
- Mantente parcheado. Los patches de Engine 29.x han incluido tanto la corrección de sub-reporte de poda como una corrección de envenenamiento de caché de BuildKit (GHSA-p3rc-w3hc-pqvv, febrero de 2026): una imagen de caché maliciosa o caché remota puede inyectar caché de build falsa en tus builds. Esa golpea a cualquiera que importe caché de build, no solo a usuarios del store containerd. Las correcciones de seguridad aterrizan en releases de patch; ejecútalas.
log-optsde json-file puestos conmax-sizeymax-file- Poda semanal programada en máquinas de build y runners de CI
data-rooten un filesystem dimensionado para tu churn de imágenes- Alertas de uso de disco disparando antes del 80%
- 15-20% de margen libre en el filesystem de Docker
Cambiar al store de imágenes containerd
Activar "features": { "containerd-snapshotter": true } en daemon.json cambia el store activo, pero no limpia. Espera que el uso de disco crezca un tiempo: containerd mantiene blobs comprimidos y snapshots desempaquetados, y los datos overlay2 heredados se quedan congelados en disco. userns-remap no está disponible con el store de imágenes containerd (moby#47377). Docker documenta una auto-migración experimental (containerd-migration más un umbral de snapshotter), y el propio Docker la llama no fiable. Prefiere un comienzo fresco en un host que puedas reconstruir.
Verifica tras cualquier cambio de data-root:
systemctl status docker
docker info | grep 'Docker Root Dir'Modo de fallo: una errata en daemon.json (un número donde se requiere un string, una coma que falta) impide que dockerd arranque. journalctl -u docker muestra el error de parseo. Guarda una copia del último archivo que funcionaba antes de editar.
Último recurso: reset controlado de Docker (ambos stores)
Último recurso
Esto es disruptivo. Cada imagen se re-descarga, cada contenedor parado está efectivamente eliminado. Más seguro que borrar directorios hash al azar, pero hazlo solo tras backups y solo cuando el playbook de poda ya no tiene nada que recuperar.
Host overlay2 heredado
- Para o elimina los contenedores que no necesitas.
- Haz backup de todo lo importante: volúmenes nombrados y datos en bind-mount especialmente.
- Para el daemon Docker:
sudo systemctl stop docker. - Mueve el data dir:
sudo mv /var/lib/docker /var/lib/docker.bak. - Arranca Docker de nuevo:
sudo systemctl start docker. Recrea/var/lib/dockervacío.
Luego re-descarga imágenes y restaura solo lo que necesitas. Una vez que todo corre y has recuperado el espacio, borra /var/lib/docker.bak en un segundo paso deliberado. No en la misma sesión de comandos.
Host con store de imágenes containerd
- Para o elimina los contenedores que no necesitas.
- Haz backup de volúmenes nombrados y datos en bind-mount.
- Para el daemon Docker:
sudo systemctl stop docker(y containerd si corre como una unidad separada que gestionas). - Mueve ambos data dirs:
sudo mv /var/lib/docker /var/lib/docker.bakysudo mv /var/lib/containerd /var/lib/containerd.bak. - Arranca Docker y confirma que está limpio antes de tocar los directorios
.bak.
Si solo mueves /var/lib/docker en un host containerd, el reset parece no hacer nada: los datos visibles estaban en /var/lib/containerd todo el tiempo. Si previamente cambiaste de backend, los restos del store inactivo también viven en el directorio que no esté activo. Por eso ambos movimientos están en los pasos.
Verifica: df -h antes y después, docker info muestra un root dir fresco, y un contenedor de prueba arranca (docker run --rm alpine echo ok). Solo entonces programa la limpieza de .bak.
FAQ: preguntas sobre limpieza de overlay2 de Docker
¿Es seguro borrar /var/lib/docker/overlay2 manualmente?
No. Los directorios hash son estructuras vivas de capas y metadatos. Borrarlos corrompe el grafo de Docker y puede romper contenedores e imágenes en ejecución incluso si el directorio “parece” sin usar. Usa docker system prune, docker builder prune y los otros comandos soportados de esta guía. La única eliminación masiva sancionada es un reset controlado de todo el data dir con el daemon parado.
¿Por qué docker volume prune no recupera espacio?
Porque desde Docker Engine 23.0 / API 1.42, docker volume prune elimina solo volúmenes anónimos. Tu espacio probablemente está en volúmenes nombrados (bases de datos, subidas), que necesitan docker volume prune -a. Comprueba con docker volume ls y docker system df -v primero. Los volúmenes nombrados contienen datos reales, así que haz backup antes de -a.
¿Por qué /var/lib/docker/overlay2 es tan grande en un servidor Docker 29?
Dos razones probables. Primero, Engine 29 activa el store de imágenes containerd en instalaciones nuevas, así que puedes estar mirando restos del store heredado que los comandos de poda nunca tocarán. Detéctalo con docker info -f '{{ .DriverStatus }}'. Segundo, overlay2 contiene capas escribibles de contenedores y caché de build, que crecen incluso cuando todas las imágenes están en uso. Lee el desglose de categorías en docker system df -v antes de asumir que el problema son imágenes sin usar.
¿Los logs de contenedores Docker realmente ocupan espacio en disco?
Sí. El driver de logs json-file va por defecto a tamaño ilimitado (max-size es -1) y los archivos viven en /var/lib/docker/containers/, no en overlay2. Trúncalos para un arreglo inmediato (truncate -s 0 sobre los archivos *-json.log, no los borres), luego pon log-opts con max-size y max-file en /etc/docker/daemon.json y recrea los contenedores para que la rotación aplique.
¿Cuál es la forma más rápida de recuperar espacio en disco de Docker esta noche?
En orden: docker system df -v para ver la categoría más grande, docker system prune -f para la victoria segura, docker builder prune -af --max-used-space 10gb si la caché de build es grande, luego comprueba du -sh /var/lib/docker/containers/* por logs desbocados y trúncalos. Guarda la línea base de docker system df -v primero para poder demostrar lo que recuperaste. Para la versión en profundidad, mira cómo limpiar todas las imágenes Docker con discos y todo.
Resumen
Un /var/lib/docker/overlay2 que crece (o /var/lib/containerd en hosts Engine 29) se reduce a cuatro cosas: objetos sin usar, caché de build, escrituras de capas escribibles, y logs de contenedores sin límite. Haz la limpieza de overlay2 de Docker en ese orden de culpables: corre docker system df -v, poda con los comandos soportados (recuerda que los volúmenes nombrados necesitan docker volume prune -a), pon tope a tus logs con log-opts, y programa mantenimiento en vez de esperar a la alarma de disco lleno.
No borres nada dentro de esos directorios a mano. Si llegas al punto en que la poda ya no tiene nada que dar y el disco sigue lleno, haz el reset controlado con el daemon parado y los backups en su sitio.
Todos los comandos de limpieza Docker

