Gestionar imágenes con Podman

Este es uno de los capítulos del tutorial Podman, el príncipe intrépido. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.

A estas alturas, ya sabes que es Podman. Has visto que tiene determinadas características que lo hace realmente interesante. Como ya te imaginabas, has podido constatar que la instalación de Podman es realmente sencilla, aunque necesitas algunos pasos para dejarlo fino, pero nada realmente complicado. Y por supuesto, te puede el ansía y necesitas comenzar a utilizarlo, prácticamente para cualquier cosa. Sin embargo, te voy a dar un noticia regulera, algo que te adelanté en el capítulo anterior del tutorial. Tienes que conocer como gestionar imágenes con Podman.

Gestionar imágenes con Podman, es algo que tienes que tener muy de la mano, algo a lo que te tienes que acostumbrar. Y no solo se trata de descargar imágenes de diferentes repositorios, sino también se trata de gestionar imágenes, actualizar aquellas imágenes que ya están desactualizadas o incluso borrar esas imágenes que ya has dejado de utilizar. Así que, vamos allá a gestionar imágenes con Podman.

Gestionar imágenes con Podman

Gestionar imágenes con Podman

Un breve recordatorio

Antes que nada, una pequeña introducción o recordatorio. ¿Que es una imagen? Una imagen no es ni mas ni menos que una aplicación o servicio empaquetado con todo aquello que necesitas para su correcto funcionamiento, todas las dependencias necesarias.

Esto desde el punto de vista del usuario, porque cuando comiences a construir tus propias imágenes, verás que se parecen, tremendamente, a una receta.

Pero, ¿donde están esas imágenes?

Registries, el lugar de las imágenes

Las imágenes están guardadas en Registries. Por defecto, al instalar Podman, se configuran dos Registries en tu equipo, docker.io y quay.io, pero puedes añadir las que tu necesites.

Cuando tu ejecutas la instrucción podman search atareao, por ejemplo, el buscará todas las imágenes con este nombre tanto en docker.io, como en quay.io. Indicar que por defecto busca un máximo de 25 imágenes en cada uno de los Registries que tengas configurado, pero, esto lo puedes modificar utilizando el parámetro --limit <numero>.

¿Como gestionar imágenes con Podman?

Para gestionar imágenes con Podman tendrás que utilizar podman image <subcomando>, donde <subcomando> podrá ser alguno de los que encontrarás listado en man podman-image, y que te comento a continuación.

build

build crea una imagen a partir de un Dockerfile. Este Dockerfile no es mas que una receta de los pasos que tiene que seguir para construir esa imagen que tiene tanto la aplicación como todas las dependencias necesarias. Este es uno de los comandos mas interesantes y por ello le dedicaré un capítulo completo, para poder abordarlo con todo detalle. Aunque para que no te quedes con las ganas, te indico aquí como hacer tu primera imagen.

Para implementar tu primera imagen, tienes que crear dos archivos. El primero de los archivos se llamará sample.sh, y tendrá el siguiente contenido,

#!/bin/sh
echo "Hola mundo"

A continuación tienes que crear un archivo llamado Dockerfile, con el siguiente contenido,

FROM alpine:3.13.0
COPY ./sample.sh /
CMD /bin/sh /sample.sh

A continuación ejecuta la instrucción podman build . --tag saludos:v1. Con el . después de build indicas que tiene que construir lo que se encuentra en el directorio, y con --tag etiquetas la imagen que acabas de crear.

Aunque lo verás mas adelanta, puedes comprobar tu recién creada imagen con la instrucción, podman image list, que te tiene que arrojar un resultado como el que te muestro a continuación,

REPOSITORY                TAG     IMAGE ID      CREATED         SIZE
localhost/saludos         v1      91d342cb93b7  7 minutes ago   5.88 MB

Aquí aparece la etiqueta de tu primera imagen, un número identificativo, la fecha de creación, y el tamaño de la imagen.

diff

diff detecta cambios en la imagen. Es decir, te muestra las diferencias con la capa anterior. Le puedes indicar el formato en el que quieres que te devuelva los resultados, aunque actualmente solo acepta el formato json.

Ahora puedes ejecutar la siguiente instrucción sobre la imagen que creaste en el apartado anterior podman image diff saludos:v1. Esto te devuelve lo siguiente,

A /sample.sh

Precisamente sample.sh es el archivo que has añadido en el directorio raíz de la imagen, y esa es justo la diferencia con la capa anterior.

exists

