Systemd

Presentación

En KDE 6, se está buscando que todos los procesos sean envueltos por systemctl, de manera que todos los procesos estén ordenados jerárquicamente pudiendo limitar los recursos usando cgroups.

Systemd es el proceso principal del sistema (PID1) del cual derivan todos los demás procesos, el único ancestro es el IDLE (PID0), que está reservado al kernel.


Directorios

Los servicios del sistema se se encuentran en tres directorios:

Directorio Prioridad Descripción
/usr/lib/systemd/system Baja Servicios creados por el SO
/run/systemd/system Media Servicios creados por procesos en tiempo de ejecución
/etc/systemd/system Alta Servicios creados por el usuario
~/.config/systemd/user Alta Servicios que se ejecutan cuando se inicia sesión

Directorio de Servicios Personalizado

Para los servicios que se crean manualmente y no hacen parte del sistema, lo mejor es usar una carpeta ~/services/ en el home y crear un enlace simbólico por cada servicio hacia ~/.config/systemd/user/. De esta manera se simplifica muchísimo tanto la creación de backups como el versionado con git.


Targets

Systemd usa un sistema de targets para agrupar los tiempos en que se ejecutan los procesos. A continuación se presenta una lista de muchos de ellos.

Estados del Sistema

Target Descripción
poweroff.target Apagado del sistema
reboot.target Reinicio del sistema
halt.target Apagado del sistema sin cortar electricidad
kexec.target Reinicio sin pasar por la BIOS
rescue.target Modo monousuario para reparaciones
emergency.target Modo más crudo, solo carga /bin/sh y FS en lectura
exit.target Cierre de sesión del usuario

Proceso de Arranque

Target Descripción
sysinit.target Servicios críticos tempranos
basic.target El sistema básico está listo
cryptsetup.target Configuración de discos cifrados
local-fs.target Todos los discos están montados
remote-fs.target Discos remotos montados
swap.target Todas las unidades swap están montadas
network.target Sistema de red listo
network-online.target El sistema tiene dirección IP
time-sync.target Reloj NTP sincronizado

Funcionalidad

Target Descripción
multiuser.target Estado normal de un servidor
graphical.target Estado normal de un escritorio
printer.target Servicios de impresión activo
sound.target Sistema de sonido activo
bluetooth.target Soporte de bluetooth activo

Tipos de Unidades

Target Descripción
paths.target Activa todas las unidades .path
timers.target Activa todas las unidades .timer
socket.target Activa todas las unidades .socket
slices.target Gestiona porciones de recursos

Crear un Servicio

Sección [Unit]

Contiene información general del servicio y algunas directrices. Tiene muchísimos parámetros, a continuación se listan los más importantes:

  • Description: Breve descripción de lo que hace el programa.
  • Documentation: Documentación relativa al daemon.
  • Before, After: Ordena la ejecución de los daemons y dependencias. Ejemplos: After=network.target sshdgenkeys.service, Before=ssh-access.target.
  • Wants: Carga las dependencias necesarias (si es que no están corriendo) al iniciar el daemon. En caso de que alguna dependencia no se cargue, inicia el daemon de todas maneras.
  • Requires: Lo mismo que Wants, pero si una dependencia no se carga, el daemon queda en estado inactivo.

Sección [Service]

Es la sección específica de un servicio, las otras dos son generales de los archivos Unit. A continuación se listan algunas de las directrices más importantes:

  • Type:
    • simple: Asume que el servicio está corriendo una vez el kernel le asigna un PID.
    • notify: Espera hasta que el servicio le envíe una notificación mediante sd_notify.
    • notify-reload: Similar a notify, pero además envía una notificación cuando un servicio es recargado.
  • ExecStart: Es lo más importante. Especifica el comando que será ejecutado al iniciar el daemon.
  • Restart: Reinicia automáticamente el proceso en caso de que sea cerrado:
    • always: Reinicia el proceso siempre.
    • on-success: Reinicia solo si cierra con exit-0.
    • on-failure: Reinicia solo si cierra con exit-1.
  • RestartSec: Determina la cantidad de segundos de espera antes de que el proceso sea iniciado nuevamente.
  • StartLimitIntervalSec, StartLimitBurst: Especifica el máximo de veces en que el proceso puede intentar reiniciarse en un intervalo de tiempo. Los valores predeterminados son 10 segundos y 5 veces respectivamente.
  • KillMode: Determina si los subprocesos del servicio se matarán también o no:
    • control-group: Es el que está por defecto, mata todos los subprocesos.
    • process: Mata solo el proceso principal y mantiene los subprocesos.
    • mixed: Da un tiempo de espera para que el proceso principal mate a los subprocesos. En caso de que no, mata a todos los subprocesos.

Sección [Install]

Directrices al usar systemctl enable:

  • WantedBy: Crea una dependencia débil con un target. Ejemplo: WantedBy=multi-user.target
    • Crea un enlace simbólico en el directorio .wants/
  • RequiredBy: Crea una dependencia fuerte con un target, afectando este. Ejemplo: RequiredBy=multi-user.target
    • Crea un enlace simbólico en el directorio .requires/
  • UpheldBy: Crea una dependencia con un target o servicio. No se deja apagar usando el subcomando stop a menos que la dependencia que lo inició se apague. Su uso es muy poco frecuente.
    • Crea un enlace simbólico en el directorio .upholds/

Sandboxing

El sandboxing agrupa las directrices de aislamiento y restricción del entorno de ejecución del servicio. Son independientes entre sí y pueden usarse con cualquier usuario, incluyendo root. Algunas de las más importantes:

  • ProtectHome=yes — el home aparece completamente vacío para el servicio.
  • ProtectHome=read-only — el home es visible pero no modificable.
  • PrivateTmp=yes — el servicio tiene su propio /tmp aislado.
  • ProtectSystem=strict — el sistema de archivos es de solo lectura para el servicio.
  • NoNewPrivileges=yes — el servicio no puede escalar privilegios.
  • RemoveIPC=yes — elimina los objetos IPC del servicio al detenerse.

Systemd puede crear y gestionar automáticamente directorios para el servicio, asignándoles los permisos correctos. Cada directriz recibe como parámetro una ruta relativa, no se permiten rutas absolutas ni el uso de ..

Directriz Ruta absoluta
StateDirectory= /var/lib/nombre
CacheDirectory= /var/cache/nombre
LogsDirectory= /var/log/nombre
RuntimeDirectory= /run/nombre
ConfigurationDirectory= /etc/nombre

DynamicUser

Para los servicios expuestos a internet, la opción más segura es usar DynamicUser=yes. A diferencia de un usuario fijo, el UID cambia en cada arranque y no existe en /etc/passwd. Además activa implícitamente las siguientes directrices de sandboxing:

  • ProtectHome=read-only
  • PrivateTmp=yes
  • ProtectSystem=strict
  • RemoveIPC=yes

Con DynamicUser=yes la única forma de persistir datos es usar las directrices de sandboxing anteriores, ya que systemd transfiere la propiedad al usuario dinámico en cada arranque.

En mi caso particular, decidí que para facilitar las copias de seguridad, todos los servicios personales usarán una subcarpeta con el nombre de usuario como prefijo:

StateDirectory=jade/mi-servicio  # /var/lib/usuario/mi-servicio

Esto agrupa todos los datos bajo /var/lib/usuario/, separando claramente lo que gestiona el sistema de lo que se gestiona manualmente, y simplificando las copias de seguridad a un único directorio.


https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html