Una herramienta nativa para Linux que se ejecuta sin ser un servicio, es open source y está diseñada para ser fácil de utilizar. Se pueden ejecutar, construir, compartir y desplegar aplicaciones utilizando la definición “Open Containers Initiative (OCI)” e imágenes de contenedor. Los contenedores se pueden ejecutar siendo root o usuario sin privilegios sin hacer uso de ningún servicio que gestione prácticamente nada, que es lo contrario a Docker que es un servicio/cliente. Se pueden configurar los contenedores con systemd para que éstos inicien en caso de reinicio del sistema, por lo que es muy bueno.
¿Qué es la OCI?
La Open Containers Initiative es un pequeño gobierno establecido en 2015 por Docker y otros líderes en la industria de los contenedores que tienen como objetivo implementar estándares abiertos en la industria que gira en torno a los contenedores con el fin de evitar que múltiples empresas generen sus propios formas de crear y desplegar contenedores volviendo a un escenario de los 90 como pasó con las redes, que si un edificio tenía el producto de una empresa A, no era compatible con los dispositivos de la empresa B.
Actualmente hay dos tipos de especificaciones:
La especificación de tiempo de ejecución (runtime-spec) y la especificación de la imagen (image-spec). La primera trata de ver cómo se desempaqueta la imagen y se ejecuta, y en la segunda es cómo y dónde se descarga o se almacena la imagen que contiene ese sistema de archivos y que se ejecutará convirtiéndose en un contenedor. Las imágenes contienen tags para definir las versiones, por ejemplo, rockylinux:latest
o rockylinux
a secas se refiere a latest
. Sin embargo, el proyecto puede tener versiones, por ejemplo:
- rockylinux:8.5
- rockylinux:7.9
- rockylinux:alpha-stage
- […]
¿Cómo se puede usar?
Se puede utilizar desde usuario root
o desde un usuario sin privilegios siempre y cuando tenga el subid y subgid definidos.
Comandos de creación
Crear un contenedor con bash basado en una imagen de Rocky Linux
podman run -ti rockylinux:latest /bin/bash
Crear un contenedor con bash basado en una imagen cuya tag es la 8.5
podman run -ti rockylinux:8.5 /bin/bash
Crear un contenedor con nombre único
podman run -ti --name micontenedor rockylinux:latest /bin/bash
NOTA: Si no eliminas el contenedor, no podrás lanzar más contenedores con este nombre.
Crear una red
podman create network nombre_red
Crear un volumen
podman create volume nombre_volumen
Crear un contenedor con una red creada
podman run -ti --network hola_mundo rockylinux /bin/bash
Crear un contenedor con un volumen creado o crearlo “al vuelo”
NOTA: Es un volumen persistente, no se elimina después de finalizar el contenedor
podman run -ti --volume nuevo_volumen:/tmp/my_vol rockylinux /bin/bash
Crear un contenedor y utilizar un archivo como volumen persistente
podman run -ti --volume /home/sincorchetes/hello_world.txt:/tmp/hello_world.txt rockylinux /bin/bash
Crear un contenedor y utilizar un directorio como volumen persistente
podman run -ti --volume /home/sincorchetes/hello_world:/tmp/hello_world rockylinux /bin/bash
Crear un contenedor que se ejecute en segundo plano
NOTA: Este contenedor no tiene acceso al exterior, si haces un
curl 127.0.0.1:80
no dará respuesta, además estará mal si lo ejecutas como usuario sin privilegios, ya que el kernel por seguridad no permite exponer programas con puertos inferiores a 1024.
podman run -d nginx
Crear un contenedor que se ejecute en segundo plano y con mapeo de puertos
podman run -d -p 8080:80 nginx
Si haces un curl 127.0.0.1:8080
obtendrás la página de bienvenida de NGINX
Genera una plantilla servicio para que se ejecute en systemd
podman generate systemd nombre_contenedor|id_imagen
NOTA: Nos genera un
.service
en la salida de la terminal que podemos añadir como servicio del sistema o de usuario. Hay que añadirlo no se configura solo.
Ejemplo:
podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a138796be81d docker.io/library/nginx:latest nginx -g daemon o... 21 minutes ago Up 21 minutes ago inspiring_hertz
podman generate systemd inspiring_hertz
# container-a138796be81d92ae13c7390fe65f3544558ec4640ed20446ac6595e24446dc27.service
# autogenerated by Podman 3.4.4
# Thu Jan 20 17:40:51 WET 2022
[Unit]
Description=Podman container-a138796be81d92ae13c7390fe65f3544558ec4640ed20446ac6595e24446dc27.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/user/1000/containers
[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman start a138796be81d92ae13c7390fe65f3544558ec4640ed20446ac6595e24446dc27
ExecStop=/usr/bin/podman stop -t 10 a138796be81d92ae13c7390fe65f3544558ec4640ed20446ac6595e24446dc27
ExecStopPost=/usr/bin/podman stop -t 10 a138796be81d92ae13c7390fe65f3544558ec4640ed20446ac6595e24446dc27
PIDFile=/run/user/1000/containers/overlay-containers/a138796be81d92ae13c7390fe65f3544558ec4640ed20446ac6595e24446dc27/userdata/conmon.pid
Type=forking
[Install]
WantedBy=default.target
Si queremos guardarlo, redirigimos la salida
podman generate systemd inspiring_hertz > nginx.service
Generando una plantilla para Kubernetes
podman generate kube
Ejemplo:
podman generate kube inspiring_hertz
# Save the output of this file and use kubectl create -f to import
# it into Kubernetes.
#
# Created with podman-3.4.4
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2022-01-20T17:43:58Z"
labels:
app: inspiringhertz
name: inspiringhertz
spec:
containers:
- args:
- nginx
- -g
- daemon off;
image: docker.io/library/nginx:latest
name: inspiringhertz
securityContext:
capabilities:
drop:
- CAP_MKNOD
- CAP_NET_RAW
- CAP_AUDIT_WRITE
Si queremos guardarlo, redirigimos la salida
podman generate kube inspiring_hertz > nginx.yaml
Y para ejecutarlo en nuestro cluster (necesitaremos tener kubectl configurado)
kubectl apply -f nginx.yaml
Comandos de construcción
Modificar una imagen
podman run -ti rockylinux /bin/bash
# dnf install -y tmux
[...]
Installed:
libevent-2.1.8-5.el8.x86_64 tmux-2.7-1.el8.x86_64
Complete!
En otra terminal, recuperamos el contenedor
podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d56ed882cbc1 docker.io/library/rockylinux:latest /bin/bash 59 seconds ago Up About a minute ago funny_stonebraker
Hacemos un commit y lo guardamos con otro nombre
podman commit d56ed882cbc1 rockylinux_custom
Getting image source signatures
Copying blob 65dbea0a4b39 skipped: already exists
Copying blob 741ec203d982 done
Copying config 515a64e7ed done
Writing manifest to image destination
Storing signatures
515a64e7ed4cbb778b043820de1ee9054c62a83c3e0462f21b188263374ba522
Ejecutando la nueva imagen
podman run -ti rockylinux_custom tmux
Ó
podman run -ti rockylinux_custom /usr/bin/tmux
Construir una imagen partiendo de un Containerfile
Podemos hacer lo anterior, pero en vez de usar ese método, utilizar un Containerfile que nos da más libertad y facilidad, también te valen los Dockerfile, recordemos (OCI compliant)
Crearmos un archivo Containerfile
mkdir imagen
touch imagen/Containerfile
Editamos imagen/Containerfile
FROM rockylinux:latest
RUN dnf install -y tmux
CMD ["/usr/bin/tmux"]
Construimos la imagen:
podman build -t rockylinux_custom image
Arrancamos la imagen
podman run -ti rockylinux_custom
Se nos abrirá con tmux directamente.
Comandos para listar
Listar imágenes
podman image ls
Listar redes
podman network ls
Listar volúmenes
podman volume ls
Listar todos los ID de las imágenes
podman image ls | awk 'NR>1 { print $3 }'
Listar todos los ID de los contenedores que se están ejecutando
podman ps | awk 'NR>1 { print $3 }'
Listar todos los ID de los contenedores que se están o hayan sido ejecutados
podman ps -a| awk 'NR>1 { print $3 }'
Listar solo el nombre de los volúmenes
podman volume ls | awk 'NR>1 { print $2 }'
Listar solo el ID de las redes y su nombre
podman network ls | awk 'NR>1 { print $2 }'
Comandos de búsqueda
Buscar en todos los registries
podman search rockylinux
Buscar en un solo registry
podman search docker.io/rockylinux
Comandos para eliminar
Eliminar contenedor en ejecución
podman rm -f ID_contenedor
Eliminar volumen
NOTA: No debe haber ningún contenedor que esté explotando el volumen
podman volume rm nombre_volumen
Eliminar una imagen
podman image rm nombre_imagen
Eliminar una imagen (forma corta)
podman rmi nombre_imagen
Eliminar una red
podman network rm nombre_red
Eliminar imágenes que no se están utilizando
podman image prune
Eliminar todos los contenedores incluyendo los que ya han finalizado
podman rm -f $(podman ps -a | awk 'NR>1 { print $1 }')
Exportación/Importación
Exportar el FS de un contenedor en ejecución
podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c5d483dc9b77 docker.io/library/nginx:latest nginx -g daemon o... About a minute ago Up About a minute ago intelligent_archimedes
podman export c5d483dc9b77 > myfs.tar
Tendremos todo el contenido del contenedor exportado.
Importar un contenedor
podman import myfs.tar
Getting image source signatures
Copying blob 0f3fecb21929 done
Copying config d485510f4c done
Writing manifest to image destination
Storing signatures
sha256:d485510f4c1ba2ba61bbd2bcdd2e632f404be7ae90b81370fda41dd16b9d3936
podman image ls
[...]
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> d485510f4c1b 43 seconds ago 144 MB
¡Perfecto!
Comandos de ejecución
Si tenemos contenedores ejecutándose podemos acceder desde otra consola aunque el contenedor lo tengamos abierto en primer/segundo plano.
Obtenemos el contenedor al que queremos acceder
podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a138796be81d docker.io/library/nginx:latest nginx -g daemon o... 3 seconds ago Up 3 seconds ago inspiring_hertz
Accedemos a él
podman exec -ti a138796be81d /bin/sh
# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
También podemos acceder a él por el nombre
podman exec -ti inspiring_hertz /bin/sh
Troubleshooting
No puedo crear un contenedor con puertos inferiores al 1024 cuando lo trato de exponer, obtengo este mensaje:
podman run -d -p 80:8080 nginx
Error: rootlessport cannot expose privileged port 80, you can add 'net.ipv4.ip_unprivileged_port_start=80' to /etc/sysctl.conf (currently 1024), or choose a larger port number (>= 1024): listen tcp 0.0.0.0:80: bind: permission denied
Esto es debido a seguridad del kernel, solo root
puede hacerlo, se puede remediar haciendo caso al mensaje, pero es mejor desplegar un reverse-proxy que atienda a los puertos no privilegiados.
Trato de eliminar una imagen y obtengo este resultado, sin embargo, no tengo ningún contenedor que la use:
podman image rm rockylinux
Error: Image used by 260f1173937ca4c82b345f54c3723908d6c4165936870914922a62e42076da00: image is in use by a container
Para solucionarlo:
podman ps -a
[...]
260f1173937c docker.io/library/rockylinux/rockylinux:latest bash 2 days ago Exited (0) 2 days ago
[...]
podman rm -f 260f1173937c
podman image rm rockylinux
Untagged: docker.io/library/rockylinux:latest
Deleted: 300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55
O también
podman image rm -f rockylinux
NOTA: Esto eliminará también el contenedor que use la imagen.
Otra forma de eliminar una imagen
podman rmi rockylinux
podman rmi -f rockylinux
Trato de eliminar una red y obtengo este resultado, pero no hay ningún contenedor ejecutándose:
podman network rm hola
Error: "hola" has associated containers with it. Use -f to forcibly delete containers and pods: network is being used
Lo mismo sucede aquí, hay que forzar la eliminación y eso implica eliminar el contenedor que finalizó la ejecución.
podman network rm -f hola
hola
No puedo montar los archivos o directorios como volúmenes persistentes, pero forman parte de mi usuario
NOTA: Esto se debe a la protección de SELinux,
Z
le dice a podman que usas SELinux en el sistema
podman run -ti --volume /home/sincorchetes/Downloads:/tmp/Downloads:Z rockylinux /bin/bash
podman run -d --volume /home/sincorchetes/Downloads:/tmp/Downloads:Z nginx
No puedo acceder a un contenedor en ejecución con exec
podman exec -ti a138796be81d /bin/ksh
Error: executable file `/bin/ksh` not found in $PATH: No such file or directory: OCI runtime attempted to invoke a command that was not found
Esto se debe porque no soporta esa shell o ese comando, si sabes la ruta
podman exec -ti a138796be81d cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/bin/rbash
/bin/dash
podman exec -ti a138796be81d /bin/dash
# echo $0
dash
Si buscas un archivo, pues un ls
podman exec -ti a138796be81d ls /etc
adduser.conf deluser.conf host.conf localtime pam.conf rc6.d subuid
alternatives dpkg hostname login.defs pam.d rcS.d systemd
apt e2scrub.conf hosts logrotate.d passwd resolv.conf terminfo
bash.bashrc environment init.d machine-id passwd- rmt timezone
bindresvport.blacklist fonts inputrc mke2fs.conf profile security ucf.conf
ca-certificates fstab issue motd profile.d selinux update-motd.d
ca-certificates.conf gai.conf issue.net mtab rc0.d shadow xattr.conf
cron.d group kernel netconfig rc1.d shadow-
cron.daily group- ld.so.cache nginx rc2.d shells
debconf.conf gshadow ld.so.conf nsswitch.conf rc3.d skel
debian_version gshadow- ld.so.conf.d opt rc4.d ssl
default gss libaudit.conf os-release rc5.d subgid