exists comprueba si existe una imagen localmente. Para esta comprobación tenemos que proporcionarle a Podman, o bien el nombre de la imagen o bien el ID. Podman, nos devolverá 0 en el caso de que exista o 1 en el caso de que no exista. En el caso de que nos devuelva 125 estaremos ante un error de acceso al almacenamiento local. Por ejemplo,

$ podman image exists saludos:v1
$ echo $?
0

Si hubieras buscado la imagen saludos:v2 te habría devuelto un 1.

history

history te da información sobre la historia de la imagen, desde el momento que se creó hasta nuestros días. De nuevo, para la primera imagen que has creado con Podman, puedes ejecutar podman image history saludos:v1. Esto te debería devolver algo similar a lo que te muestro a continuación,

ID            CREATED        CREATED BY                                     SIZE     COMMENT
5d506fa0fbeb  8 minutes ago  /bin/sh -c #(nop) CMD /bin/sh /sample.sh       0 B      
<missing>     8 minutes ago  /bin/sh -c #(nop) COPY file:c294989e6814b0...  2.05 kB  
7731472c3f2a  12 days ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]             0 B      
<missing>     12 days ago    /bin/sh -c #(nop) ADD file:edbe213ae0c825a...  5.88 MB

import

import es la herramienta complementaria a export. Te permite importar un archivo comprimido como una nueva imagen. Este archivo comprimido se obtiene a través de exportar un contenedor. Es decir, a partir del contenedor, creas una nueva imagen. Es posible modificar la imagen añadiendo determinadas opciones.

En el caso del ejemplo que estás utilizando no vas a poder crear una imagen del contenedor, porque tu contenedor se detiene inmediatamente, con lo que no te da tiempo material a hacer el export para luego hacer el import.

Si estás muy interesado en probar esto del import y export, puedes modificar el archivo sample.sh de la siguiente forma,

#!/bin/sh
sleep 20
echo "Hola mundo"

Te estás dando 20 segundos para crear ese export. A partir de aquí, crea la imagen como has visto anteriormente con podman build . --tag saludos:v2, y una vez creada la ejecutas con podman run -d --name saludos2 saludos:v2. Con esto y antes de que transcurran esos 20 minutos, tienes que exportar el contenedor a un archivo,

podman export saludos2 -o saludos2.tar

Y con esto habrás exportado el contenedor a un archivo tar. El siguiente paso sería importarlo. Algo tan sencillo como ejecutar el siguiente comando,

podman import saludos2.tar localhost/saludos:v3

inspect

inspect muestra información detallada de la configuración de una determinada imagen. Esta información la muestra en formato json.

Así en nuestro caso, puedes ejecutar podman image inspect saludos:v2, que te debería devolver un resultado como el que te muestro a continuación,

