Contenido

Tutorial de limpieza de espacio en disco de Docker: usa prune para liberar espacio

Tras usar Docker durante un tiempo, se acumulan imágenes antiguas, contenedores detenidos, caché de compilación y volúmenes sin uso, que pueden ocupar decenas de GB. En esta sección, primero averiguarás qué consume espacio y luego lo limpiarás de forma segura. Todas las salidas son el resultado de ejecutar los comandos en orden en el mismo entorno.

Comprueba cuánto espacio se usa

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          13        3         2.886GB   2.377GB (82%)
Containers      4         1         98.3kB    16.38kB (16%)
Local Volumes   4         1         40.61MB   40.61MB (100%)
Build Cache     151       0         3.554GB   2.954GB
CampoSignificado
TOTALCantidad total
ACTIVECantidad que usan los contenedores
SIZEEspacio ocupado
RECLAIMABLEParte que se puede liberar (sin uso)

En este entorno hay 13 imágenes y solo 3 están en uso; se pueden recuperar 2.377 GB (82 %). La caché de compilación ocupa aún más: 2.954 GB. Añade -v para ver los detalles de cada imagen, contenedor y volumen: docker system df -v.

Imágenes y contenedores actuales:

$ docker images
IMAGE               ID             DISK USAGE   CONTENT SIZE   EXTRA
adminer:latest      74f29c416e14        164MB         43.8MB
alpine:3.23         85fe1e81d675       26.6MB         8.21MB   U
hello-node:latest   4063457524bb        245MB         62.2MB
myapp:latest        80cb5c41a286       54.9MB         24.8MB   U
mysql:8.4           24989179f588       1.12GB          254MB
nginx:1.30          9bf97bd7714f        242MB         66.5MB
nginx:1.30-alpine   0985e772fb9f       93.7MB           27MB   U
node:24-alpine      ebfe2f904627        242MB           62MB
postgres:18         74935e722416        650MB          169MB
python:3.14-slim    a2b82f3c4855        180MB         45.7MB
redis:8-alpine      3811787313eb        161MB         39.6MB
registry:3          ddf754342cfc       86.9MB         20.7MB
ubuntu:26.04        f144425ff09b        162MB         45.6MB
$ docker ps -a
CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS                     PORTS     NAMES
cc43746c9a29   alpine:3.23         "true"                   7 seconds ago   Exited (0) 6 seconds ago             anon1
7e269fff858b   nginx:1.30-alpine   "/docker-entrypoint.…"   8 seconds ago   Up 7 seconds               80/tcp    web
bf5ff318eb63   alpine:3.23         "echo done"              8 seconds ago   Exited (0) 7 seconds ago             old2
b580380c1fd2   myapp               "cat /version.txt"       9 seconds ago   Exited (0) 8 seconds ago             old1

La U de la columna EXTRA significa In Use (en uso por un contenedor). De los contenedores, solo web está en ejecución; los otros tres ya terminaron (Exited), pero siguen ocupando espacio.

Limpieza por componente

ComandoQué elimina
docker container pruneTodos los contenedores detenidos
docker image pruneImágenes colgantes (sin nombre, <none>)
docker image prune -aTodas las imágenes que no usa ningún contenedor
docker builder pruneCaché de compilación
docker volume pruneVolúmenes anónimos sin uso
docker volume prune -aTodos los volúmenes sin uso (incluidos los que tienen nombre)
docker network pruneRedes personalizadas sin uso

Cada comando pide confirmación primero (Are you sure you want to continue? [y/N]). Añade -f para omitirla, algo útil en scripts. En los siguientes ejemplos se usa -f.

Eliminar contenedores detenidos

$ docker container prune -f
Deleted Containers:
cc43746c9a2993bda0fb21ab3f161b78603353714f396f86fa8c4b5caf90e25a
bf5ff318eb6331a05239ad7fa39420ff96dc1c8f84b9a3548ce38a0f71a2d63a
b580380c1fd2dc6cca2dc6e009bb877c3eb2df1cf388664a32c8932aff8169fa

Total reclaimed space: 16.38kB

Se eliminaron los tres contenedores detenidos. El contenedor web, que sigue en ejecución, no se ve afectado.

Si usas Docker Desktop, también puedes seleccionar los contenedores en la pantalla Containers y hacer clic en Delete:

Selecciona contenedores en la pantalla Containers de Docker Desktop y haz clic en Delete
Docker Desktop: selecciona contenedores y haz clic en Delete. Imagen: documentación oficial de Docker (Apache-2.0)

Docker 29: las reconstrucciones ya no dejan imágenes <none>

