Ejecute systemd en el contenedor

Hemos estado siguiendo el tema del uso de systemd en contenedores durante mucho tiempo. En 2014, nuestro ingeniero de seguridad Daniel Walsh escribió un artículo llamado Running systemd dentro de un Docker Container , y un par de años más tarde, otro artículo llamado Running systemd en un contenedor no privilegiado , en el que afirmó que la situación no era Mucho mejoró. En particular, escribió que "desafortunadamente, y dos años más tarde, si buscas en Google el sistema Docker, lo primero que aparece es el mismo artículo antiguo suyo. Así que es hora de cambiar algo ". Además, ya hablamos sobre el conflicto entre los desarrolladores de Docker y systemd .



En este artículo mostraremos lo que ha cambiado en el pasado y cómo Podman puede ayudarnos en este asunto.

Hay muchas razones para ejecutar systemd dentro de un contenedor, como:

  1. Contenedores multiservicio : muchas personas desean sacar sus aplicaciones multiservicio de máquinas virtuales y ejecutarlas en contenedores. Sería mejor, por supuesto, dividir tales aplicaciones en microservicios, pero no todos pueden hacerlo todavía o simplemente no hay tiempo. Por lo tanto, el lanzamiento de dichas aplicaciones en forma de servicios lanzados por systemd desde archivos unitarios tiene mucho sentido.
  2. Archivos de unidad de Systemd : la mayoría de las aplicaciones que se ejecutan dentro de contenedores se compilan a partir de código que se ejecutó previamente en máquinas virtuales o físicas. Estas aplicaciones tienen un archivo de unidad que se escribió para estas aplicaciones y comprende cómo ejecutarlas. Por lo tanto, es mejor comenzar los servicios utilizando los métodos admitidos, en lugar de piratear su propio servicio de inicio.
  3. Systemd es un administrador de procesos. Gestiona los servicios (apaga, reinicia los servicios o rastrea los procesos zombies) mejor que cualquier otra herramienta.

Hay muchas razones para no ejecutar systemd en contenedores. El principal es que systemd / journald controla la salida de los contenedores, mientras que herramientas como Kubernetes u OpenShift esperan que los contenedores escriban el registro directamente en stdout y stderr. Por lo tanto, si tiene la intención de administrar contenedores a través de herramientas de orquestación como las mencionadas anteriormente, debe considerar seriamente el uso de contenedores basados ​​en systemd. Además, los desarrolladores de Docker y Moby a menudo se oponían fuertemente al uso de systemd en contenedores.

La venida de Podman


Nos complace anunciar que la situación finalmente ha despegado. El equipo responsable del lanzamiento de contenedores en Red Hat decidió desarrollar su propio motor de contenedores . Obtuvo el nombre de Podman y ofrece la misma interfaz de línea de comandos (CLI) que Docker. Y casi todos los comandos de Docker se pueden usar de la misma manera en Podman. A menudo organizamos seminarios, que ahora se llaman Cambiar Docker a Podman , y la primera diapositiva lo alienta a registrarse: alias docker = podman.

Muchos lo hacen

Mi Podman y yo no estamos en contra de los contenedores basados ​​en systemd. Después de todo, Systemd se usa con mayor frecuencia como el subsistema init de Linux, y no dejar que funcione normalmente en contenedores significa ignorar la forma en que miles de personas están acostumbradas a ejecutar contenedores.

Podman sabe qué hacer para que systemd funcione correctamente en el contenedor. Necesita cosas como montar tmpfs en / run y / tmp. Le gusta cuando el entorno "contenedor" está habilitado y está esperando permisos de escritura en su parte del directorio cgroup y en la carpeta / var / log / journald.

Al iniciar un contenedor en el que init o systemd es el primer comando, Podman configura automáticamente tmpfs y Cgroups para que systemd se inicie sin problemas. Para bloquear este modo de inicio automático, use la opción --systemd = false. Tenga en cuenta que Podman usa el modo systemd solo cuando ve que es necesario ejecutar el comando systemd o init.

Aquí hay un extracto del manual:

hombre podman correr
...

–Systemd = verdadero | falso

Ejecutando el contenedor en modo systemd. Habilitado por defecto.

Si se ejecuta un comando systemd o init dentro del contenedor, Podman configurará los puntos de montaje tmpfs en los siguientes directorios:

/ run, / run / lock, / tmp, / sys / fs / cgroup / systemd, / var / lib / journal

Además, SIGRTMIN + 3 se utilizará como señal de parada de forma predeterminada.

Todo esto permite que systemd funcione en un contenedor cerrado sin modificaciones.

NOTA: systemd está intentando escribir en el sistema de archivos cgroup. Sin embargo, SELinux por defecto evita que los contenedores hagan esto. Para habilitar la escritura, habilite el parámetro por lotes container_manage_cgroup:

setsebool -P container_manage_cgroup true

Ahora mire cómo se ve el Dockerfile para ejecutar systemd en el contenedor cuando usa Podman:

# cat Dockerfile FROM fedora RUN dnf -y install httpd; dnf clean all; systemctl enable httpd EXPOSE 80 CMD [ "/sbin/init" ] 

Eso es todo