[
    {
        "Id": "dce32fb4130fcf543678a118c956a81e75bb617249593566276257593a644758",
        "Digest": "sha256:5c8195e7d3c0fc65e9453d59f200fcb34ff65fa4d0179f391a2d9242d9c5b1ce",
        "RepoTags": [
            "localhost/saludos:v2"
        ],
        "RepoDigests": [
            "localhost/saludos@sha256:5c8195e7d3c0fc65e9453d59f200fcb34ff65fa4d0179f391a2d9242d9c5b1ce"
        ],
        "Parent": "",
        "Comment": "",
        "Created": "2021-01-27T06:04:03.277249091Z",
        "Config": {
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "/bin/sh /saludos2.sh"
            ],
            "Labels": {
                "io.buildah.version": "1.18.0"
            }
        },
        "Version": "",
        "Author": "",
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 5886554,
        "VirtualSize": 5886554,
        "GraphDriver": {
            "Name": "overlay",
            "Data": {
                "LowerDir": "/home/lorenzo/.local/share/containers/storage/overlay/097c3bf65a7dca2825519097c11d706344469a8815d3fbeed0a95e6c29495f8f/diff:/home/lorenzo/.local/share/containers/storage/overlay/c04d1437198bc178b49fdb9a90a9c0e362ffbd63c4be5d19fec406d1c9d6a03c/diff",
                "UpperDir": "/home/lorenzo/.local/share/containers/storage/overlay/193a2abeaf31bf56fdac1bc93dc9304c9174696e525d1301f20da070e9d490de/diff",
                "WorkDir": "/home/lorenzo/.local/share/containers/storage/overlay/193a2abeaf31bf56fdac1bc93dc9304c9174696e525d1301f20da070e9d490de/work"
            }
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:c04d1437198bc178b49fdb9a90a9c0e362ffbd63c4be5d19fec406d1c9d6a03c",
                "sha256:3050e090b1e0ba49f21fb6b4abf1d49ed52dc87c9527dba28674c63c0e1f86e3",
                "sha256:5f553e79b0113e70a0b180bc373d52a4cb90e330a83efee9f6d5a7b965fa10c1"
            ]
        },
        "Labels": {
            "io.buildah.version": "1.18.0"
        },
        "Annotations": {},
        "ManifestType": "application/vnd.oci.image.manifest.v1+json",
        "User": "",
        "History": [
            {
                "created": "2021-01-15T02:23:51.062843845Z",
                "created_by": "/bin/sh -c #(nop) ADD file:edbe213ae0c825a5bfbe569928cf20f683f334f93a093ccd0a3a014b7428e760 in / "
            },
            {
                "created": "2021-01-15T02:23:51.238454884Z",
                "created_by": "/bin/sh -c #(nop)  CMD [\"/bin/sh\"]",
                "empty_layer": true
            },
            {
                "created": "2021-01-27T06:02:11.000445095Z",
                "created_by": "/bin/sh -c #(nop) COPY file:c294989e6814b092a5fa845cd1057ca9477dcab4c3a49b2f510ddb1fd6742c2f in / "
            },
            {
                "created": "2021-01-27T06:02:11.169382092Z",
                "created_by": "/bin/sh -c #(nop) CMD /bin/sh /sample.sh",
                "empty_layer": true
            },
            {
                "created": "2021-01-27T06:04:03.000412313Z",
                "created_by": "/bin/sh -c #(nop) COPY file:99d0d6c19f3ac47b7becaf5f58e89af58f432a399ba1f5e427b50a4650f93ef8 in / "
            },
            {
                "created": "2021-01-27T06:04:03.277595448Z",
                "created_by": "/bin/sh -c #(nop) CMD /bin/sh /saludos2.sh",
                "empty_layer": true
            }
        ],
        "NamesHistory": []
    }
]

Si te fijas aquí tienes información detallada de todo lo relativo a la imagen. Por ejemplo, la fecha de creación, la arquitectura o el sistema operativo, el tamaño que ocupa. Pero no solo esto, también puedes ver la historia, tal y como la has visto con uno de los comandos anteriores, pero además con la fecha de creación.

list

list o ls o también lo puedes utilizar directamente como podman images, muestra todas las imágenes que se encuentran en tu sistema.

En mi caso, el resultado es el siguiente, que diferirá del tuyo, dependiendo de las pruebas y ejemplos que hayas ido haciendo hasta aquí,

REPOSITORY                TAG     IMAGE ID      CREATED            SIZE
localhost/saludos         v3      674848ed9e80  32 minutes ago     5.88 MB
localhost/saludos         sleep   31ce9865fe9d  33 minutes ago     5.88 MB
localhost/saludos         v2      dce32fb4130f  46 minutes ago     5.89 MB
localhost/saludos         v1      7ce974065486  48 minutes ago     5.88 MB
<none>                    <none>  6c3afe27c334  51 minutes ago     5.88 MB
<none>                    <none>  a36d7d5e7b2c  52 minutes ago     5.88 MB
<none>                    <none>  60503d0b1277  53 minutes ago     5.88 MB
<none>                    <none>  91d342cb93b7  About an hour ago  5.88 MB
<none>                    <none>  79b016843d30  About an hour ago  5.88 MB
docker.io/library/alpine  3.13.0  7731472c3f2a  12 days ago        5.88 MB
docker.io/library/alpine  latest  7731472c3f2a  12 days ago        5.88 MB

load y save

load carga una imagen desde un archivo tar. Este archivo se crea a partir de una imagen en Podman con podman save. Se trata de un archivo oci o docker. Este comando carga por defecto desde la entrada por defecto stdin o desde un archivo utilizando la opción --input.

Para probar este comando puedes guardar una de tus imágenes, utilizando podman save y posteriormente restaurarla con podman load. Por ejemplo,

$ podman save saludos:sleep -o saludos.tar
$ podman image rm saludos:seep
$ podman load -i saludos.tar

También lo puedes hacer utilizando estas otras variantes para cargar el archivo .tar,

$ podman load < saludos.tar
$ cat saludos.tar | podman load

En este caso save te permite guardar una imagen a un archivo tar.

Para probar este comando puedes guardar una de tus imágenes, utilizando podman save y posteriormente restaurarla con podman load. Por ejemplo,

$ podman save saludos:sleep -o saludos.tar

mount y unmount

mount monta el sistema de archivos de una imagen. Para poder hacerlo, antes de ejecutar esta instrucción tienes que ejecutar podman unshare. Por ejemplo podman mount hello-world. Una vez la ha conseguido montar, te devuelve el directorio en donde lo hizo. Si ejecutas esta instrucción sin argumentos, Podman te devolverá el listado de todas las imágenes que se encuentran montadas. Por ejemplo,

$ podman unshare
$ podman image mount saludos:sleep

/home/lorenzo/.local/share/containers/storage/overlay/9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63/merged

$ podman image mount --format=json

[
 {
  "id": "bf756fb1ae65adf866bd8c456593cd24beb6a0a061dedf42b26a993176745f6b",
  "Names": [
   "sha256:31b9c7d48790f0d8c50ab433d9c3b7e17666d6993084c002c2ff1ca09b96391d"
  ],
  "Repositories": [
   "docker.io/library/hello-world:latest"
  ],
  "mountpoint": "/home/lorenzo/.local/share/containers/storage/overlay/9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63/merged"
 }
]

Ahora, te queda listar el contenido del directorio que te ha devuelto al realizar el montaje, es decir,

ls -la /home/lorenzo/.local/share/containers/storage/overlay/9c27e219663c25e0f28493790cc0b88bc973ba3b1686355f221c38a36978ac63/merged

Te vas a encontrar con una estructura de directorios que te resultará tremendamente familiar,

dr-xr-xr-x 19 root root 4096 ene 28 06:39 .
drwxr-xr-x  2 root root 4096 ene 14 12:49 bin
drwxr-xr-x  2 root root 4096 ene 14 12:49 dev
drwxr-xr-x 15 root root 4096 ene 14 12:49 etc
drwxr-xr-x  2 root root 4096 ene 14 12:49 home
drwxr-xr-x  7 root root 4096 ene 14 12:49 lib
drwxr-xr-x  5 root root 4096 ene 14 12:49 media
drwxr-xr-x  2 root root 4096 ene 14 12:49 mnt
drwxr-xr-x  2 root root 4096 ene 14 12:49 opt
dr-xr-xr-x  2 root root 4096 ene 14 12:49 proc
drwx------  2 root root 4096 ene 14 12:49 root
drwxr-xr-x  2 root root 4096 ene 14 12:49 run
-rw-rw-r--  1 root root   39 ene 27 07:16 sample.sh
drwxr-xr-x  2 root root 4096 ene 14 12:49 sbin
drwxr-xr-x  2 root root 4096 ene 14 12:49 srv
drwxr-xr-x  2 root root 4096 ene 14 12:49 sys
drwxrwxrwt  2 root root 4096 ene 14 12:49 tmp
drwxr-xr-x  7 root root 4096 ene 14 12:49 usr
drwxr-xr-x 12 root root 4096 ene 14 12:49 var

Como te puedes imaginar umount desmonta la imagen que hayas montado previamente. Puedes forzar a que se desmonte la imagen con --force, y puedes desmontar todas las imágenes que se encuentren montadas actualmente utilizando --all.

prune

prune te permite borrar todas las imágenes que no se están utilizando. Si utilizas la opción -a o --all, se borrarán todas las imágenes que no estén asociadas con ningún contenedor asociado. Se trata de un comando que tienes que utilizar con sumo cuidado para evitarte alguna sorpresa desagradable.

podman image prune --all --force

También tienes una opción interesante, como es --filter que te permite utilizar filtros para seleccionar que imágenes quieres borrar. Por ejemplo, si quisieras borrar todas las imágenes anteriores a una fecha determinada podrías hacerlo como en el siguiente ejemplo,

podman image prune --all --force --filter until=2021-1-1

pull y push

Con este comando Podman copia una imagen de un registro a la máquina en la que estés ejecutándolo. Si no has especificado otro registro, por defecto, Podman intentará traerse la imagen de Docker Hub. En el caso de que no hayas especificado ninguna etiqueta, Podman utilizará por defecto la etiqueta latest, e intentará copiar esa imagen del registro remoto al registro local, a tu máquina. Una vez que Podman ha copiado la imagen del registro remoto en el registro local se mostrará el número identificativo de la imagen. Por ejemplo,

$ podman pull atareao/hola-mundo