Antes, al reconstruir una imagen varias veces con el mismo nombre (por ejemplo, al ejecutar docker build -t myapp .), las versiones antiguas pasaban a ser «imágenes colgantes» llamadas <none>, que había que eliminar con docker image prune. Prueba en Docker 29:

$ docker build -q --build-arg VERSION=4 -t myapp:latest .
sha256:3f33bc33eb36171280e9b90d904e25c58b2dcf509390536580ffacafc35d4595

$ docker images --filter dangling=true
IMAGE   ID             DISK USAGE   CONTENT SIZE   EXTRA

$ docker ps -a --filter name=old1
CONTAINER ID   IMAGE          COMMAND              CREATED          STATUS                      PORTS     NAMES
b580380c1fd2   80cb5c41a286   "cat /version.txt"   26 seconds ago   Exited (0) 26 seconds ago             old1

Se reconstruyó myapp:latest cuatro veces seguidas, pero --filter dangling=true no devuelve nada. Docker 29 usa por defecto el almacenamiento de imágenes de containerd; cuando una imagen nueva sustituye el nombre, la versión anterior ya no se conserva como <none>. En el caso de los contenedores que aún usan una versión anterior (old1), la columna IMAGE muestra el ID de la imagen.

Por eso, en Docker 29, normalmente hay poco que limpiar con docker image prune (sin -a). Lo que realmente ocupa espacio son las imágenes que no se usan pero aún tienen nombre y la caché de compilación.

Eliminar volúmenes anónimos

$ docker volume ls
DRIVER    VOLUME NAME
local     6f6f8ce590c609d4f39b3a676282da88866c8ab20a064132f7746c3cf6717f2c
local     991c93cb6ebeac8570e9c15a89b4225c2bb5e20cbfde2f5bf665fa4dfa23a1aa
local     5396795eeeaab8415295814207a02f75f6ea136d5c34574ba9b16ecdc1b975f9
local     cleanup-demo_pgdata

$ docker volume prune -f
Deleted Volumes:
5396795eeeaab8415295814207a02f75f6ea136d5c34574ba9b16ecdc1b975f9
991c93cb6ebeac8570e9c15a89b4225c2bb5e20cbfde2f5bf665fa4dfa23a1aa
6f6f8ce590c609d4f39b3a676282da88866c8ab20a064132f7746c3cf6717f2c

Total reclaimed space: 0B

$ docker volume ls
DRIVER    VOLUME NAME
local     cleanup-demo_pgdata
  • Los tres primeros nombres largos son volúmenes anónimos. Por ejemplo, el Dockerfile de la imagen postgres declara VOLUME; aunque no montes nada al ejecutar el contenedor, Docker crea automáticamente un volumen anónimo. Este permanece después de eliminar el contenedor (consulta Volúmenes y persistencia de datos).
  • docker volume prune solo elimina volúmenes anónimos que no se estén usando.
  • cleanup-demo_pgdata es un volumen con nombre del proyecto Compose. Aunque después de docker compose down ya no haya ningún contenedor que lo use, no se ha eliminado.

Eliminar la caché de compilación

$ docker builder du | tail -n 3
Private:	2.996GB
Reclaimable:	3.596GB
Total:		3.596GB

$ docker builder prune -f --filter until=1h | tail -n 3
lv85kuv5xx5h65k941qjoxecz               	true 	98.69kB   	About an hour ago
kc9tcgw8l1aq9dz1agx096se0               	true 	870kB     	About an hour ago
Total:	1.662GB

$ docker builder prune -f | tail -n 3
6os07ml167zpcfh09ushitk2b               	true 	8.285kB   	38 minutes ago
7ir7u28j6esk2x7pyu6q38kvk               	true 	74.75MB   	38 minutes ago
Total:	1.334GB
  • docker builder du muestra que la caché de compilación ocupa 3.596 GB en total, y que todo ese espacio se puede recuperar.
  • --filter until=1h solo elimina la caché que no se ha usado durante más de 1 hora; liberó 1.662 GB.
  • Sin filtro, se liberaron otros 1.334 GB.

El coste de eliminar la caché de compilación es que la próxima compilación tendrá que volver a ejecutar todos los pasos (por ejemplo, ejecutar de nuevo npm ci y pip install), así que tardará más. Sin embargo, no afectará a ninguna imagen ni contenedor.

Limpiar todo de una vez: docker system prune

docker system prune

Elimina los contenedores detenidos, las redes sin usar, las imágenes colgantes y la caché de compilación.

docker system prune -a

