2 puntos por GN⁺ 2025-03-25 | 1 comentarios | Compartir por WhatsApp
  • Como Podman no tiene daemon, después del arranque del servidor se necesita un ejecutor que levante los contenedores de forma confiable, y Quadlet lo resuelve con el enfoque de archivos de servicio de systemd
  • El método anterior, podman generate systemd, obligaba a manejar por separado la creación del contenedor y la generación del archivo de servicio, y cada vez que había que cambiar el archivo generado aparecía la carga de editarlo manualmente
  • Quadlet coloca juntos los ajustes de [Container], [Service] y [Install] en archivos .container dentro de ~/.config/containers/systemd, para administrar en un solo lugar las opciones de Podman y el comportamiento de systemd
  • En Podman rootless, para el inicio automático al arrancar se necesita WantedBy=default.target y habilitar linger; multi-user.target no está definido en modo de usuario
  • Si se aprovechan AutoUpdate=registry, las dependencias de systemd, la agrupación de archivos por directorio y la herramienta de conversión podlet, Quadlet encaja bien con la operación de Podman rootless y sin daemon

Por qué hace falta Quadlet

  • Quadlet es una forma de ejecutar contenedores Podman como si fueran servicios de systemd
    • Permite ejecutar contenedores en segundo plano
    • Permite iniciar contenedores automáticamente después de reiniciar el servidor
  • La idea de ejecutar contenedores Podman bajo systemd no es nueva
    • Antes se usaba el comando podman generate systemd
    • Ese comando ahora muestra una advertencia de obsolescencia que recomienda migrar a Quadlet
  • Como Podman tiene una arquitectura daemonless, se necesita un ejecutor que inicie los contenedores sin depender de un daemon

Incomodidades del método anterior con podman generate systemd

  • Con el método anterior, primero había que crear el contenedor con podman create
    • El contenedor de ejemplo usa la imagen docker.io/library/postgres:16
    • Incluye -p 5432:5432, montaje de volúmenes, la variable de entorno POSTGRES_PASSWORD y la etiqueta io.containers.autoupdate=registry
  • Luego se ejecutaba podman generate systemd test-db -fn --new para generar el archivo container-test-db.service
  • El archivo de servicio generado se ubicaba en ~/.config/systemd/user y se habilitaba e iniciaba con el siguiente comando
    • systemctl --user enable --now container-test-db
  • Este flujo obliga a repetir la creación del contenedor, la generación del archivo de servicio, el traslado del archivo si hace falta y la habilitación del servicio
  • Si el comando de creación del contenedor se vuelve largo, había que mantener aparte un script de shell para poder volver a ejecutarlo más adelante
  • Para personalizar el archivo de servicio systemd generado, había que volver a modificarlo manualmente cada vez

Estructura de archivos de Quadlet

  • Con Quadlet, se crea el directorio ~/.config/containers/systemd y dentro se colocan archivos .container
  • El archivo de ejemplo test-db.container incluye los siguientes elementos
    • [Container]
      • Image=docker.io/library/postgres:16
      • AutoUpdate=registry
      • PublishPort=5432:5432
      • Volume=%h/volumes/test-db:/var/lib/postgresql/data:Z
      • Environment=POSTGRES_PASSWORD=CHANGE_ME
    • [Service]
      • Restart=always
    • [Install]
      • WantedBy=default.target
  • Un archivo .container es un archivo de servicio systemd común, pero incluye una sección especial [Container]
  • Muchas opciones de [Container] corresponden a opciones de línea de comandos usadas en podman create
    • Image: imagen y etiqueta que se usarán
    • AutoUpdate=registry: corresponde a --label "io.containers.autoupdate=registry"
    • PublishPort: corresponde a -p
    • Volume: corresponde a -v
    • Environment: corresponde a -e
  • Para el directorio home del usuario se debe usar el especificador de systemd %h en lugar de ~
  • Restart=always en [Service] hace que el contenedor se reinicie siempre, salvo que se lo detenga manualmente
  • WantedBy=default.target en [Install] hace que el contenedor se inicie automáticamente al arrancar

