Este es uno de los capítulos del tutorial Trabajando con Systemd. Encontrarás los enlaces a todos los de capítulos, al final de este artículo.
En los anteriores capítulos de este tutorial hemos visto que era Systemd y que eran las unidades. Además hemos visto como podíamos conocer el estado de las unidades y como podíamos gestionarlas. Sin embargo, para poder sacar todo el partido a Systemd, es necesario que aprendamos a crear nuestras propias unidades. Y en particular, en este capítulo del tutorial te mostrará como crear un servicio con Systemd.
Aunque de buenas a primeras pueda sonar como algo complejo, la realidad es que es una operación bastante trivial. Al final nos puede ser de gran utilidad para tener nuestro propio servicio funcionando, para hacer cualquier cosa que nos podamos imaginar.
En particular, para ver que veas lo fácil que resulta crear un servicio, vamos a crear un servidor de páginas web.
Como crear un servicio con Systemd
Como he comentado en la introducción para que veas lo sencillo que resulta crear un servicio, vamos a crear un servidor de páginas web. Para ello, parte de un sencilllo ejemplo que puedes encontrar en GitHub.
Este servidor lo único que hace es devolverte una sencilla página web, en función de la dirección que introduzcas. Sin embargo, esto no es mas que un ejemplo, lo importante es crear un servicio con Systemd.
¿Porque crear un servicio? Si te limitas a ejecutar este sencillo script con python3 sample.py
, te darás cuenta que necesitas ejecutarlo cada vez que quieras tener la aplicación funcionando. ¿Pero que sucede cuando apagas o reinicias tu equipo o VPS? Simplemente tu aplicación muere.
La ventaja de convertir tu aplicación en un servicio es que no te tienes que preocupar de arrancar tu servicio cuando inicies el ordenador, el sistema ya se preocupa por ti. Simplemente, conforme vimos en el segundo capítulo del tutorial, te tienes que preocupar de tener habilitado el servicio.
Al queso… como crear un servcio con Systemd
Para ello, crearemos el siguiente archivo /lib/systemd/system/sample.service
con el contenido que indico a continuación,
[Unit]
Description=Ejemplo
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=lorenzo
ExecStart=/usr/bin/env python3 /home/lorenzo/temporal/sample/sample.py
[Install]
WantedBy=multi-user.target
Recuerda que debes sustituir mi usuario lorenzo
por el tuyo, así como la ruta donde has puesto el script en Python.
Y ya lo tienes… ¿Sencillo no?. Así de primeras suena todo a chino, pero vamos a desgranarlo.
Desgranando nuestro servicio
Vamos punto por punto, para dejar claro cada uno de los elementos en que consiste,
Description
. Aquí puedes introducir la definición o descripción del servicio. Esta información es la que aparecerá en el log y en la salida del comandosystemctl status
. Es decir, que tiene que ser suficientemente descriptiva para ti.After
. Esta directiva indica que nuestro servicio tiene que iniciarse después de que la red esté lista. En el caso de que tuvieramos que esperar a que estuvira listo MariaDB, la directiva sería tal comoAfter=mysqld.service
. También podemos encadenar varios servicios, separados por espacio, por ejemplo
After=syslog.target network.target sshd.service
ExecStart
. Aquí debe figrurar la ruta al ejecutable, así como los parámetros necesarios para que arranque.Type
. Permite configurar el inicio de nuestro servicio. Así tenemos,simple
. El proceso empieza conExecStart
y es el principal proceso del servicio.forking
. En este caso se lanza un proceso hijo, que se convierte en el proceso principal.oneshot
. El proceso termina antes de comenzar con las siguientes unidades.dbus
. Las siguientes unidades empezarán cuando el proceso principal tegan el D-Bus.notify
. En este caso depende de un mensaje de notificación enviado porsd_notify
.idle
. La ejecución del servicio se retraza hasta que todos los trabajos han terminado.
Restart
. Por defecto Systemd, no reinicia tu servicio en caso de que este caiga, por la razón que sea. Sin embargo, a ti lo que te interesa es que tu servicio siempre esté en funcionamiento. Para lograr esto, tienes que poner la directivaRestart=always
. Otra opción es utilizarRestart=on-failure
, en cuyo caso solo se reinicializará si el servicio se ha parado por fallo.RestartSec
. Te permite definir el tiempo que debe transcurrir hasta que se intente poner de nuevo en marcha tu servicio. Por defecto, Systemd, trata de levantar el servicio, transcurrido 100 ms. Con esta directiva, tu puedes establecer el tiempo en segundos. Sin embargo, es interesante que dejes como mínimo un segundo para no forzar la máquina.StartLimitBurst
yStartLimitIntervalSec
. Estos dos parámetros te permitirán definir cuantos intentosStartLimtBurs
y en que intervaloStartLimitIntervalSec
, vas a permitir para que se restablezca el servicio. Por defecto, Systemd permite 4 intentos en 10 segundos. Por supuesto estableciendoRestartSec=3
nunca se alcanzarán estos valores.StartLimitIntervalSec=0
, obligará a Systemd a reiniciar el servicio tantas veces como sea necesario.WantedBy
. Esto equivale al runlevel. Establece el objetivo (Target) u objetivos bajo los que el servicio debería ser iniciado.
Objetivos o Targets
Los objetivos existentes los puedes ver en la siguiente tabla,
Runlevel | Objetivo | Descripción |
---|---|---|
0 | poweroff.target | Apagado del sistema |
1 | rescue.target | Shell de rescate |
2 | multi-user.target | Sistema no gráfico |
3 | multi-user.target | Sistema no gráfico |
4 | multi-user.target | Sistema no gráfico |
5 | multi-user.target | Sistema gráfico |
6 | reboot.target | Apagado y reinicio |
Para conocer cual es el objetivo definido por defecto, tienes que ejecutar la siguiente orden,
systemctl get-default
En mi portátil devuelve graphical.target
.
Sin embargo, hay mas objetivos, a parte de los indicados anteriormente. Si quieres conocer todos los objetivos que hay preestablecidos, ejecuta la orden,
systemctl list-units --type target
En mi caso el resultado fue el siguiente,
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
bluetooth.target loaded active active Bluetooth
cryptsetup.target loaded active active Local Encrypted Volumes
getty.target loaded active active Login Prompts
graphical.target loaded active active Graphical Interface
local-fs-pre.target loaded active active Local File Systems (Pre)
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
network.target loaded active active Network
nss-lookup.target loaded active active Host and Network Name Lookups
nss-user-lookup.target loaded active active User and Group Name Lookups
paths.target loaded active active Paths
remote-fs.target loaded active active Remote File Systems
slices.target loaded active active Slices
sockets.target loaded active active Sockets
sound.target loaded active active Sound Card
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
time-sync.target loaded active active System Time Synchronized
timers.target loaded active active Timers
Poniendo en marcha el servicio
Ahora que tenemos unas ligeras nociones de quien es quien en el archivo de configuración de nuestro servicio, y ya hemos creado nuestro servicio, tan solo nos queda ponerlo en marcha.
Esto se hace conforme vimos en el capítulo sobre gestionar servicios en Systemd. Así para iniciar nuestro servicio, simplemente,
sudo systemctl start sample
para detenerlo
sudo systemctl stop sample
También recuerda que vimos que para que nuestro servicio se iniciara con el sistema, teníamos que ejecutar la orden,
sudo systemctl enable sample
Y con esto tenemos las operaciones básicas y necesarias para gestionar el servicio que acabamos de crear.
Conclusiones
Con esto ya tienes unas nociones básicas de como crear un servicio en Systemd. Ten en cuenta que esto no son mas que unas pinceladas de todas las posibilidades que nos ofrece Systemd. Pero creo que es suficiente para crear un servicio con Systemd.
Mas información,
De verdad que cada vez que busco algo en la web acabo leyendote/oyendote/viendote. Gran aporte, una vez más ¡enhorabuena!