Ejecute contenedores con Podman y servicios systemd compartibles

Nota del editor:

La habilidad de usar systemd Los usuarios han solicitado servicios de administración y tiempo de ejecución de contenedores durante muchos años. Hubo varios intentos en Docker temprano para permitir que los contenedores de Docker se ejecutaran con systemd, pero esta característica resultó ser más difícil de lo esperado. ¿Por qué? Systemd debe conocer y controlar los procesos que se ejecutan dentro del systemd servicio para gestionarlo bien. Por lo tanto, es particularmente importante systemd puede saber si el proceso principal se está ejecutando y si se encuentra en buen estado.

El problema es que la arquitectura cliente-servidor de Docker complica las cosas. Todos los comandos de Docker se envían al demonio de Docker, lo que hace que sea casi imposible systemd para controlar los procesos del contenedor. Además, una ejecución exitosa del cliente Docker no implica necesariamente que el contenedor esté operativo. Varios intentos de mejorar la situación. fueron rechazados, dejando mucho margen de mejora.

La buena noticia es que Podman es una excelente opción para ejecutar contenedores, y especialmente para ejecutarlos en systemd prestaciones de servicio. Vamos a ver cómo funciona.

Índice

    systemd servicio de generación de archivos

    La arquitectura fork y exec de Podman permite systemd para controlar y gestionar adecuadamente los procesos de los contenedores. De hecho, Podman te permite poner un contenedor dentro de un systemd un servicio tan simple como una llamada podman generate systemd $container. Generemos un servicio para un contenedor:

    $ podman create -d --name foo busybox:latest top
    54502f309f3092d32b4c496ef3d099b270b2af7b5464e7cb4887bc16a4d38597
    $ podman generate systemd --name foo
    # container-foo.service
    # autogenerated by Podman 1.6.2
    # Tue Nov 19 15:49:15 CET 2019
    
    [Unit]
    Description=Podman container-foo.service
    Documentation=man:podman-generate-systemd(1)
    
    [Service]
    Restart=on-failure
    ExecStart=/usr/bin/podman start foo
    ExecStop=/usr/bin/podman stop -t 10 foo
    KillMode=none
    Type=forking
    PIDFile=/run/user/1000/overlay-Contenedores/54502f309f3092d32b4c496ef3d099b270b2af7b5464e7cb4887bc16a4d38597/userdata/conmon.pid
    
    [Install]
    WantedBy=multi-user.target
    

    lo generado systemd El archivo de servicio ahora se puede usar para administrar el foo contenedor vía systemd. Podemos copiar el archivo a ~/.config/systemd/user/container-foo.service e inicie un contenedor sin root a través de systemctl --user start container-foo.service.

    Servicios de contenedores específicos o genéricos

    La capacidad de generar systemd Los archivos de servicio brindan una gran flexibilidad a los usuarios y difuminan intencionalmente la diferencia entre un contenedor y cualquier otro programa o servicio en el host. Desde Podman v1.6, también podemos generar archivos de servicio para pods que se pueden escribir fácilmente en archivos a través de la --files bandera. Sin embargo, todos estos archivos generados son específicos de contenedores y pods que ya existen. Como se muestra en el ejemplo anterior, primero debemos crear un contenedor o pod y luego podemos generar archivos de servicio específicos. Pero, ¿y si queremos ejecutar un contenedor directamente a través del servicio? ¿Qué pasa si queremos compartir un archivo de servicio con otros usuarios?

    Después de acumular más experiencia en esta área y recibir comentarios de la comunidad, nos sentamos y pensamos en cómo podemos mejorar y proporcionar un esqueleto de servicio genérico que se pueda usar compatible con versiones anteriores de Podman en la naturaleza. La buena noticia es que hemos encontrado tales archivos de servicio compatibles con versiones anteriores, que veremos más de cerca ahora:

    [Unit]
    Description=Podman in Systemd
    
    [Service]
    Restart=on-failure
    ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid
    ExecStart=/usr/bin/podman run --conmon-pidfile  /%t/%n-pid  --cidfile /%t/%n-cid -d busybox:latest top
    ExecStop=/usr/bin/sh -c "/usr/bin/podman rm -f `cat /%t/%n-cid`"
    KillMode=none
    Type=forking
    PIDFile=/%t/%n-pid
    
    [Install]
    WantedBy=multi-user.target
    

    El archivo de servicio superior establece la política de reinicio en on-failure, que ordena systemd para reiniciar el servicio cuando, entre otras cosas, el servicio no puede iniciarse o detenerse limpiamente, o cuando el proceso finaliza con un valor distinto de cero. el ExecStart línea describe cómo iniciamos el contenedor, el ExecStop describe cómo paramos y retiramos el contenedor. En este ejemplo, queremos ejecutar un simple busybox:latest contenedor de fondo que se está ejecutando top. Pero hay otras dos banderas que debemos considerar: --conmon-pidfile y --cidfile.

    el --conmon-pidfile la bandera apunta a una ruta para almacenar la identificación del proceso para el contenedor conmon para tratar. Conmon es una pequeña herramienta de monitoreo que Podman usa para realizar cosas como mantener abiertos los puertos y los identificadores de archivos, transmitir registros de contenedores y limpiar cuando el contenedor está terminado. Este comando también devuelve el código de salida del contenedor, que es esencial para el systemd caso de uso de servicio, porque podemos usar el conmon-pidfile como PIDFile para el mismo servicio. Si el contenedor genera un valor distinto de cero, conmon también lo hará, y systemd puede informar el estado correcto del servicio y reiniciarlo si es necesario:

    [Service]
    Restart=on-failure
    ExecStartPre=/usr/bin/rm -f  /%t/%n-pid  /%t/%n-cid
    ExecStart=/usr/bin/podman run --conmon-pidfile  /%t/%n-pid  --cidfile /%t/%n-cid -d busybox:latest top
    ...
    PIDFile=/%t/%n-pid
    

    el --cidfile la bandera apunta a la ruta que almacena el ID del contenedor. Al ejecutar o crear un contenedor, Podman escribe el ID del contenedor correspondiente en la ruta especificada. Esto nos permite escribir archivos de servicio elegantes y genéricos, ya que también podemos usar el archivo para detener o eliminar el contenedor. En el ejemplo anterior, el ExecStop línea utiliza un truco de shell (es decir, -c seguido de un conjunto de comandos para la interpretación del shell) para detener el contenedor. A partir de la próxima versión de Podman v1.7, podman stop y podman rm apoyen el --cidfile flag también, por lo que ya no necesitamos los trucos de la capa superior:

    [Service]
    Restart=on-failure
    ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid
    ExecStart=/usr/bin/podman run --conmon-pidfile /%t/%n-pid --cidfile  /%t/%n-cid  -d busybox:latest top
    ExecStop=/usr/bin/sh -c "/usr/bin/podman rm -f `cat  /%t/%n-cid`"
    ...
    

    Ahora echemos un vistazo a las rutas especificadas a la conmon-pidfile y el cidfile, /%t/%n-pid y /%t/%n-cid, que también merecen alguna explicación. En estas declaraciones, %t es la ruta a la raíz del directorio de tiempo de ejecución (es decir, /run/user/$UserID). Aquí es donde Podman también almacena la mayoría de sus datos de tiempo de ejecución. el %n porción es el nombre completo del servicio. Systemd garantiza la unicidad de los nombres de los servicios, por lo que no tenemos que preocuparnos por posibles conflictos de nombres de archivos.

    Asumiendo que nuestro servicio se llama foo y tiene un ID de usuario de 1000, el correspondiente conmon-pidfile se coloca en /run/user/1000/foo.service-pid, mientras que la cidfile se coloca en /run/user/1000/foo.service-cid.

    Notar: Es importante establecer el modo de eliminación en none. Otro, systemd comenzará a competir con Podman para detener y eliminar procesos de contenedores. lo que puede conducir a varios efectos secundarios no deseados y estados inválidos.

    Un ejemplo paso a paso

    Hasta aquí la teoría, echemos un vistazo. Primero, asegúrese de que el archivo sea accesible para nuestro usuario no root.

    $ cat ~/.config/systemd/user/container.service
    [Unit]
    Description=Podman in Systemd
    
    [Service]
    Restart=on-failure
    ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid
    ExecStart=/usr/bin/podman run --conmon-pidfile /%t/%n-pid --cidfile /%t/%n-cid -d busybox:latest top
    ExecStop=/usr/bin/sh -c "/usr/bin/podman rm -f `cat /%t/%n-cid`"
    KillMode=none
    Type=forking
    PIDFile=/%t/%n-pid
    
    [Install]
    WantedBy=multi-user.target
    

    Ahora podemos cargar e iniciar el servicio:

    $ systemctl --user daemon-reload
    $ systemctl --user start container.service
    $ systemctl --user status container.service
    ● container.service - Podman in Systemd
       Loaded: loaded (/home/valentin/.config/systemd/user/container.service; disabled; vendor preset: enabled)
       Active: active (running) since Mon 2019-11-18 15:32:56 CET; 1min 5s ago
      Process: 189705 ExecStartPre=/usr/bin/rm -f //run/user/1000/container.service-pid //run/user/1000/container.service-cid (code=exited, status=0/SUCCESS)
      Process: 189706 ExecStart=/usr/bin/podman run --conmon-pidfile //run/user/1000/container.service-pid --cidfile //run/user/1000/container.service-cid -d busybox:latest top (code=exited, status=0/SUCCESS)
     Main PID: 189731 (conmon)
       CGroup: /user.slice/user-1000.slice/[email protected]/container.service
           	├─189724 /usr/bin/fuse-overlayfs [...]
           	├─189726 /usr/bin/slirp4netns [...]
           	├─189731 /usr/bin/conmon [...]
           	└─189737 top
    
    $ podman ps
    CONTAINER ID  IMAGE                        	COMMAND  CREATED     	STATUS         	PORTS  NAMES
    f20988d59920  docker.io/library/busybox:latest  top  	12 seconds ago  Up 11 seconds ago     	funny_zhukovsky
    

    ¡Estupendo! Systemd inició el servicio con éxito y Podman informa que el contenedor también se está ejecutando. Tenga en cuenta que he cortado partes de la salida superior por brevedad. Una parte importante es la Main PID, que apunta a la correcta conmon para tratar. Sin señalar explícitamente systemd al proceso correcto a través del PIDFile opción, systemd puede elegir incorrectamente otro proceso en este cgroup como el proceso principal. Hay algunos otros procesos enumerados (por ejemplo, fuse-overlayfs, slirp4nets, y top), y todos se ejecutan en el mismo cgroup. Fuse-overlayfs es una implementación del sistema de archivos de superposición de espacio de usuario a través de Fuse y slirp4nets permite redes sin privilegios. Ambas herramientas son esenciales para ejecutar contenedores sin raíz con Podman.

    Antes de detener correctamente el servicio a través de systemctl --user stop container.service, probemos la política de reinicio, que está establecida en on-failure. Podemos causar tal fracaso matando al top proceso (es decir, 189737):

    $ kill -9 189731
    $ systemctl --user status container.service
    ● container.service - Podman in Systemd
       Loaded: loaded (/home/valentin/.config/systemd/user/container.service; disabled; vendor preset: enabled)
       Active: active (running) since Mon 2019-11-18 16:09:38 CET; 1min 3s ago [...]
    Main PID: 191263 (conmon)
    

    Podemos ver que el Main PID ha cambiado de 189731 en 191263. Este es un resultado esperado, porque eliminamos el proceso del contenedor, por lo que salió con un valor distinto de cero. Común salió con el mismo código de salida y systemd reiniciado con éxito el servicio. Tenga en cuenta que el servicio también se reiniciará cuando detengamos manualmente un contenedor a través de podman stop $container, porque el top binario en el busybox:latest contenedor sale con 143 al apagar con SIGTERM. el top binario de otras distribuciones (por ejemplo, BusyBox) sale con 0 después de SIGTERM, por lo que systemd no reiniciaría el servicio. Es muy importante tener en cuenta estas diferencias de comportamiento al escribir systemd services, por lo que debemos tener cuidado al configurar la política de reinicio.

    Volver al trabajo

    Lo bueno de los genéricos systemd servicio presentado en este artículo es que es compatible con versiones anteriores de Podman que se ejecutan en la naturaleza. Ya sea Red Hat Enterprise Linux, BusyBox o Ubuntu, los usuarios pueden seguir inmediatamente el formato sugerido. Sin embargo, el equipo de Podman continúa mejorando el soporte y la experiencia del usuario al ejecutar contenedores en systemd prestaciones de servicio. ¡Intentalo!

    Artículos de interés

    Subir