Configuración de systemd necesaria en Podman rootless

  • En contenedores rootless se debe usar default.target, no multi-user.target
    • multi-user.target no está definido en el modo de usuario de systemd
    • Se puede comprobar con systemctl --user status multi-user.target
    • En modo de sistema se puede comprobar con systemctl status multi-user.target
  • Como el contenedor se ejecuta como servicio de usuario de systemd, si se quiere que arranque aunque el usuario no inicie sesión, hay que habilitar linger
    • loginctl enable-linger
  • Si se necesita inicio automático después de reiniciar el servidor, habilitar linger es obligatorio
  • Para que systemd descubra el nuevo archivo de servicio, se ejecuta el siguiente comando
    • systemctl --user daemon-reload
  • El inicio del contenedor y la consulta de estado se pueden hacer tanto desde systemd como desde Podman
    • systemctl --user start test-db
    • systemctl --user status test-db
    • podman ps
  • El nombre predeterminado del contenedor tiene la forma del nombre del archivo de servicio con systemd- como prefijo
    • El nombre predeterminado del contenedor para test-db.container es systemd-test-db
    • Es una convención de nombres para evitar conflictos
    • Se puede especificar directamente con la opción ContainerName en la sección [Container]

Ventajas operativas de Quadlet

  • Quadlet permite administrar la configuración de servicios de contenedores en un solo archivo
    • No hace falta mantener por separado un script que genera archivos de servicio y los archivos de servicio generados, como en el método anterior
  • Se pueden usar las opciones disponibles en las secciones [Unit] y [Service] de systemd
    • Por ejemplo, se puede especificar con StartExecPre un comando que se ejecute antes de iniciar el contenedor
    • Se reduce el proceso de corregir manualmente el archivo generado más adelante
  • En lugar de escribir y depurar scripts de shell, se pueden operar los contenedores alrededor de archivos de configuración
  • Es más fácil expresar dependencias entre contenedores con el enfoque de systemd

Expresar dependencias entre contenedores

  • Si un contenedor de aplicación depende de un contenedor de base de datos, se puede definir la relación con la sección [Unit] de systemd
  • El contenedor OxiTraffic es un ejemplo que depende del contenedor test-db
    • Al configurar Requires=test-db.service en [Unit], la aplicación solo se inicia cuando se inicia la base de datos
    • Al configurar After=test-db.service, se evita que ambos contenedores se inicien en paralelo
  • Al referenciarlo, se usa el nombre del servicio, no el nombre del archivo .container
    • test-db.container: nombre del archivo
    • test-db.service: nombre del servicio
    • systemd-test-db: nombre predeterminado del contenedor
  • Para que la aplicación se comunique con la base de datos, ambos contenedores deben agregar la opción Network en la sección [Container], pero aquí no se cubre networking

Varios archivos y agrupación

  • Quadlet se puede configurar con un archivo .container separado por cada contenedor
  • En comparación con poner toda una app multicontenedor en un solo archivo Docker Compose, tener archivos por contenedor puede reducir la carga cognitiva
  • Si un archivo Docker Compose incluye cientos de líneas y decenas de contenedores, puede volverse difícil de mantener
  • Docker Compose también soporta la función de dividirse en varios archivos
  • Quadlet permite poner archivos unit en directorios dentro de ~/.config/containers/systemd
    • En el ejemplo, se puede crear el directorio oxitraffic y colocar juntos los archivos de la aplicación y la base de datos

