Articles

Creando un servicio Linux con systemd

Posted on
Creando tus propios servicios – Photo by Jeff Sheldon on Unsplash

Mientras escribo aplicaciones web, a menudo necesito descargar tareas de computación pesada a un script de trabajador asíncrono, programar tareas para más tarde, o incluso escribir un demonio que escucha un socket para comunicarse con los clientes directamente.

Aunque a veces puede haber mejores herramientas para el trabajo -siempre considere usar primero el software existente, como un servidor de cola de tareas-, escribir su propio servicio puede darle un nivel de flexibilidad que nunca obtendrá cuando esté limitado por las restricciones del software de terceros.

Lo bueno es que es bastante fácil crear un servicio Linux: use su lenguaje de programación favorito para escribir un programa de larga duración y conviértalo en un servicio usando systemd.

Creemos un pequeño servidor usando PHP. Puedo ver cómo se levantan las cejas, pero funciona sorprendentemente bien. Escucharemos en el puerto UDP 10000, y devolveremos cualquier mensaje recibido con una transformación ROT13:

Iniciémoslo:

$ php server.php

Y lo probamos en otro terminal:

$ nc -u 127.0.0.1 10000
Hello, world!
Uryyb, jbeyq!

Bien, funciona. Ahora queremos que este script se ejecute en todo momento, se reinicie en caso de fallo (salida inesperada), e incluso sobreviva a los reinicios del servidor. Ahí es donde entra en juego systemd.

Convirtiéndolo en un servicio

Creemos un archivo llamado /etc/systemd/system/rot13.service:


Description=ROT13 demo service
After=network.target
StartLimitIntervalSec=0
Type=simple
Restart=always
RestartSec=1
User=centos
ExecStart=/usr/bin/env php /path/to/server.php

WantedBy=multi-user.target

Necesitarás:

  • poner tu nombre de usuario real después de User=
  • poner la ruta adecuada a tu script en ExecStart=
  • Eso es todo. Ya podemos arrancar el servicio:

$ systemctl start rot13

Y conseguir que se inicie automáticamente al arrancar:

$ systemctl enable rot13

Además

Ahora que tu servicio (con suerte) funciona, puede ser importante profundizar un poco más en las opciones de configuración, y asegurarte de que siempre funcionará como esperas.

Comenzando en el orden correcto

Tal vez te hayas preguntado qué hace la directiva After=. Simplemente significa que su servicio debe iniciarse después de que la red esté lista. Si su programa espera que el servidor MySQL esté en funcionamiento, debe añadir:

After=mysqld.service

Reinicio al salir

Por defecto, systemd no reinicia su servicio si el programa sale por cualquier motivo. Esto no suele ser lo que quieres para un servicio que debe estar siempre disponible, así que le indicamos que se reinicie siempre al salir:

Restart=always

También podrías usar on-failure para que sólo se reinicie si el estado de salida no es 0.

Por defecto, systemd intenta un reinicio después de 100ms. Puedes especificar el número de segundos a esperar antes de intentar un reinicio, usando:

RestartSec=1

Evitando la trampa: el límite de arranque

Yo personalmente he caído en esta más de una vez. Por defecto, cuando configuras Restart=always como hicimos nosotros, systemd renuncia a reiniciar tu servicio si falla en el arranque más de 5 veces en un intervalo de 10 segundos. Para siempre.

Hay dos opciones de configuración responsables de esto:

StartLimitBurst=5
StartLimitIntervalSec=10

La directiva RestartSec también tiene un impacto en el resultado: si lo configuras para que se reinicie después de 3 segundos, entonces nunca podrás llegar a 5 reintentos fallidos en 10 segundos.

La solución simple que siempre funciona es establecer StartLimitIntervalSec=0. De esta manera, systemd intentará reiniciar su servicio para siempre.

Es una buena idea establecer RestartSec a por lo menos 1 segundo sin embargo, para evitar poner demasiado estrés en su servidor cuando las cosas comienzan a ir mal.

Como alternativa, puedes dejar la configuración por defecto, y pedir a systemd que reinicie tu servidor si se alcanza el límite de arranque, usando StartLimitAction=reboot.

¿Es eso realmente?

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *