Reiniciar automáticamente un servicio con Systemd

18 Noviembre 2018 by 0 Comment Configuraciones 190 Views
Computer Computer Ales Nesetril
Valora este artículo
(0 votos)

Normalmente tenemos en ejecución decenas de servicios, y todos deben estar en ejecución en todo momento. Puede que si somos usuarios de escritorio y tenemos un problema, lo detectemos al momento y reiniciemos el ordenador, o incluso investiguemos qué se ha detenido, lo reiniciamos y continuamos trabajando.

Aunque, si tenemos un VPS, una Raspberry PI o un NAS con un pequeño servidor, o cualquier sistema que tenga que estar todo el día encendido de forma independiente ejecutando un sistema GNU/Linux tenemos que tener en mente que los servicios fallan en algún momento. Ya sea por ejecutar una versión experimental, descubrir un bug, o simplemente quedarte sin memoria o disco. La clave es tener previsto que esos servicios pueden sufrir un problema. En el caso de tener un VPS con una web o un blog, significaría dejar a los usuarios sin poder acceder si por ejemplo se cae el servidor web o el servidor de aplicación. O en el caso de una Raspberry implicaría conectarnos o conectar monitor y teclado para reiniciar el servicio a mano, cuando debería ser algo que funcione de manera independiente.

Y como actualmente muchas distribuciones incluyen Systemd, vamos a hacerlo utilizando este sistema.

NOTA: En este tutorial, estoy utilizando sudo para ejecutar acciones con privilegios de root, pero puede que tu sistema no tenga sudo configurado. Así que tendrás que alcanzar el usuario root para ejecutar los comandos.

Listar nuestros servicios

Para ello, tenemos que tener claro cómo se llama el servicio. En Systemd todos acaban con ".service", algunos ejemplos de servicios pueden ser: apache, nginx (servidores web), sshd (servidor ssh), ufw (firewall), etc.

Podemos obtener un listado de los servicios de nuestro sistema así

sudo systemctl list-units --type=service

Vamos a probar, por ejemplo con el servicio apache2.service, es un servidor web y será muy fácil hacer pruebas con él.

Simulando fallos en el servicio

Es posible que este servicio falle. Y es algo que pasa en servidores del mundo real. Puede ser por algún fallo que se haya descubierto y haya sido explotado por un atacante, falta de recursos en el servidor, o incluso un fallo en un módulo, pero no podemos renunciar a ofrecer el servicio a nuestros usuarios. Así que, vamos a matar el proceso, para que éste finalice repentinamente sin contar con systemd:

sudo killall -9 apache2

Lo ejecutamos varias veces, hasta que nos aseguremos de que el proceso está realmente muerto. Si queremos, podemos intentar acceder al servidor web, y asegurarnos de que no responde.

Editando el servicio

Ahora, vamos a editar el archivo de descripción del servicio. Lo bueno de systemd es que no tenemos que editar el archivo original que describe el servicio, en mi caso /lib/systemd/system/apache2.service. Editar el archivo original implica que si actualizamos el sistema, una actualización puede deshacer nuestros cambios y nos obligaría a revisarlos cada vez que actualicemos. En su lugar podemos editar el archivo /etc/systemd/system/apache2.service o, en versiones más modernas de systemd, podemos ejecutar:

sudo systemctl edit apache2.service
 


Esto directamente nos mostrará un editor de texto (vi, nano, etc) con un fichero en blanco desde el que podemos introducir modificaciones al fichero original. Los cambios introducidos aquí se sumarán al fichero original y systemd lo interpretará como un archivo que contiene todas las directivas conjuntas. El comando, crea un directorio llamado /etc/systemd/system/apache2.service.d/ y dentro de ese directorio creará el archivo override.conf.

En dicho editor introduciremos lo siguiente:

 
[Service]
Restart=always
 

Con esto indicaremos a systemd que debe reiniciar el servicio siempre que se pare. Guardamos el fichero y ejecutaremos ahora:

sudo systemctl daemon-reload
sudo systemctl daemon-reload

Con este comando indicaremos a systemd que debe leer de nuevo todos los ficheros de configuración de los servicios. Ya podemos reiniciar el servicio (porque lo dejamos parado antes):

sudo systemctl restart apache2.service

o

sudo service apache2 restart

Este segundo es el antiguo método, aunque systemd lo mantiene. Para comprobar que realmente funciona este método, podemos esperarnos un minuto y pedir el estado del proceso apache2, para ello ejecutamos:

sudo systemctl status apache2.service

Y veremos algo parecido a esto:

● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: ena
Drop-In: /lib/systemd/system/apache2.service.d
└─apache2-systemd.conf
/etc/systemd/system/apache2.service.d
└─override.conf
Active: active (running) since Sun 2018-11-18 14:15:51 CET; 1min 19s ago
Process: 13229 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/SUCCESS
Main PID: 13245 (apache2)
Tasks: 55 (limit: 4915)
CGroup: /system.slice/apache2.service
├─13245 /usr/sbin/apache2 -k start
├─13248 /usr/sbin/apache2 -k start
└─13249 /usr/sbin/apache2 -k start

En la línea que comienza por Active, veremos cuánto tiempo lleva el proceso arrancado, en este caso 1 minuto y 19 segundos. Ahora, si matamos el proceso apache2 y pedimos el estado del proceso de nuevo, ahora veremos que el proceso sigue activo, pero se habrá iniciado hace unos segundos nada más. También veremos que los PID de los procesos son diferentes, y veremos una líneas indicando este reinicio.

Ver el log del proceso

Si queremos ver el log del proceso para saber el momento en el que se ha reiniciado, o ver directamente si se ha producido este reinicio y diagnosticarlo, porque lo ideal es que esto nunca suceda, podemos ejecutar:

sudo journalctl -u apache2.service

Ganando algo más de control

Ya hemos conseguido que los procesos se reinicien automáticamente, ahora vamos a afinar un poco esta configuración. Puede que nuestro servicio necesite unos segundos antes de levantarse, para lo que podremos editar el archivo de descripción del servicio e introducir:

RestartSec=2s

Y así esperaremos 2 segundos antes de reiniciarlo.

Incluso podemos limitar el número de veces que se reiniciará dentro de un intervalo de tiempo, por ejemplo, le podemos decir que si en un intervalo de 10 segundos, el servicio se reinicia 3 veces, no intentemos reiniciarlo más. Imaginemos que el equipo se queda sin disco, y vamos a tener a systemd reiniciando constantemente un servicio, ocupando CPU y memoria y puede que impidiendo la administración remota. Lo podemos hacer introduciendo estas líneas en la descripción del servicio:

StartLimitBurst=3
StartLimitIntervalSec=10

Y por supuesto, podemos probarlo matando el servicio varias veces. Incluso systemd nos indicará en el estado que ha superado el límite de reinicios y por eso el servicio se ha detenido.

Otra buena idea es, por ejemplo, enviar un correo electrónico al administrador en caso de reinicio de determinados servicios. Para ello, en esta misma descripción podemos incluir:

ExecStartPre=/usr/local/bin/correo_error_admin.pl

Luego, podemos crear el script que envía el correo, por ejemplo en Perl, introduciendo lo siguiente en el script /usr/local/bin/correo_error_admin.pl :

#!/usr/bin/perl
use strict;
use warnings;
# first, create your message
use Email::MIME;
my $message = Email::MIME->create(  
  header_str => [
    From    => <a href="mailto:Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'">Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'</a>,
    To      => <a href="mailto:Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'">Esta dirección de correo electrónico está siendo protegida contra los robots de spam. Necesita tener JavaScript habilitado para poder verlo.'</a>,
    Subject => 'Error en tu servidor',
  ],
  attributes => {
    encoding => 'quoted-printable',
    charset  => 'ISO-8859-1',
  },
  body_str => "Lo siento, tu servidor se ha reiniciado\n",
);
# send the message
use Email::Sender::Simple qw(sendmail);
sendmail($message);

En este script podemos incluir cualquier acción que nos interese automatizar cuando se inicie el servicio. Incluso podemos utilizar ExecStartPost= para ejecutar una acción cuando el servicio se haya iniciado y de la misma manera ExecStopPre= y ExecStopPost= para ejecutar acciones cuando paremos el servicio (pero no cuando el servicio se detenga o muera).

¡Espero que les haya sido útil!

 

Foto: unsplash-logoAles Nesetril

Información adicional

Gaspar Fernández

Mente inquieta. Linuxero empedernido.

Sitio Web: https://poesiabinaria.net

Deja un comentario

Asegúrese de introducir toda la información requerida, indicada por un asterisco (*). No se permite código HTML.

¡Atención! Este sitio usa cookies y tecnologías similares.

Si no cambia la configuración de su navegador, usted acepta su uso. Saber más

Acepto

Vea nuestra política de cookies y enlaces de interés aquí