Actualización de imágenes

  • Si se configura AutoUpdate=registry, se pueden comprobar actualizaciones de imágenes con podman auto-update
  • Si en el registry hay una imagen nueva compatible con la etiqueta en uso, Podman hace pull de la imagen y reinicia el contenedor
  • En Docker podría hacer falta una herramienta como Watchtower para este uso, pero Podman ofrece esa función de forma nativa
  • Etiquetas como latest pueden ser riesgosas
    • En OxiTraffic, latest puede incluir breaking changes de la siguiente versión
    • Si se usa latest en PostgreSQL, puede subir a una nueva versión major, y las actualizaciones major de PostgreSQL siempre requieren migración manual
  • En producción se deben usar etiquetas que no lleven a breaking changes
  • También es posible ejecutar manualmente podman auto-update cada algunos días para ver qué se actualizó y luego verificar que los contenedores funcionen correctamente

podman-compose y herramientas de migración

  • podman-compose es un script en Python que ejecuta archivos Compose con Podman
  • Las razones por las que es difícil verlo como una alternativa de largo plazo a Docker Compose son las siguientes
    • Es una capa de traducción entre la especificación Compose y Podman/systemd, y no permite usar todas las capacidades de systemd
    • El proyecto oficial de Podman está escrito en lenguajes compilados como Rust o Go
    • El último commit fue hace 5 meses, por lo que no parece tener mantenimiento activo
  • Quadlet encaja mejor con el diseño rootless y daemonless de Podman
  • Para probar Quadlet a partir de archivos Compose se puede usar podlet
    • Es una herramienta en Rust que puede crear archivos Quadlet a partir de comandos Podman o archivos Docker Compose

Lecturas adicionales

1 comentarios

 
GN⁺ 2025-03-25
Opiniones de Hacker News
  • Quadlet es de lo mejor que ha salido de Podman, y lo recomiendo mucho a cualquiera que tenga curiosidad por Podman o quiera migrar a cargas de trabajo basadas en contenedores
    Permite integrar y manejar contenedores como servicios normales del sistema, sin tener que aprender una capa de orquestación aparte ni depender de recursos que no son contenedores para hacerlos funcionar juntos
    Simplemente escribes las unidades systemd como siempre, y las actualizaciones automáticas o el reinicio/notificación del servicio ante fallas vienen de regalo
    Las formas de intentar hacer algo parecido con Docker solían esquivar el daemon de Docker con enormes comandos run, y muchas veces dejaban servicios y contenedores fantasma; Quadlet es mucho más limpio, y la configuración queda junto con las unidades de systemd en ubicaciones como /etc/systemd/, .config/systemd, /usr/local/lib/systemd, lo que facilita hacer respaldos
    Eso sí, no es la respuesta a docker-compose para desarrollo local, y el equipo de Podman tampoco parece muy interesado en ese ámbito
    Los contenedores de usuario son buenos para infraestructura local de pruebas de larga duración, como bases de datos en segundo plano, pero son demasiado engorrosos para el flujo típico compilar → docker compose up → probar → docker compose down
    La respuesta realista es usar Quadlet .kube (Kubernetes play) o usar docker compose contra el socket de Podman
    Me gustó tanto que llevo meses, en mi tiempo libre, creando una herramienta GitOps para gestionar Quadlet, y se siente como la forma correcta de administrar servidores contenerizados
    Es importante que [0] no sea podman-compose. El artículo también señalaba que podman-compose no es muy bueno y le falta desarrollo. Podman implementa la mayor parte de la especificación de compose, así que en la mayoría de los casos se puede usar docker compose
    Es muy probable que quienes probaron Podman cuando RH empezó a impulsarlo se hayan ido por lo ambiguo que era Podman 3 y la mala experiencia con podman-compose

    • Quería acercarme más al enfoque de RH y probé Quadlet y podlet, pero la experiencia viniendo de docker compose sobre Podman fue horrible
      Entre cambiar varias flags, subir versiones y seguir el flujo en el que el propio podlet recomendaba cambiar a otra herramienta, terminé en un agujero de conejo interminable
      Al final, mi systemd simplemente ejecuta podman compose up
      Me pregunto qué ventaja tiene Quadlet frente a dejar que compose haga su trabajo
      Como referencia, Podman corre con mi usuario y no hay ningún daemon
    • El truco para desarrollo es activar el socket de Podman y, si son contenedores rootless, activarlo a nivel de usuario, y luego usar el docker-compose independiente
    • En Windows o Mac no se puede usar systemd, así que al final solo queda podman compose
  • Hace poco descubrí Quadlet y armé todo mi homelab sobre atomic OS y Quadlet rootless; lo recomiendo muchísimo
    También permite activación por sockets de systemd; por ejemplo, se pueden crear sockets http/https de systemd y activar automáticamente Traefik, igual que ssh.socket y podman.socket activan sshd.service y podman.service, respectivamente
    En una configuración rootless, es prácticamente la única forma de conservar la IP de origen, así que ha sido casi un salvavidas. Podman/Docker rootless normalmente no permiten conservar fácilmente la IP de origen sin grandes desventajas
    https://github.com/savely-krasovsky/homelab

    • Me pregunto cuánto tarda Traefik en activarse
  • Quadlet es una buena alternativa para el uso de docker compose de “ejecutar todos los contenedores interdependientes en un entorno parecido a producción”.
    Pero me gustaría que fuera mejor para el otro uso de docker compose: el desarrollo.
    Con docker compose puedes levantar juntos una base de datos, Redis, OpenSearch, otras dependencias, un proxy nginx y un contenedor de desarrollo con .:/app montado como volumen; eliminarlos juntos; y guardar docker-compose.yml en el repositorio.
    Quadlet te pide poner todos los archivos en ~/.config/containers/systemd, así que ya no quedan aislados dentro del proyecto, y tampoco es cómodo hacer check-in para compartirlos con otros desarrolladores. Además, ellos también tendrían que usar Podman.
    La mayoría todavía usa Docker, y en entornos de desarrollo hospedados como Codespaces también se ofrece Docker.
    Por eso uso docker compose con un archivo YAML versionado. Como yo uso Podman, tengo que agregar manualmente :Z a todos los volúmenes, pero Docker normal no puede manejar eso.
    Me gustaría que hubiera una alternativa a docker compose para desarrollo, pero Quadlet no parece encajar bien.

    • Si usas podman-compose --in-pod=1 systemd -a create-unit, puedes crear un servicio podman-compose@, y luego registrar un archivo compose.yml junto con $name mediante podman-compose systemd -a register.
      Así puedes administrar un pod basado en un archivo compose como podman-compose@$name.service, y también funciona de forma completamente rootless.
    • En este caso, lo que buscas es un pod de Podman, y yo orquestaría todo eso con Ansible y luego distribuiría el playbook de Ansible a todos para que lo ejecuten localmente.
    • systemd-run te permite ejecutar servicios systemd transitorios basados en comandos arbitrarios.
      Si hace falta, crea unidades transitorias prolijas que siguen las reglas de alcance de systemd, incluso con timers.
      [1] https://www.freedesktop.org/software/systemd/man/systemd-run...
    • Diría que Quadlet es, en general, más bien para despliegue. Si buscas una alternativa a compose, conviene mirar Podman Kube Play[1].
      Tiene un formato parecido a Kubernetes, con algunas funciones prácticas adicionales como la compilación de contenedores.
      Si pones el archivo kube play en la raíz del proyecto y ejecutas podman kube play project.yaml --build, se ejecutan juntos los pods, volúmenes, etc.
      Los archivos Quadlet son útiles en la etapa de despliegue. Si quieres subir el proyecto a un VPS, puedes usar Kube Quadlet[2] junto con el project.yaml que ya tienes.
      [1] https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
      [2] https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
    • En nuestra empresa también usamos docker-compose.yml para desarrollo, así que entiendo el dolor.
      En general funciona muy bien, pero en OSX a veces se comporta raro por culpa de esa maldita VM intermedia.
      De vez en cuando reviso la compatibilidad con Podman, pero ya acepté que, por la gran diferencia en la filosofía rootless, la compatibilidad total es imposible.
      Aun así, esta herramienta es genial para producción. Tengo algunos proyectos personales corriendo en nodos bare metal con servicios systemd hechos a mano, y actualmente usan containerd en modo de usuario.
      Si encuentro tiempo, tal vez los migre.
  • Es curioso que este artículo diga que Podman-Compose “no se mantiene activamente”, señalando que el último commit fue hace 5 meses, y enseguida recomiende como alternativa Podlet, cuyo último commit también fue hace 5 meses.
    Podlet puede ser útil, pero no soporta muchas funciones de Docker Compose y no siempre hace conversiones limpias.
    En particular, no soporta apilar varios archivos YAML como -f docker-compose.yml -f docker-compose.override.yml.

    • Si te gustan los archivos compose, puedes usar la aplicación compose de Docker[1] junto con Podman[2].
      Parece que la CLI de compose controla el motor mediante un socket, y los motores de Podman y Docker tienen prácticamente la misma API.
      Uso este método porque podman-compose no se comportaba como esperaba.
      Docker-compose normalmente se instala como un plugin del cliente docker, pero yo lo uso como aplicación independiente para usarlo con Podman.
      Además, para la configuración de integración prefiero los contexts de docker antes que la variable de entorno DOCKER_HOST.
      Si Quadlet puro no te resulta lo suficientemente potente, Quadlet[3] y Podman normal[4] también soportan la ejecución limitada de manifiestos de Kubernetes.
      Todavía no he logrado entender cómo maneja Podman la opción restart de los archivos compose, porque Podman no tiene un demonio supervisor.
      En cambio, sí sé que la opción healthcheck depende de temporizadores de systemd.
      Cuando usé Podman en Gentoo, una distribución sin systemd, los chequeos de salud automáticos no funcionaban, pero al ejecutar manualmente el healthcheck el resto de la configuración avanzaba hasta el final.
      [1] https://github.com/docker/compose
      [2] https://docs.podman.io/en/latest/markdown/podman-system-serv...
      [3] https://docs.podman.io/en/latest/markdown/podman-systemd.uni...
      [4] https://docs.podman.io/en/latest/markdown/podman-kube-play.1...
    • Para ser justos, las funciones de Podlet no necesitan actualizaciones constantes, pero podman compose sí.
      Podlet es una herramienta auxiliar y, a largo plazo, es mejor trabajar con Quadlet.
    • La fecha del commit no es precisa para demostrar que algo está mantenido, pero sí puede demostrar que no lo está.
      5 meses no significa que no esté mantenido; tendría que ser algo como 2 años.
      Aun así, aumenta la preocupación. Pero 5 meses de ninguna manera son prueba de que esté mantenido.
      Hay muchas razones por las que un repositorio no mantenido podría actualizarse, y solo la reciente y mediocre función de archivado de GitHub puede impedirlo.
  • Hace unos años, al reiniciar mi configuración de self-hosting, quería probar algo distinto, así que elegí openSUSE MicroOS, y terminé corriendo contenedores de Podman bajo systemd/Quadlet. Estoy bastante conforme con mi configuración actual.
    Los contenedores se actualizan automáticamente con las herramientas integradas de Podman, y la revisión de logs y el monitoreo los manejo con las herramientas habituales de systemd.
    Cuando tengo que cambiar algo, aunque haya olvidado dónde están los archivos de configuración, es fácil encontrarlos, leerlos y modificarlos.
    También está bueno que sea rootless y daemonless.
    Probé varias cosas en el camino, pero podman compose se sentía torpe; me alegra que esté deprecated y está claro que Quadlet es el camino a seguir.
    Hay que tener en cuenta que tiene curva de aprendizaje y menos material que Docker.
    Para desarrollo local, si se trata de levantar y bajar stacks de varios servicios, todavía elegiría Docker y docker compose.

    • Estoy corriendo Nextcloud con Fedora CoreOS en una workstation vieja y barata.
      Me tomó algo de tiempo ajustar la configuración, pero me impresionó mucho lo poco que requiere mantenimiento. Hasta ahora, nada en absoluto.
      Quien quiera intentar algo similar puede consultar mi configuración.
      https://github.com/jeppester/coreos-nextcloud
    • La combinación Quadlet + MicroOS es muy potente, y lo mismo aplica a otras distribuciones atomic como Fedora CoreOS.
      Estoy migrando lentamente todos mis nodos a MicroOS, y en la empresa también estamos impulsando MicroOS o algo similar.
      La combinación de rollback automático del sistema operativo base con configuración declarativa de contenedores y actualizaciones automáticas se siente como un encaje perfecto.
  • El formato es más claro que podman generate systemd o YAML de Kubernetes, y la integración con systemd también es excelente.
    Lo molesto es que Podman upstream no ofrece repositorios para Debian/Ubuntu.
    En Debian stable quedé atado a la 4.3.1, perdiéndome muchas funciones nuevas, y al final decidí volver a Docker compose.

    • Me encontré con el mismo problema al intentar usar Quadlet en una Raspberry Pi con Debian.
      Las soluciones alternativas propuestas eran compilar Podman uno mismo o usar debian/testing.
  • De verdad espero que este nuevo enfoque ayude a la gente a pasar de Docker a Podman
    Docker Compose es una razón por la que mucha gente duda en hacer el cambio, y a mí también me pasó
    Siendo honestos, antes de Quadlet Podman no tenía una respuesta realmente adecuada
    Si Docker Compose era lo que te hacía dudar de dejar Docker, Podman con Quadlet es una alternativa mucho más comparable
    Probablemente extrañes Docker menos de lo que crees, y además obtendrás una mejora de seguridad al ejecutar contenedores rootless

    • No voy a hacer el cambio hasta que se puedan tener varios entornos Quadlet independientes
      Eso de poner todo en ~/.config/quadlet/systemd no sirve
      Para desarrollo y pruebas esto es indispensable, y hoy Quadlet es estrictamente una solución de despliegue
  • Me gusta mucho Quadlet porque permite usar contenedores como servicios normales del sistema
    Pero la experiencia de usuario de los contenedores rootless no encaja bien con esa conceptualización
    Normalmente los servicios del sistema se ejecutan como usuarios del sistema en una sesión systemd del sistema, pero los servicios de contenedores rootless existen en la sesión systemd de usuario de un usuario del sistema
    Sería bueno poder ejecutar Quadlet rootless dentro de la sesión del sistema

    • Me pregunto si hay alguna diferencia práctica con activar user-linger y ejecutarlo como rootless mediante systemd de usuario
      Yo siempre lo he hecho así
    • A mí también me gustaría poder ejecutar Quadlet rootless dentro de la sesión del sistema
      También me gustaría poder ejecutar Quadlet rootless con la opción DynamicUser=
      DynamicUser= era una excelente forma de limitar los permisos de los servicios del sistema, pero ahora mismo no encaja bien con Podman
  • Es interesante ver Quadlet en la portada de Hacker News. Creo que no ha recibido suficiente atención
    Ygal y Valentin, del proyecto, nos enviaron alguna vez un artículo invitado sobre cómo ejecutar el cliente de túneles inlets. Es parecido a Ngrok/Cloudflared, pero autohospedado y sin las limitaciones de un SaaS
    https://inlets.dev/blog/2023/10/03/client-quadlet.html
    Ellos usaron [kube] en vez de [container], lo que les permitió llevar YAML estándar de Kubernetes y lo volvió bastante portable

  • Para quien tenga interés, armé una plantilla de Ansible que muestra lo fácil que es desplegar Quadlet hoy
    GH: https://github.com/Mati365/hetzner-podman-bunjs-deploy