Ahora recoge el contenedor:

 # podman build -t systemd . 

Le decimos a SELinux que permita que systemd modifique la configuración de Cgroups:

 # setsebool -P container_manage_cgroup true 

Muchos, por cierto, se olvidan de este paso. Afortunadamente, es suficiente hacer esto solo una vez y la configuración se guarda después de reiniciar el sistema.

Ahora solo ejecuta el contenedor:

 # podman run -ti -p 80:80 systemd systemd 239 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid) Detected virtualization container-other. Detected architecture x86-64. Welcome to Fedora 29 (Container Image)! Set hostname to <1b51b684bc99>. Failed to install release agent, ignoring: Read-only file system File /usr/lib/systemd/system/systemd-journald.service:26 configures an IP firewall (IPAddressDeny=any), but the local system does not support BPF/cgroup based firewalling. Proceeding WITHOUT firewalling in effect! (This warning is only shown for the first loaded unit using IP firewalling.) [ OK ] Listening on initctl Compatibility Named Pipe. [ OK ] Listening on Journal Socket (/dev/log). [ OK ] Started Forward Password Requests to Wall Directory Watch. [ OK ] Started Dispatch Password Requests to Console Directory Watch. [ OK ] Reached target Slices. … [ OK ] Started The Apache HTTP Server. 

Todo, el servicio comenzó y funciona:

 $ curl localhost <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> … </html> 

NOTA: ¡No intente repetir esto en Docker! Allí, todavía se necesitan bailes con una pandereta para lanzar tales contenedores a través de un demonio. (Se necesitarán campos y paquetes adicionales para que esto funcione a la perfección en Docker, o deberá ejecutarse en un contenedor privilegiado. Consulte el artículo para obtener más detalles ).

Un par de cosas más interesantes sobre Podman y systemd


Podman funciona mejor que Docker en archivos de unidad systemd


Si los contenedores deben iniciarse en el arranque del sistema, simplemente puede insertar los comandos Podman apropiados en el archivo de la unidad del sistema, que iniciará el servicio y lo supervisará. Podman utiliza el modelo estándar de fork-exec. En otras palabras, los procesos de contenedor están afiliados al proceso Podman, por lo que systemd puede monitorearlos fácilmente.

Docker utiliza el modelo cliente-servidor, y los comandos de Docker CLI también se pueden colocar directamente en el archivo de la unidad. Sin embargo, después de que el cliente Docker se conecta al demonio Docker, (el cliente) se convierte en otro proceso que procesa stdin y stdout. A su vez, systemd no tiene idea de la conexión entre el cliente Docker y el contenedor que ejecuta el demonio Docker, y por lo tanto, bajo este modelo, systemd no puede monitorear fundamentalmente el servicio.

Activación del sistema a través de un enchufe


Podman cumple correctamente la activación a través de un zócalo. Debido a que Podman usa el modelo fork-exec, puede reenviar un socket a sus procesos contenedores secundarios. Docker no sabe cómo, porque usa un modelo cliente-servidor.

El servicio varlink que Podman usa para interactuar con clientes remotos con contenedores se activa realmente a través del socket. El paquete cockpit-podman, escrito en Node.js y parte del proyecto cockpit, permite a las personas interactuar con los contenedores Podman a través de una interfaz web. El demonio web en el que se ejecuta cockpit-podman envía mensajes al zócalo varlink que escucha systemd. Después de eso, systemd activa el programa Podman para recibir mensajes y comenzar a administrar contenedores. La activación de systemd a través de un socket le permite prescindir de un demonio que funciona constantemente al implementar API remotas.

Además, estamos desarrollando otro cliente para Podman, llamado podman-remote, que implementa la misma CLI de Podman, pero llama a varlink para lanzar contenedores. Podman-remote puede funcionar sobre sesiones SSH, lo que le permite interactuar de forma segura con contenedores en diferentes máquinas. Con el tiempo, planeamos usar podman-remote para admitir MacOS y Windows junto con Linux, de modo que los desarrolladores en estas plataformas puedan ejecutar la máquina virtual Linux con Podman varlink ejecutándose y tener la plena sensación de que los contenedores se ejecutan en la máquina local.

SD_NOTIFY


Systemd le permite retrasar el lanzamiento de servicios auxiliares hasta que comience el servicio contenedorizado requerido. Podman puede reenviar el socket SD_NOTIFY al servicio en contenedor para que el servicio notifique al sistema de su disponibilidad para el trabajo. Y nuevamente, Docker, usando el modelo cliente-servidor, no sabe cómo.

En los planes


Planeamos agregar el comando podman generate systemd CONTAINERID, que generará el archivo de unidad systemd para administrar un contenedor específico. Esto debería funcionar tanto en modo raíz como sin raíz para contenedores no privilegiados. Incluso vimos una solicitud para crear un tiempo de ejecución systemd-nspawn compatible con OCI.

Conclusión


Ejecutar systemd en un contenedor es una necesidad comprensible. Y gracias a Podman, finalmente tenemos un entorno de iniciador de contenedores que no es hostil a systemd, pero que lo hace fácil de usar.

Source: https://habr.com/ru/post/468931/


All Articles