En este momento estás viendo [Docker] – Limpiar contenedores, imágenes y volúmenes

[Docker] – Limpiar contenedores, imágenes y volúmenes

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:

  1. Comprobar el espacio utilizado con docker system df.
  2. Eliminar contenedores detenidos.
  3. Eliminar imágenes que realmente ya no necesitemos.
  4. Limpiar la caché de construcción si ocupa demasiado.
  5. Revisar los volúmenes antes de eliminar cualquiera.
  6. 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

Website |  + posts

Automation & Data Specialist | Web Development | Data Processing & Integration

Serna Studio

Automation & Data Specialist | Web Development | Data Processing & Integration

Deja una respuesta