¿Se pregunta cómo gestionar los servicios en segundo plano o en el arranque?

El mecanismo para gestionar e iniciar procesos en el arranque ha cambiado. Hasta RHEL/CentOS 6.x, habría creado un script en /etc/init.d/ y habilitado con la ayuda de chkconfig pero las cosas son diferentes en RHEL 7.

Ha sido reemplazado por systemd y dado que es más o menos el gestor de procesos por defecto en las principales versiones de Linux, los administradores de sistemas versados en otros sabores se sentirán como en casa. En este artículo, exploraremos qué es systemd, cuáles fueron las razones del cambio y cómo utilizar systemd para configurar, ejecutar y gestionar procesos en segundo plano con él.

¿Qué es systemd?

Dado que todos los procesos en Linux son transparentemente visibles, veamos dónde se esconde systemd. En mi sistema, obtengo lo siguiente

 ~$ ps -ef | grep systemd
root 1 0 0 Nov11 ?        00:01:02 /lib/systemd/systemd --system --deserialize 22
mensaje 768 1 0 Nov11 ?        00:05:46 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root 805 1 0 Nov11 ?        00:10:22 /lib/systemd/systemd-logind
ankush 1132 1 0 Nov11 ?        00:00:00 /lib/systemd/systemd --user
ankush 1176 1132 0 Nov11 ?        00:04:50 /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
ankush 9772 20029 0 21:11 pts/6 00:00:00 grep --color=auto systemd
systemd 17298 1 0 Nov19 ? 00:00:12 /lib/systemd/systemd-resuelto
systemd 17303 1 0 Nov19 ? 00:00:00 /lib/systemd/systemd-timesyncd
root 17307 1 0 Nov19 ? 00:00:02 /lib/systemd/systemd-journald
root 18182 1 0 Nov19 ? 00:00:00 /lib/systemd/systemd-udevd

Apuesto a que se ha dado cuenta al instante. El primer proceso del listado se inició como usuario root y tiene el pid 1.

Efectivamente, este fue el primer proceso que el sistema lanzó al arrancar. Salude a systemd. 🙂

Así que, sencillamente, systemd es el proceso «madre» que lanza, gestiona y termina otros procesos en el sistema, además de proporcionar información sobre su registro, estados del sistema de archivos, etc.

Una nota sobre el nombre, sin embargo. El nombre es efectivamente systemd y no System D o cualquier otro. La «d» significa demonio, un proceso estándar de Linux que trabaja (¿acecha?) en segundo plano y no está unido a ninguna sesión de terminal.

¿Por qué RHEL cambió a systemd?

Como ya hemos comentado, systemd es un gestor de sistemas y procesos y, en RHEL 7, sustituye al conocido programa Upstart. ¿Por qué RHEL tomó esta decisión? Bueno, hay muy buenas razones para ello, así que echemos un vistazo rápido.

Inicialización paralela de servicios

A diferencia del programa init de SysV, systemd es capaz de lanzar servicios en paralelo. El programa init, por el contrario, los lanza uno a uno. En una era en la que incluso los dispositivos móviles tienen CPUs multinúcleo, la falta de inicialización paralela es una gran desventaja.

Gestión dinámica (en caliente) de servicios

Si ha notado que las unidades USB necesitan ser montadas explícitamente en los sistemas Fedora anteriores mientras que se abrían automáticamente en Ubuntu y distribuciones similares, la razón es systemd. Es capaz de detectar cambios en vivo en el hardware y terminar/lanzar servicios según sea necesario. Algunos pueden argumentar que es innecesario, pero para muchos, cualquier cosa que reduzca la carga cognitiva es bienvenida.

Lanzamiento diferido de servicios

systemd hace que los tiempos de arranque sean más cortos, ya que es capaz de aplazar el lanzamiento de servicios hasta el momento en que realmente se necesitan. Un ejemplo sencillo son los servicios relacionados con el sistema de archivos en red. Si no hay disco de red disponible, no tiene sentido tener un servicio en marcha.

Comunicación de procesos más rápida

Las capacidades paralelas de systemd se trasladan a la comunicación entre procesos. systemd es capaz de ofrecer acceso paralelo a los sockets y al bus del sistema, reduciendo significativamente los tiempos de espera de los procesos para los recursos de comunicación.

Reinicio automático

Si un servicio se bloquea, systemd puede detectarlo e intentar reiniciarlo. La mayoría de las veces, un simple reinicio es todo lo que se necesita para que una aplicación empiece a funcionar de nuevo, a menos que haya problemas más fundamentales.

En cualquier caso, systemd facilita aquí la vida de un administrador de sistemas.

systemd en RHEL7 – ¿Qué cambia para los administradores de sistemas?

Si tiene la persistente sensación de que systemd no va a ser todo campanas y silbatos, está en lo cierto. Hay algunas incompatibilidades significativas que pueden pillar por sorpresa a los sysadmin de RHEL. Echemos un vistazo rápido.

Soporte limitado de runlevel

systemd tiene un reconocimiento y soporte de los niveles de ejecución bastante limitado. No todos los niveles de ejecución están soportados, y para algunos objetivos puede que incluso no haya ninguno. En tales casos, systemd devuelve «N» como respuesta a los comandos runlevel, lo que significa que no tiene ningún runlevel correspondiente a este objetivo. En definitiva, Red Hat nos aconseja no utilizar (!) los comandos runlevel.

Sin comandos personalizados

Esto va a doler. Una gran ventaja con SysV era la posibilidad de definir comandos personalizados para proporcionar una mejor funcionalidad para la gestión de procesos. Con systemd, no hay tal opción y usted está atascado con start, stop, status, restart, etc.

Sólo para la familia y no interactivo

systemd (por supuesto) mantiene un registro de los procesos que ha lanzado y almacena sus PID. El reto, sin embargo, es que systemd no puede ocuparse de procesos no lanzados por él. Además, no es posible que un usuario interactúe con un proceso iniciado por systemd. Toda la salida va a /dev/null, poniendo fin de forma efectiva a cualquier esperanza que pudiera haber tenido de capturar la salida.

Sin contexto

A diferencia de los servicios init, los lanzados por systemd no heredan ningún entorno de ningún usuario del sistema. En otras palabras, la información como PATH y otras variables del sistema no están disponibles, y cada nuevo proceso se lanza en un contexto vacío.

Si esta lista de limitaciones le hace llorar, de nuevo, no está solo. systemd ha sido una fuerza polarizadora en el mundo Linux, y si busca en Google «systemd apesta» encontrará mucho material de lectura. 😉

¿Cómo iniciar el servicio automáticamente cuando está caído?

He aquí un caso de uso bastante común en los despliegues. Necesitamos daemonizar un programa en un lenguaje que no tiene procesos de larga ejecución: ¡PHP! Supongamos que escribo un script PHP para manejar las conexiones websocket entrantes (¡después de todo construimos una aplicación de chat!) y el script se coloca en /home/ankush/chat_server/index.php.

Dado que las conexiones websocket pueden llegar al servidor en cualquier momento, este proceso necesita estar activo en todo momento y monitorizar las conexiones entrantes. No podemos tener el ciclo de vida tradicional de PHP aquí porque los WebSockets son conexiones con estado, y si el script muere, la conexión es una lista. De todos modos, suficiente sobre websockets; veamos como haremos para daemonizar este script a través de systemd.

Todos los servicios systemd residen en /etc/systemd/system, así que vamos a crear un archivo allí para describir nuestro script de servidor websocket. Asumiendo que ha iniciado sesión como usuario root.

# vi /etc/systemd/system/chat_server.service

y se necesita lo siguiente.

 [Unidad]
Descripción=Servicio de servidor de chat
Después=network.target

[Servicio]
Tipo=simple
Usuario=ankush
ExecStart=php /home/ankush/servidor_chat/index.php
Reiniciar=on-abortar


[Instalar]
WantedBy=multi-user.target

Guarde el archivo y el siguiente paso es recargar el demonio systemd

 # systemctl daemon-reload

y arrancar el servicio que acabamos de crear

 # systemctl start chat_server

Si no ve ningún error, ¡ya está!

Echemos también un vistazo rápido a lo que significan las distintas directivas del archivo:

  • La parte [Unidad ] define una nueva unidad de servicio para systemd. En la jerga de systemd, todos los servicios se conocen como unidades de servicio.
  • La directiva After (predeciblemente) le dice a systemd que lance este servicio sólo después de que se lancen los servicios de red (de lo contrario, ¡¿quién se encargará del manejo de bajo nivel de las conexiones de socket?!).
  • El Type=simple le dice a systemd que este servicio no debe bifurcarse a sí mismo. En otras palabras, sólo se ejecutará una instancia en un momento dado.
  • User=ankush significa que este servicio se ejecutará como el usuario «ankush». Podríamos cambiarlo por «root», pero es muy poco recomendable desde el punto de vista de la seguridad.
  • ExecStart, como puede deducir, es el comando real a ejecutar.
  • Restart=on-abort significa que el servicio debe reiniciarse cuando aborte. En PHP, los procesos de larga ejecución pierden memoria y eventualmente explotan, por lo que esto es necesario.
  • La directiva WantedBy= indica a systemd de qué objetivo (piense en grupos) forma parte este servicio. Esto hace que se creen enlaces simbólicos dentro de ese objetivo para apuntar al servicio.

Generalmente, esto es suficiente para ejecutar procesos en segundo plano utilizando systemd en RHEL 7.

Más opciones para la lógica de reinicio

En el ejemplo anterior, he configurado Restart=on-abort pero esa no es la única opción. Hay más y elija en función de sus necesidades.

  • on-failure – se reiniciará cuando no se encuentre limpio el código de salida o la señal
  • always – se reiniciará cuando se encuentre abajo, señal limpia o unclean
  • on-abnormal – señal no limpia, watchdog o timeout
  • on-success – sólo cuando se detuvo por una señal limpia o código de salida

Configuración del servicio para que se inicie al arrancar

Una vez que esté satisfecho con el script y se asegure de que funciona, lo siguiente es configurarlo para que se active al arrancar y se inicie.

Vaya a /etc/systemd/system y ejecute el siguiente comando enable (no olvide cambiar el nombre del archivo .service por el que tenga)

 # systemctl enable chat_server.service

Verá una confirmación de que se ha creado un enlace simbólico.

 Se ha creado un enlace simbólico de /etc/systemd/system/multi-user.target.wants/chat_server.service a /etc/systemd/system/chat_server.service.

Reinicie su servidor y debería ver que el servicio se inicia al arrancar.

Ha sido fácil ¿Verdad que sí?

¡Ayuda! Estoy masivamente invertido en Upstart. 🙁

Le entiendo confíe en mí, su caso es la norma más que la excepción. RHEL ha estado utilizando Upstart durante tanto tiempo que el cambio casi se siente como una traición. Pero bueno, los sistemas siguen cambiando y no deberíamos discutir por nimiedades. Red Hat reconoce que mucha gente está atascada con versiones anteriores y ha creado una guía de migración que sin duda debería consultar.

Una gracia salvadora en todo esto es que systemd es compatible con los scripts de init de SysV, así que en su mayor parte, simplemente tendrá que mover sus archivos y conseguir que se ejecuten los mismos servicios.

¿Está interesado en aprender más sobre la administración y resolución de problemas de Linux? Eche un vistazo a este curso en línea.