Systemd/Systemctl – Configuración de Servicios en RedHat

La histórica configuración de /etc/init.d se está quedando obsoleta y en RedHat 7 / Centos 7 debemos utilizar systemctl (systemd) para personalizar aquellos procesos que queramos que arranquemos con el boot del sistema.

Configurar systemctl es muy sencillo. De hecho, creé un script para arrancar el Apache que hace que funcione este blog. Lo hice asi:

Configuración de un servicio básico con systemd

[root@prt53ws1 ~]# cat /usr/lib/systemd/system/httpd_puerto53.service
[Unit]
Description=Apache puerto53
After=network.target remote-fs.target nss-lookup.target

[Service]
ExecStart=/app/puerto53/scripts/Apache/apache_puerto53.sh start
ExecStop=/app/puerto53/scripts/Apache/apache_puerto53.sh stop
Type=forking
PIDFile=/app/puerto53/httpd/run/httpd/httpd.pid

[Install]
WantedBy=multi-user.target
[root@prt53ws1 ~]#

Arranque del servicio

Veamos cómo funciona:

[root@prt53ws1 system]# systemctl enable httpd_puerto53.service
[root@prt53ws1 system]# systemctl start httpd_puerto53.service
[root@prt53ws1 system]# ps -ef |grep -i http
root 4732 1 0 12:28 ? 00:00:00 /usr/bin/sh /etc/init.d/httpd_puerto53 start
root 4734 1 1 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4736 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4737 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4738 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4739 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4740 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4741 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4742 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4743 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4744 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4745 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4746 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4747 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4748 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4749 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4750 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
puerto53 4751 4734 0 12:28 ? 00:00:00 httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
root 4756 2794 0 12:28 pts/0 00:00:00 grep --color=auto -i http

Comprobar el estado del servicio

[root@prt53ws1 system]# systemctl status httpd_puerto53.service
● httpd_puerto53.service - Apache puerto53
Loaded: loaded (/etc/systemd/system/httpd_puerto53.service; enabled; vendor preset: disabled)
Active: inactive (dead) since Thu 2018-08-16 12:28:46 CEST; 4s ago
Process: 4760 ExecStop=/etc/init.d/httpd_puerto53 stop (code=exited, status=0/SUCCESS)
Process: 4732 ExecStart=/etc/init.d/httpd_puerto53 start (code=exited, status=0/SUCCESS)
Main PID: 4732 (code=exited, status=0/SUCCESS)

Aug 16 12:28:41 prt53ws1 systemd[1]: Started Apache puerto53.
Aug 16 12:28:41 prt53ws1 systemd[1]: Starting Apache puerto53...
Aug 16 12:28:46 prt53ws1 httpd_puerto53[4732]: 4734 (process ID) old priority 0, new priority -19
[root@prt53ws1 system]#

Script de arranque y parada del servicio

Ya que estamos, os enseño el script que utilizo para parar y arrancar apache:

[root@prt53ws1 ~]# cat /app/puerto53/scripts/Apache/apache_puerto53.sh
#!/usr/bin/sh

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

if [ $1 == «start» ]
then


 
httpd -f /app/puerto53/httpd/conf/httpd.conf -k start -D SSL
sleep 5
PID=`cat /app/puerto53/httpd/run/httpd/httpd.pid`
/usr/bin/renice -n -19 $PID

elif [ $1 == «stop» ]
then

httpd -f /app/puerto53/httpd/conf/httpd.conf -k stop

fi
[root@prt53ws1 ~]#

Entendiendo el funcionamiento de Systemd

Sección Service

  • Directiva Type:
    • simple: El proceso principal del servicio se especifica en la línea de inicio. Este es el valor por defecto si las directivas «Type=» y «Busname=» no están establecidas, pero el «ExecStart=» sí lo está.
    • forking: Este tipo de servicio se utiliza cuando se crea un proceso hijo. Esto le dice a systemd que el proceso sigue ejecutándose aunque el padre haya salido.
    • oneshot: Este tipo indica que el proceso durará poco tiempo y que el sistema debe esperar a que el proceso salga antes de continuar con otras unidades.
    • dbus: Algunas aplicaciones necesitan conectarse entre sí mediante el protocolo D-BUS.
    • notify: El servicio enviará una notificación cuando haya terminado de ponerse en marcha. El sistema esperará antes de continuar con el arranque de otros servicios.
    • idle: El servicio no funcionará hasta la finalización de todos los trabajos.
  • Directivas relacionadas con la ejecución de los procesos:
    • ExecStart: Indicamos el proceso que va a iniciar el servicio.
    • ExecStartPre: Antes de la ejecución del proceso inicial, ejecutamos otros comandos.
    • ExecStartPost: Al finalizar el proceso, ejecutamos otros comandos.
    • ExecReload: Volvemos a leer la configuración del servicio
    • ExecStop: Especificamos el comando para finalizar el proceso.
    • ExecStopPost: Ejecutamos algunos comandos después de finalizar el proceso.
    • Restart: Indicamos las circunstancias en que systemd reiniciará el proceso automáticamente: “always”, “on-success”, “on-failure”, “on-abnormal”, “on-abort”, or “on-watchdog”.
    • TimeoutSec: Especificamos el tiempo máximo que Systemd esperará antes de parar el servicio si ha sido marcado como «failed» o «forcefully killing it».
  • Directivas adicionales:
    • RemainAfterExit: Se suele utilizar conjuntamente con oneshot. Indica que el proceso debería ser considerado en ejecución, incluso, si ha devuelto un código de salida.
    • PIDFile: Si el servicio es de tipo forking el PID del proceso se almacenará en el fichero indicado en esta directiva.
    • BusName: Utilizaremos esta directiva para indicar el nombre del bus (D-BUS) al que se asociará el proceso cuando arranque.
    • NotifyAccess: Especificamos el acceso al socket que se debe usar para escuchar las notificaciones cuando se selecciona el tipo de servicio «notify». Este puede ser «none», «main» o «all». El valor predeterminado «none», ignora todos los mensajes de estado. La opción «main» escucha los mensajes del proceso principal y la opción «all» escucha todos los procesos del servicio.
    • User y Group: Especificamos el usuario y grupo de sistema que arranca el servico.

Sección Socket

  • Las directivas más utilizadas:
    • ListenStream: Define una dirección TCP/IP para poder establecer una comunicación por red con el servicio.
    • ListenDatagram: Los servicios UDP utilizan este tipo de comunicación.
    • ListenSequentialPacket: Define la dirección de red para una comunicación secuencial. Si el dato enviado por red es muy grande, se envían varios paquetes de manera secuencial.
    • ListenFIFO: FiFo proviene de First In First Out o, lo primero que llega es lo primero que sale. Muchas aplicaciones utilizan este tipo de comunicación. Podemos definir un buffer de este tipo en vez de un socket.
  • Directivas de control de las comunicaciones:
    • Accept: Podemos definir si todas las comunicaciones las administrará una sola instancia o crearemos nuevas para repartir el tráfico entre ellas.
    • SocketUser: Definimos el usuario propietario del socket. Por defecto es el root.
    • SocketGroup: Definimos el grupo propietario del socket. Por defecto es root.
    • SocketMode: Definimos los permisos (de UNIX) para el socket.
    • Service: Podemos definir un nombre del servicio para el socket (MiServicio.socket).

Sección Mount

Mount está relacionado con los puntos de montaje de los filesystems, tal y como podemos ver en el fichero /etc/fstab.

  • What: Indicamos el path del recurso que vamos a montar.
  • Where: Especificamos dónde vamos a montar el recurso (punto de montaje).
  • Type: Indicamos el tipo de filesystem. Por ejemplo, XFS.
  • Options: Opciones de montaje. Cada opción se separará con una coma.
  • SloppyOptions: Si está definido como true y hay una opción de montaje incorrecta, él recurso se montará igualmente con las opciones de montaje por defecto.
  • DirectoryMode: Si se necesitan crear directorios para poder montar el filesystem, indicaremos con qué permisos se crearán.
  • TimeoutSec: Especificamos el tiempo máximo de espera para montar el filesystem.

Sección Automount

Las dos únicas directivas importantes son Where y DirectoryMode, que ya hemos visto anteriormente.

Sección Swap

Las unidades o servicios de swap se configuran para montar filesystems de swap en el sistema. Lo podemos hacer mediante la configuración del fichero /etc/fstab o con la llamada de una unidad o servicio de systemd.

Las directivas relacionadas con esta sección son:

  • What: Indicamos el path absoluto del recurso de swap.
  • Priority: Definimos la prioridad con la que el espacio de swap debe ser creado.
  • Options: Especificamos las opciones de montaje del swap, separadas por comas.
  • TimeoutSec: El tiempo de espera en segundos para montar el swap antes de dar la operación por fallada.

Sección Path

Una unidad path se define para que Systemd pueda monitorizar los cambios o la actividad de un path del sistema. Debe existir otra unidad que se activará cuando se detecten cierta actividad. La actividad del path se notifica mediante eventos inotify.

Directivas de esta sección:

  • PathExists: Revisa si el path indicado existe.
  • PathExistsGlob: Igual que la anterior directiva pero soporta expresiones glob.
  • PathChanged: La unidad asociada se activa si se detecta algún cambio.
  • PathModified: Igual que la directiva anterior pero actúa en las escrituras en los archivos o cuando se ha cerrado uno.
  • DirectoryNotEmpty: Activa la unidad asociada cuando el directorio ya no está vacío.
  • Unit: Se especifica la unidad que se activará.
  • MakeDirectory: Definimos si Systemd creará la estructura de directorios antes de monitorizarla.
  • DirectoryMode: Si la directiva anterior está habilitada, configuraremos los permisos de los directorios creados.

Sección Timer

Los «systemd timers» son una característica de systemd que se utiliza para programar y automatizar tareas periódicas en sistemas Linux. Estos timers son una forma de reemplazar o complementar las utilidades tradicionales de programación de tareas como cron.

Los timers en systemd funcionan en conjunto con las unidades de servicio para ejecutar tareas en momentos específicos o a intervalos regulares. Algunas de las características clave de los systemd timers incluyen:

1. Precisión: Los timers de systemd pueden ser altamente precisos, lo que permite especificar tareas para que se ejecuten en momentos exactos con resolución de segundos o incluso milisegundos.

2. Programación flexible: Podemos programar tareas para que se ejecuten en un horario específico, como todos los días a las 3 PM, o en intervalos regulares, como cada 30 minutos.

3. Unidades de servicio asociadas: Los timers trabajan en conjunto con unidades de servicio, lo que significa que puedes especificar qué tarea debe ejecutarse cuando el timer se active.

4. Gestión centralizada: Systemd proporciona herramientas como `systemctl` para administrar y supervisar timers, lo que facilita la gestión centralizada de tareas programadas en el sistema.

5. Registro de eventos: Systemd registra eventos relacionados con la activación y ejecución de timers, lo que facilita el seguimiento y la solución de problemas.

6. Flexibilidad para configurar temporizadores: Podemos configurar timers para que se activen en función de la fecha y hora actuales, o puedes utilizar temporizadores monotónicos que se cuentan a partir del inicio del sistema.

Parámetros o directivas de uso de esta sección:

  • OnActiveSec: Permite que la unidad asociada se active en relación con la activación de la unidad .timer.
  • OnBootSec: Especificamos el tiempo que pasará para que se active la unidad asocidad después de que el sistema se inicie.
  • OnStartUpSec: Similar al anterior pero se ejecuta unos segundos después de que el servicio Systemd se haya iniciado.
  • OnUnitActiveSec: Se configura un temporizador en relación a la última vez en que la unidad asociada fue ejecutada.
  • UnitInactiveSec: Se configura un temporizador en relación a la última vez en que la unidad asociada se marcó como inactiva.
  • OnCalendar: Podemos definir una fecha y hora exactas para ejecutar la unidad asociada.
  • AccuracySec: Especificamos la precisión del temporizador. Por ejemplo, la unidad asociada se activará en un plazo de un minuto desde que se alcanza el temporizador.
  • Unit: Indicamos la unidad que debe ser activada cuando alcancemos el temporizador.
  • Persistent: Si se configura, systemd activará la unidad asociada cuando el temporizador se active si se hubiera activado durante el período en que el temporizador estuvo inactivo.
  • WakeSystem: Permite despertar un sistema de suspensión si se alcanza el temporizador cuando está en ese estado.

Ejemplo de uso de Systemd Timers

1. Crea un archivo de unidad de servicio (`backup.service`):

Primero, crea un archivo de unidad de servicio que especifique la tarea que deseas realizar. Por ejemplo, crea un archivo llamado `backup.service` en `/etc/systemd/system/` con el siguiente contenido:

[Unit]

   Description=Backup Service

   [Service]

   Type=oneshot

   ExecStart=/ruta/a/tu/script_de_copia_de_seguridad.sh

  Asegúrate de cambiar `/ruta/a/tu/script_de_copia_de_seguridad.sh` por la ruta real de tu script de copia de seguridad.

2. Crea un archivo de unidad de timer (`backup.timer`):

Luego, crea un archivo de unidad de timer que especifique cuándo se activará el servicio de copia de seguridad. Crea un archivo llamado `backup.timer` en el mismo directorio (`/etc/systemd/system/`) con el siguiente contenido:

[Unit]

   Description=Backup Timer

   [Timer]

   OnCalendar=*-*-* 03:00:00

   Persistent=true

   [Install]

   WantedBy=timers.target

 

En este ejemplo, `OnCalendar` especifica que el servicio se activará todos los días a las 3 AM. Puedes ajustar el horario según tus necesidades.

3. Habilita y comienza el timer:

   Una vez que hayas creado ambos archivos, debes habilitar y comenzar el timer y la unidad de servicio asociada:

sudo systemctl daemon-reload
sudo systemctl enable backup.timer
sudo systemctl start backup.timer

   4. Verifica el estado del timer:

   Puedes verificar el estado del timer en cualquier momento usando:

sudo systemctl status backup.timer

Esto te mostrará si el timer se encuentra activo y cuándo está programada la próxima activación.

Ahora, systemd se encargará de ejecutar la tarea de copia de seguridad todos los días a las 3 AM, según la configuración del timer. Este es un ejemplo simple de cómo utilizar systemd timers para automatizar tareas periódicas en tu sistema Linux.

Conocer los servicios de systemctl de tipo timer que han fallado

Si queremos hacer un poco de troubleshooting y detectar que procesos de systemctl de tipo timer han fallado, simplemente, ejecutaremos el siguiente comando:

systemctl --type=timer --all --failed 

Esperar el arranque de un servicio antes de montar un filesystem

Algunos filesystems como, por ejemplo, Stratis necesitan que esté arrancado un servicio para poder ser montados. Para ello, y siguiendo con el ejemplo de Stratis, configuraremos el fstab de la siguiente manera:

/dev/test_stratis /stratis xfs defaults,x-systemd.requires=stratisd.service 0 0

Limitar los recursos de memoria y CPU de un servicio

Systemd utiliza cgroups para limitar el uso de recursos del sistema.

Si queremos limitar el uso de CPU de un servicio, utilizaremos la directiva CPUQuota, mientras que si queremos limitar el uso de memoria, emplearemos MemoryLimit. Veamos un ejemplo de un servicio que utiliza estas directivas:

[root@server1 ~]# systemctl cat cbdaemon
# /etc/systemd/system/cbdaemon.service
[Unit]
Description=Startup/shutdown script for VMware Carbon Black EDR Sensor
After=network.target

[Service]
Type=simple
ExecStartPre=-/etc/sysconfig/modules/cbresponse.modules
ExecStart=/usr/sbin/cbdaemon
KillMode=mixed
IgnoreSIGPIPE=no
GuessMainPID=no
Restart=on-failure
RestartSec=10
UMask=0027
WorkingDirectory=/opt/carbonblack/response/bin
StandardOutput=journal
StandardError=journal
CPUQuota=20%
MemoryLimit=1G

[Install]
WantedBy=multi-user.target
[root@server1 ~]#

Como podemos observar, estamos limitando el servicio a que pueda utilizar, como máximo, un 20% de CPU y 1GB de memoria.

Crear un servicio con Systemctl que solamente se ejecute durante la parada del sistema

En determinadas situaciones, nos interesa crear un script con una parada ordenada de una aplicación. Normalmente, el procedimiento de parada son varios pasos. Para ello, nos interesa crear un servicio que llame a este script solamente durante la parada del sistema operativo.

Para ello, utilizaremos los siguientes requerimientos:

Before=poweroff.target halt.target shutdown.target

Requires=poweroff.target

Por lo tanto, un servicio de ejemplo que solamente se ejecutase durante la parada del sistema, quedaría de la siguiente manera:

[Unit]
Description=Stop My Service
DefaultDependencies=no
Conflicts=reboot.target
Before=poweroff.target halt.target shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
User=docker
ExecStart=Script.sh stop
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target

Controlando el espacio que utilizan los ficheros .journal

En el directorio /var/log/journal/ se guarda la información de lo que hace cada servicio de systemd cuando para o arranca y se puede consultar por la línea de comandos de la siguiente manera:

# Ver los registros del último arranque del sistema
journalctl -b

# Ver los logs desde una fecha
journalctl --since "2022-10-25 10:00:00"

# Ver los logs entre dos fechas
journalctl --since "2012-10-25" --until "2022-11-12"

# Ver los logs desde ayer
journalctl --since yesterday

# Ver los logs desde ayer hasta hace dos horas
journalctl --since "2012-11-25" --until "2 hours ago"

# Ver los logs del servicio sshd
journalctl -u sshd.service

# Ver los logs de los servicios sshd y firewalld
journalctl -u sshd.service -u firewalld.service

# Ver los logs del servicio sshd entre dos fechas, horas y minutos
journalctl -u sshd.service --since "2012-11-05 13:12:38" --until "2012-11-08 14:00:00"

# Ver los logs de usuario con UID 1000
journalctl _UID=1000

# Ver registros en tiempo real
journalctl -f

Si no se limita el espacio que pueden ocupar estos logs, podemos tener un problema y llenar el filesystem /var:

[root@server1 b4035313481740e48eaf2d56867507c0]# journalctl --disk-usage
Archived and active journals take up 2.5G on disk.
[root@server1 b4035313481740e48eaf2d56867507c0]#

Para que esto no suceda, configuraremos la directiva SystemMaxUse=500M (o el tamaño que estimemos oportuno) del fichero /etc/systemd/journald.conf y reinciaremos el servicio journalctl:

systemctl kill --kill-who=main --signal=SIGUSR2 systemd-journald.service
systemctl restart systemd-journald.service

Si volvemos a consultar el espacio que ocupan los ficheros .journal, se habrá vaciado automáticamente.

COMPÁRTEME

Deja un comentario