También elimina todas las imágenes que no se estén usando. La próxima vez que las necesites, tendrás que volver a descargarlas.

Comprobación práctica: ¿--volumes eliminará los datos de la base de datos?

Muchos tutoriales (incluidas versiones anteriores de este tutorial) advierten que docker system prune --volumes también elimina los volúmenes de bases de datos que están «temporalmente sin uso» después de ejecutar docker compose down. Prueba realizada con Docker 29:

$ docker system prune --volumes -f
Deleted Containers:
871f1c408d23dd413804105498b5520385dfafc9e558c02447ed940684bbc483

Deleted Volumes:
e5d0caa972c5323d5a64e9baf5fcb21d66ce7fbb4879bdcc7aa068a14fdbbf76

Total reclaimed space: 8.192kB

$ docker volume ls
DRIVER    VOLUME NAME
local     cleanup-demo_pgdata

--volumes solo eliminó un volumen anónimo. El volumen con nombre de la base de datos de Compose, cleanup-demo_pgdata, sigue ahí. Desde Docker 23, volume prune y system prune --volumes solo procesan de forma predeterminada los volúmenes anónimos.

El comando que realmente elimina los volúmenes con nombre es docker volume prune -a:

$ docker volume prune -a -f
Deleted Volumes:
cleanup-demo_pgdata

Total reclaimed space: 40.61MB

$ docker volume ls
DRIVER    VOLUME NAME

Esta vez se eliminó cleanup-demo_pgdata, y los 40.61 MB de archivos de la base de datos que contenía también desaparecieron y no se pueden recuperar.

Usa docker volume prune -a solo cuando estés seguro de que no necesitas ninguno de los datos. Para eliminar un volumen específico, es más seguro usar docker volume rm nombre; en un proyecto Compose, usa docker compose down -v, que solo elimina los volúmenes de ese proyecto. Si usas Docker 20.10 o una versión anterior, --volumes todavía elimina los volúmenes con nombre.

Eliminar todas las imágenes que no se estén usando

$ docker image prune -a -f | grep -E "^untagged|^Total"
untagged: nginx:1.30
untagged: node:24-alpine
untagged: postgres:18
untagged: python:3.14-slim
untagged: myapp:latest
untagged: mysql:8.4
untagged: redis:8-alpine
untagged: registry:3
untagged: ubuntu:26.04
untagged: adminer:latest
untagged: alpine:3.23
untagged: hello-node:latest
Total reclaimed space: 2.665GB

$ docker images
IMAGE               ID             DISK USAGE   CONTENT SIZE   EXTRA
nginx:1.30-alpine   0985e772fb9f       93.7MB           27MB   U

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          1         1         93.66MB   0B (0%)
Containers      1         1         81.92kB   0B (0%)
Local Volumes   0         0         0B        0B
Build Cache     26        0         599.6MB   506.9MB
  • Se eliminaron las otras 12 imágenes, excepto nginx:1.30-alpine, que está usando el contenedor web; se recuperaron 2.665 GB.
  • El último comando docker system df muestra que solo quedan 93.66 MB de imágenes.

La próxima vez que ejecutes docker run o construyas una imagen, estas imágenes se descargarán automáticamente de nuevo. Si la red es lenta o la imagen es muy grande (por ejemplo, las imágenes relacionadas con modelos de IA pueden ocupar varios GB), considera usar --filter para eliminar solo las antiguas:

docker image prune -a --filter "until=168h"      # Elimina solo las creadas hace más de 7 días

Ten en cuenta que until compara la fecha de creación de la imagen (cuándo la creó su autor), no cuándo la descargaste.

Los registros de los contenedores también ocupan espacio

De forma predeterminada, los registros json-file no tienen límite de tamaño. Prueba con un contenedor que genera salida continuamente (el comando yes produce mucho texto cada segundo):

$ docker run -d --name noisy alpine:3.23 sh -c "timeout 3 yes hello-docker-log; sleep 600"
863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6

$ docker inspect --format "{{.LogPath}}" noisy
/var/lib/docker/containers/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6-json.log

$ du -h $(docker inspect --format "{{.LogPath}}" noisy)
69.3M	/var/lib/docker/containers/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6-json.log

$ docker rm -f noisy
noisy

Con solo 3 segundos de salida, el archivo de registro ya ocupa 69.3 MB. En los contenedores que se ejecutan durante mucho tiempo y generan muchos registros, estos archivos pueden alcanzar decenas de GB y no se eliminan automáticamente hasta que se borra el contenedor. Los archivos de registro están en /var/lib/docker/containers/ID_DEL_CONTENEDOR/. En un host Linux, puedes encontrar los archivos de registro más grandes así:

sudo du -h /var/lib/docker/containers/*/*-json.log | sort -h | tail

Configurar límites para un solo contenedor

$ docker run -d --name noisy --log-opt max-size=10m --log-opt max-file=3 alpine:3.23 sh -c "timeout 3 yes hello-docker-log; sleep 600"
fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161

$ ls -lh $(dirname $(docker inspect --format "{{.LogPath}}" noisy)) | grep json
-rw-------    1 root     root        3.2K Oct 13 01:07 config.v2.json
-rw-r-----    1 root     root        7.2M Oct 13 01:07 fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161-json.log
-rw-r-----    1 root     root        9.5M Oct 13 01:07 fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161-json.log.1
-rw-r-----    1 root     root        9.5M Oct 13 01:07 fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161-json.log.2
-rw-------    1 root     root        1.5K Oct 13 01:07 hostconfig.json

$ docker inspect --format '{{json .HostConfig.LogConfig}}' noisy
{"Type":"json-file","Config":{"max-file":"3","max-size":"10m"}}

$ docker rm -f noisy
noisy

max-size=10m indica un máximo de 10 MB por archivo, y max-file=3 indica que se conservan como máximo 3 archivos. Los antiguos rotan a .1, .2. Con la misma cantidad de salida, los registros ocupan unos 26 MB en total y no seguirán creciendo.

En Compose se escribe así:

services:
  app:
    image: myapp
    logging:
      options:
        max-size: "10m"
        max-file: "3"

Configurar límites globales para los registros

Para aplicar límites a todos los contenedores nuevos: en Linux, edita /etc/docker/daemon.json; en Docker Desktop, edita el mismo JSON en Settings → Docker Engine:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

En Linux, ejecuta sudo systemctl restart docker después de modificar el archivo. En Docker Desktop, pulsa Apply & restart. Solo se aplica a los contenedores que se creen a partir de entonces. Para los contenedores existentes, elimínalos y vuelve a crearlos (en Compose, usa docker compose up -d --force-recreate).

Docker Desktop: el espacio en disco no aumenta después de limpiar

En Windows y macOS, todos los datos de Docker se almacenan en un archivo de disco virtual. Al eliminar imágenes, se libera espacio dentro del disco virtual, pero es posible que el archivo no reduzca su tamaño de inmediato.

  • Docker Desktop: en Settings → Resources → Advanced puedes consultar y ajustar el límite del disco virtual. Troubleshoot → Clean / Purge data borra todos los datos de Docker (elimina imágenes, contenedores y Volumes). Úsalo solo como último recurso.
  • Windows (WSL 2): si el archivo .vhdx sigue ocupando mucho espacio, primero ejecuta wsl --shutdown y luego comprime el archivo .vhdx correspondiente con compact vdisk de diskpart.

Limpieza periódica recomendada

En un servidor, puedes usar cron para ejecutarla una vez por semana:

docker container prune -f --filter "until=168h"
docker image prune -af --filter "until=168h"
docker builder prune -af --filter "until=168h"

Estos comandos no afectan a ningún Volume, así que los datos de la base de datos están seguros. Si además configuras límites globales para los registros, evitarás que el espacio en disco se descontrole.

Resumen

  • Primero consulta docker system df y luego decide qué limpiar.
  • image prune -a elimina todas las imágenes que no se estén usando; builder prune limpia la caché de compilación.
  • volume prune solo elimina Volumes anónimos; -a también incluye los que tienen nombre.
  • Configura los límites de registros max-size y max-file.

Ejercicios

Ejercicio 1: Escribe un conjunto de comandos para cron que no afecte a ningún Volume y elimine solo las imágenes y la caché de compilación con más de 7 días.

Respuesta
docker image prune -af --filter "until=168h"
docker builder prune -af --filter "until=168h"

Preguntas frecuentes

¿Es seguro docker system prune?

Sin --volumes, no toca ningún volumen. Desde Docker 23, incluso con --volumes, solo elimina volúmenes anónimos. El comando realmente peligroso es docker volume prune -a.

¿Por qué no hay más espacio en disco en Windows después de limpiar?

Docker Desktop almacena los datos en un archivo de disco virtual. Al eliminar imágenes, el archivo no siempre se reduce de inmediato. Consulta la última sección de este capítulo.

¿Puedo borrar toda la caché de compilación?

Sí. No afecta a ninguna imagen ni contenedor, aunque la próxima compilación será más lenta.

Actualizado 14 de octubre de 2026