Cómo limpiar Docker de contenedores, imágenes y volúmenes con PowerShell
Si utilizamos Docker habitualmente, tarde o temprano nuestro sistema empieza a acumular contenedores detenidos, imágenes antiguas, redes y volúmenes que ya no utilizamos.
Al principio apenas lo notamos. Pero después de varias semanas o meses trabajando con diferentes proyectos, haciendo docker compose up, reconstruyendo imágenes y probando diferentes versiones, podemos terminar ocupando varios gigabytes de espacio sin darnos cuenta.
En este artículo voy a crear un pequeño script de PowerShell para consultar el espacio utilizado por Docker y realizar una limpieza de forma controlada.
Importante antes de empezar
Las operaciones de limpieza de Docker pueden eliminar datos. Especialmente los volúmenes, ya que pueden contener bases de datos y otros datos persistentes. Antes de utilizar cualquier opción destructiva, comprueba qué recursos tienes y asegúrate de que no necesitas conservarlos.
¿Qué podemos limpiar en Docker?
Antes de empezar con PowerShell conviene entender qué estamos eliminando.
- Contenedores detenidos: contenedores que ya no están ejecutándose.
- Imágenes no utilizadas: imágenes que no están siendo utilizadas por ningún contenedor.
- Redes no utilizadas: redes que Docker ya no necesita.
- Volúmenes no utilizados: volúmenes que no están asociados a ningún contenedor.
- Build cache: caché generada durante la construcción de imágenes.
Docker proporciona comandos específicos para cada uno de estos recursos y también dispone de docker system prune, que permite realizar varias operaciones de limpieza de una sola vez.
Comprobar cuánto ocupa Docker
Antes de borrar nada, lo primero que haría es consultar el estado actual de Docker.
docker system df
Podremos obtener una salida similar a:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 12 5 6.8GB 3.1GB Containers 8 2 420MB 310MB Local Volumes 6 3 2.4GB 1.1GB Build Cache 18 0 1.7GB 1.7GB
Hay una columna especialmente interesante:
RECLAIMABLE
Esta columna nos indica aproximadamente cuánto espacio puede recuperar Docker mediante las operaciones de limpieza correspondientes.
Esto es mucho más útil que intentar calcular manualmente el espacio leyendo y procesando el texto de docker system df.
La forma rápida: docker system prune
Docker incorpora un comando específico para eliminar recursos que ya no se utilizan:
docker system prune
Por defecto, Docker solicita confirmación antes de realizar la limpieza.
Si queremos evitar la confirmación interactiva:
docker system prune -f
Pero existe una diferencia importante cuando utilizamos -a:
docker system prune -a
Con -a, Docker amplía la limpieza y puede eliminar también imágenes que no están asociadas actualmente a ningún contenedor.
Por eso no conviene utilizar -a sin saber qué imágenes queremos conservar.
¿Y qué ocurre con los volúmenes?
Aquí tenemos que tener especial cuidado.
Los volúmenes pueden contener datos persistentes. Por ejemplo, una base de datos MySQL, MariaDB, PostgreSQL o cualquier otro servicio puede estar utilizando un volumen para conservar sus datos aunque eliminemos el contenedor.
Podemos consultar nuestros volúmenes con:
docker volume ls
Y consultar los detalles de un volumen concreto:
docker volume inspect NOMBRE_DEL_VOLUMEN
Por este motivo, no recomiendo plantear una limpieza de volúmenes como una operación rutinaria sin comprobar antes qué estamos eliminando.
Mucho cuidado con los volúmenes
Eliminar un volumen puede significar perder los datos almacenados en él. Si contiene una base de datos, asegúrate de tener una copia de seguridad antes de eliminarlo.
Crear nuestro script de PowerShell
Ahora sí. Vamos a crear un pequeño script para consultar Docker y ofrecernos diferentes opciones de limpieza.
Crearemos un archivo llamado:
DockerCleanup.ps1
La idea es mantener el script sencillo: primero veremos el estado actual de Docker y después podremos seleccionar qué queremos limpiar.
function Write-Section {
param (
[string]$Text
)
Write-Host ""
Write-Host "========================================" -ForegroundColor Cyan
Write-Host $Text -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
}
function Confirm-Action {
param (
[string]$Message
)
$response = Read-Host "$Message (s/n)"
return $response -match '^[sS]$'
}
function Show-DockerUsage {
Write-Section "Uso actual de Docker"
docker system df
}
function Test-Docker {
try {
docker version | Out-Null
if ($LASTEXITCODE -ne 0) {
throw "Docker no está disponible."
}
return $true
}
catch {
Write-Host ""
Write-Host "No se ha podido conectar con Docker." -ForegroundColor Red
Write-Host "Comprueba que Docker Desktop o el daemon de Docker estén funcionando." -ForegroundColor Yellow
return $false
}
}
# ========================================
# INICIO
# ========================================
Write-Host ""
Write-Host "Docker Cleanup - PowerShell" -ForegroundColor Green
if (-not (Test-Docker)) {
exit 1
}
Show-DockerUsage
Write-Section "Opciones de limpieza"
Write-Host "1) Eliminar contenedores detenidos"
Write-Host "2) Eliminar imágenes no utilizadas"
Write-Host "3) Eliminar redes no utilizadas"
Write-Host "4) Eliminar caché de construcción"
Write-Host "5) Limpieza general (prune)"
Write-Host "6) Limpieza general + imágenes no utilizadas"
Write-Host "7) Eliminar volúmenes no utilizados"
Write-Host "8) Mostrar uso de Docker"
Write-Host "0) Salir"
$option = Read-Host ""
switch ($option) {
"1" {
if (Confirm-Action "¿Eliminar los contenedores detenidos?") {
docker container prune
} else {
Write-Host "Operación cancelada." -ForegroundColor Yellow
}
}
"2" {
if (Confirm-Action "¿Eliminar las imágenes no utilizadas?") {
docker image prune
} else {
Write-Host "Operación cancelada." -ForegroundColor Yellow
}
}
"3" {
if (Confirm-Action "¿Eliminar las redes no utilizadas?") {
docker network prune
} else {
Write-Host "Operación cancelada." -ForegroundColor Yellow
}
}
"4" {
if (Confirm-Action "¿Eliminar la caché de construcción no utilizada?") {
docker builder prune
} else {
Write-Host "Operación cancelada." -ForegroundColor Yellow
}
}
"5" {
if (Confirm-Action "¿Realizar una limpieza general de Docker?") {
docker system prune
} else {
Write-Host "Operación cancelada." -ForegroundColor Yellow
}
}
"6" {
if (Confirm-Action "¿Eliminar también imágenes no utilizadas?") {
docker system prune -a
} else {
Write-Host "Operación cancelada." -ForegroundColor Yellow
}
}
"7" {
Write-Host ""
Write-Host "ATENCIÓN: los volúmenes pueden contener datos importantes." -ForegroundColor Red
if (Confirm-Action "¿Eliminar los volúmenes que no estén siendo utilizados?") {
docker volume prune
} else {
Write-Host "Operación cancelada." -ForegroundColor Yellow
}
}
"8" {
Show-DockerUsage
}
"0" {
Write-Host "Saliendo..." -ForegroundColor Yellow
exit 0
}
default {
Write-Host "Opción no válida." -ForegroundColor Red
}
}
Write-Section "Estado final"
docker system df
Write-Host ""
Write-Host "Proceso terminado." -ForegroundColor Green
¿Qué hace el script?
La primera diferencia respecto al script original es que no intento calcular artificialmente cuánto espacio se va a liberar procesando el texto devuelto por docker system df.
Docker ya proporciona esa información mediante la columna RECLAIMABLE, por lo que resulta mucho más fiable consultar directamente al propio Docker.
El script también comprueba primero que Docker esté disponible:
docker version
Después muestra el uso actual:
docker system df
Y finalmente presenta un menú para decidir qué operación queremos realizar.
Limpiar únicamente contenedores detenidos
Si queremos eliminar los contenedores que ya no están ejecutándose:
docker container prune
También podemos hacerlo directamente sin confirmación:
docker container prune -f
Esta es probablemente una de las operaciones de limpieza más habituales.
Para consultar primero qué contenedores tenemos:
docker ps -a
Limpiar imágenes no utilizadas
Docker puede acumular imágenes que ya no necesitamos.
Para eliminar las imágenes que no estén siendo utilizadas:
docker image prune
Existe una diferencia importante con:
docker image prune -a
La opción -a amplía la limpieza a todas las imágenes que no estén siendo utilizadas por contenedores, no solamente a las imágenes “dangling”.
Por tanto, utilizaría -a cuando realmente quiera hacer una limpieza más agresiva y tenga claro qué imágenes necesito conservar.
Limpiar redes no utilizadas
También podemos eliminar redes que Docker ya no necesite:
docker network prune
Podemos consultar previamente las redes existentes:
docker network ls
Limpiar la caché de construcción
Si construimos imágenes frecuentemente, también podemos acumular bastante caché.
Para comprobarla:
docker system df
Y para limpiar la caché de construcción:
docker builder prune
Si queremos una limpieza más agresiva de la caché:
docker builder prune -a
De nuevo, Docker solicitará confirmación salvo que utilicemos -f.
La limpieza general con docker system prune
Si queremos que Docker realice varias operaciones de limpieza de una sola vez:
docker system prune
Esta es una opción bastante cómoda para realizar mantenimiento periódico.
Si queremos incluir también imágenes no utilizadas:
docker system prune -a
Y si además queremos incluir volúmenes no utilizados:
docker system prune -a --volumes
Atención con este comando
docker system prune -a --volumes
Es una limpieza considerablemente más agresiva. Los volúmenes no utilizados pueden contener datos que queramos conservar. No lo utilizaría como comando rutinario sin comprobar previamente el estado de los volúmenes.
¿Necesito ejecutar PowerShell como administrador?
No necesariamente.
Esto depende principalmente de cómo esté instalado Docker y de los permisos de nuestro entorno.
En Docker Desktop para Windows, normalmente podemos ejecutar estos comandos desde una sesión de PowerShell del usuario que utiliza Docker Desktop.
Si Docker devuelve un error de permisos, acceso al daemon o ejecución de PowerShell, entonces sí tendremos que revisar la configuración de nuestro entorno.
Por tanto, no es necesario establecer como regla que PowerShell tenga que ejecutarse siempre como administrador.
Ejecutar nuestro script
Guardamos el archivo:
DockerCleanup.ps1
Nos desplazamos hasta el directorio donde lo hemos guardado:
cd C:\Ruta\Del\Script
Y lo ejecutamos:
.\DockerCleanup.ps1
Si PowerShell bloquea la ejecución del script debido a la política de ejecución, podemos consultar la configuración actual:
Get-ExecutionPolicy
No recomiendo cambiar la política global del sistema simplemente para ejecutar un script puntual. Si estamos trabajando en un entorno controlado, podemos utilizar una política apropiada para nuestra situación o ejecutar PowerShell con una política temporal para ese proceso.
Una limpieza rápida para el día a día
Si no necesitamos utilizar el script y simplemente queremos hacer una limpieza básica, podemos hacerlo directamente desde PowerShell.
Por ejemplo:
docker system df
Comprobamos el estado y, si queremos eliminar recursos básicos que ya no se utilizan:
docker system prune
Después podemos volver a comprobar:
docker system df
Así podemos comprobar qué ha cambiado.
¿Qué no deberíamos hacer a la ligera?
Hay algunos comandos que pueden parecer muy cómodos cuando nuestro disco empieza a quedarse sin espacio, pero que conviene utilizar con cuidado.
Por ejemplo:
docker rm -f $(docker ps -aq)
Esto intenta eliminar todos los contenedores, incluidos los que estén ejecutándose.
Algo similar ocurre con:
docker rmi -f $(docker images -aq)
La intención es eliminar todas las imágenes disponibles.
Y todavía hay que tener más cuidado con:
docker volume rm -f $(docker volume ls -q)
porque estamos entrando directamente en el territorio de los datos persistentes.
No incluiría estas operaciones en una limpieza automática rutinaria. Si necesitamos realizar una limpieza destructiva de este nivel, prefiero ejecutar los comandos conscientemente y después de haber comprobado qué recursos tenemos.
Docker Compose merece una consideración especial
Si trabajamos con Docker Compose, muchas veces los contenedores, redes y volúmenes forman parte de un proyecto concreto.
Podemos consultar los recursos del proyecto antes de eliminarlos:
docker compose ps
Y también podemos revisar los volúmenes:
docker volume ls
Esto es especialmente importante cuando tenemos proyectos de desarrollo con bases de datos.
Por ejemplo, eliminar un contenedor de MariaDB no necesariamente significa perder la base de datos si esta está almacenada en un volumen. Pero eliminar posteriormente ese volumen sí puede significar perder los datos.
Por eso conviene distinguir siempre entre:
- el contenedor;
- la imagen;
- y los datos persistentes almacenados en volúmenes.
Una estrategia de limpieza razonable
Después de utilizar Docker durante bastante tiempo, una rutina sencilla podría ser:
- Comprobar el espacio utilizado con
docker system df. - Eliminar contenedores detenidos.
- Eliminar imágenes que realmente ya no necesitemos.
- Limpiar la caché de construcción si ocupa demasiado.
- Revisar los volúmenes antes de eliminar cualquiera.
- Volver a ejecutar
docker system df.
De esta forma no convertimos una tarea de mantenimiento en una operación destructiva.
Conclusión
Docker es fantástico para trabajar con entornos aislados, pero esa comodidad también significa que podemos terminar acumulando una cantidad considerable de recursos que ya no necesitamos.
Con unos pocos comandos podemos controlar fácilmente qué está ocupando espacio:
docker system df
Y podemos realizar limpiezas específicas:
docker container prune docker image prune docker network prune docker builder prune docker volume prune
O una limpieza general:
docker system prune
La clave está en no confundir limpiar lo que no utilizamos con borrar Docker entero a machetazos.
Especialmente cuando hablamos de volúmenes, merece la pena pararse unos segundos y comprobar qué contienen antes de pulsar el botón rojo.
Y precisamente para eso resulta útil PowerShell: podemos convertir todas estas operaciones en un pequeño menú, revisar el estado de Docker y decidir qué queremos eliminar sin tener que memorizar todos los comandos.
Docker limpio, disco respirando y nosotros sin llorar porque acabamos de borrar la base de datos del proyecto. 😎
Visitas: 12
Automation & Data Specialist | Web Development | Data Processing & Integration