Completed short name "atareao/hola-mundo" with unqualified-search registries (origin: /etc/containers/registries.conf)
Trying to pull docker.io/atareao/hola-mundo:latest...
Getting image source signatures
Copying blob 5d20c808ce19 done  
Copying config 8f808bd8b0 done  
Writing manifest to image destination
Storing signatures
8f808bd8b04a5f27105d184a9283f21c7850ea75db6277588fffbce689097998

Como te indicaba anteriormente, por defecto, trae la imagen de Docker Hub, pero es posible traerla de otras fuentes, al igual que será posible subirla a otras fuentes, como verás en el siguiente apartado. Por ejemplo,

podman pull quay.io/dockerlibrary/hola-mundo

Por ejemplo, si hiciste push contra un directorio en tu equipo, puedes hacer un pull tal y como te muestro a continuación,

podman pull dir:/tmp/temporal

Este comando hace la justo la operación opuesta al anterior, es decir, en lugar de bajar la imagen de un registro, lo que hace es subirla. Da lo mismo donde la quieras subir, ya sea un registro local como un registro remoto. También, puedes hacerlo contra un directorio, como te muestro a continuación,

podman push saludos:sleep dir:/tmp/temporal

rm

Para borrar una imagen o varias imágenes, y liberar espacio en tu equipo puedes hacerlo utilizando podman image rm <ID> o también con podman rmi <ID>. Si lo que quieres es borrar todas las imágenes puedes hacerlo con la opción --all ó -a.

Con la opción --force o -f, se eliminarán todos los contenedores que están correspondientes a la imagen, antes de borrar la imagen del sistema. Así, si quieres borrar todas las imágenes y contenedores lo puedes hacer con podman rmi --all --force o podman rmi -a -f.

search

search te permite buscar imágenes en uno o varios registros. Puedes especificar en que registro quieres buscar alñadiendo el registro en el término de búsqueda. Por defecto, buscará en los registros que se encuentrend definidos en /etc/containers/registries.conf. En mi caso, por ejemplo, el contenido de este archivo es,

[registries.search]
registries = ['docker.io', 'quay.io']

De esta manera buscará en los dos registros. Si solo quisieras buscarlo en uno de ellos, por ejemplo en quay.io, lo podrías hacer de la siguiente forma,

podman search quay.io/hola-mundo

Además de esto también puedes utilizar filtros para realilzar tus búsquedas. Por ejemplo puedes buscar imágenes con un número determinado de estrellas,

podman search hola-mundo --filter stars=2

O también, buscar solo imágenes oficiales con,

podman search hola-mundo --filter is-official=true

sign

podman image sign crea una firma local para una o mas imágenes descargadas de un registro. Con la opción --cert-dir indicas la ruta en la que se encuentra el certificado. Con la opción --directory especificas donde se guardará las firmas, mientras que con --sign-in sobreescribes la identidad de la firma. Por ejemplo,

podman image sign --sign-by atareao@atareao.es --directory /tmp/signatures /tmp/temporal

tag y untag

Con estos dos comandos añades o quitas etiquetas a una imagen local. No solo es capaz de añadir una etiqueta si no también renombrar la imagen. Por ejemplo,

$ podman image tag hola:sleep hola:despierta
$ podman image tag hola:sleep adios:sleep
$ podman tag docker.io/atareao/hola-mundo saludos:sleep

En el caso de untag tienes que tener en cuenta que quita el nombre, de la imagen almacenada localmente.

tree

Imprime la jerarquía de capas de una imagen en formato de árbol, tal y como puedes ver en el ejemplo que te muestro a continuación,

$ podman image tree localhost/saludos:sleep

Image ID: f76e3ddccbc2

Tags:     [localhost/tmp/temporal:latest localhost/saludos:sleep localhost/sleepi:latest lo
calhost/saludos:sleepi]
Size:     5.884MB
Image Layers
├──  ID: c04d1437198b Size:  5.88MB Top Layer of: [docker.io/library/alpine:3.13.0]
└──  ID: db85b5fb6931 Size: 2.048kB Top Layer of: [localhost/tmp/temporal:latest localhost/
saludos:sleep localhost/sleepi:latest localhost/saludos:sleepi]

trust

Con este comando gestionas tu política de confianza, es decir, gestionas en que registros confias y en cuales no. Esto lo haces en base a su ubicación. Con la opción set estables cual es la política por defecto, mientras que con show muestras las políticasa de confianza que hay disponibles en tu sistema. Por ejemplo,

$ podman image trust show

default accept
        insecureAcceptAnything

Imagen de portada de Andre Mouton en Unsplash

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *