systemd-d dale una oportunidad

Dale una oportunidad a Systemd

Systemd es un software creado por Lennart Poettering y Kay Sievers en 2010 que tiene mucha polémica y controversia detrás. Cuenta con muchos detractores debido a su estructura compleja que a todas luces parece ir en contra de la filosofía GNU/Linux y Unix; pero tanto si lo odias como si lo amas, la realidad es que a día de hoy, la mayoría de distribuciones lo han implantado.
Por este motivo y para que podáis exprimirlo un poco más os presento una pequeña guía para que le deis una oportunidad y comencéis a usarlo en el día a día si no lo hacéis ya.

¿Qué es Systemd?

Systemd es un software que se encarga de iniciar el sistema así como de gestionar todo el sistema. Es el sucesor de otros software de inicio como SysVinit o Upstart entre otras muchas cosas.

Las unidades

En comparación con SysVinit que funciona con scripts, Systemd trabaja con unidades (units). Hay unidades de muchos tipos: device, mount, service, socket, target, timer, etc.

Cada unidad no es más que un fichero de texto en el que la extensión del fichero define el tipo de unidad (.target, .service, etc…).
Dependiendo de la distribución podemos encontrar estos archivos en /lib/systemd/system/, /etc/systemd/system/, /run/systemd/ o /usr/lib/systemd/. Para conocer todas las rutas podemos ver las páginas man de systemd.unit.

De esta forma si echamos un vistazo a /lib/systemd/system/ veremos las unidades hay dentro y lo mismo pasa con /etc/systemd/system/.

systemd-01
Esto son sólo algunos

Si miramos el contenido de uno de estos archivos, por ejemplo ssh.service:

systemd-02

Veamos los bloques que definen el archivo:

  • [Unit]: Define la unidad en sí (nombre, descripción,…). Define también las condiciones, dependencias y restricciones necesarias para ejecutar la unidad: unidades que es necesario cargar antes o después y el orden de ejecución de todas las unidades necesarias.
  • [Service]: Aquí se definen las acciones que realiza la unidad cuando se inicia, para, recarga o muere.
  • [Install]: Define en qué escenarios se cargará automáticamente esta unidad. En el caso de la imagen, cuando se cargue el multi-user.target se cargará también ssh.service. También define Alias para el servicio.

Los tipos de unidades que veremos con más frecuencia son los targets, services y timers:

  • Target: Son los escenarios en los que se ejecuta el sistema. Son los antiguos runlevels. No me voy a extender en esto, pero dejo abajo una imagen con la correspondencia entre runlevels y targets.
  • Service: Son los servicios propiamente dichos. Pueden residir en memoria o ejecutarse una sola vez cuando sea necesario.
  • Timer: Son tareas programadas para la ejecución de otras unidades. Similar a cron.

Hablar con Systemd: systemctl

Una vez que sabemos a grandes rasgos que son las unidades y sus tipos, debemos interactuar con Systemd para pedirle información o que haga cosas por nosotros. El principal comando para esto será systemctl.

Obtener información de las unidades

Listar unidades activas

systemctl list-units: Lista todas las unidades activas. Al ejecutarlo veremos algo similar a esto (sólo pongo unos pocos):

root:~# systemctl list-units
accounts-daemon.service         loaded active running   Accounts Service                    
alsa-restore.service            loaded active exited    Save/Restore Sound Car
apparmor.service                loaded active exited    Load AppArmor profiles
avahi-daemon.service            loaded active running   Avahi mDNS/DNS-SD Stac
binfmt-support.service          loaded active exited    Enable support for add
bluetooth.service               loaded active running   Bluetooth service                   
colord.service                  loaded active running   Manage, Install and Ge
console-setup.service           loaded active exited    Set console font and k
cpufrequtils.service            loaded active exited    LSB: set CPUFreq kerne
cron.service                    loaded active running   Regular background pro
cups-browsed.service            loaded active running   Make remote CUPS print
cups.service                    loaded active running   CUPS Scheduler                      
dbus.service                    loaded active running   D-Bus System Message B
exim4.service                   loaded active running   LSB: exim Mail Transpo
gdm.service                     loaded active running   GNOME Display Manager

Si usamos -t podemos filtrar un tipo de unidad concreto, también podemos pasarle un patrón para filtrar por palabras. Si añadimos –all vemos también los inactivos.

Listar todas las unidades

systemctl list-unit-files: Muestra no sólo los activos, sino todos los archivos de unidades que hay en el sistema, cargados o no. Es interesante destacar la opción –state= con la que podremos ver las unidades con cierto estado, como enabled, disabled, masked, etc.

root:~# systemctl list-unit-files --state=enabled
UNIT FILE                                  STATE  
accounts-daemon.service                    enabled
anacron.service                            enabled
apparmor.service                           enabled
autovt@.service                            enabled
avahi-daemon.service                       enabled
binfmt-support.service                     enabled
bluetooth.service                          enabled
console-setup.service                      enabled
cron.service                               enabled
cups-browsed.service                       enabled
cups.service                               enabled

Listar dependencias

systemctl list-dependencies: Muestra el árbol de dependencias para una unidad. Es decir todas aquellas que estén relacionadas mediante las condiciones requires, wants, wantedby, after, berfore, etc.

systemd-03

Normalmente list-dependencies sigue recursivamente las dependencias de tipo requies, wants, etc. Podemos hacer que sigua las de tipo inverso, es decir, requiredby, wantedbym etc con –reverse. También podemos decirle que muestre las dependencias después de las cuales nuestro servicio debe ejecutarse con –after o las dependencias antes de las cuales nuestro servicio debe ejecutarse con –before.

Mostrar contenido

systemctl cat: Muestra el contenido del archivo de una unidad. Es lo mismo que usar cat pero no tenemos que indicar la ruta del archivo, sólo su nombre. En el resultado veremos un comentario con la ruta del archivo.
El resultado es el mismo que vimos al examinar el archivo ssh.service más arriba.

systemctl cat ssh.service 
# /lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=sshd.service

Cambiando de target

Como hemos visto más arriba los targets sustituyen a los runlevels. Podemos ver la correspondencia entre ambos en la siguiente imagen:

systemd-04

Saber el target por defecto

systemctl get-default: Nos dice que target se carga por defecto al arrancar el sistema.

root:~# systemctl get-default 
graphical.target

Cambiar el target por defecto

systemctl set-default: Cambia el target por defecto.

Cambiar de target (aislar unidad)

systemctl isolate [target]: Inicia la unidad especificada y todas sus pendencencias y además para todas las unidades que no sean dependencia de esta. Esto nos permite cambiar al target que especifiquemos.

root:~# systemctl isolate rescue.target

Se puede abreviar quitando isolate y poniendo sólo el nombre del target:

root:~# systemctl rescue

Saber el target actual

Para saber en que target nos encontramos sigue siendo más rápido usar el comando runlevel, esto nos dará el número de runlevel con el que podremos saber el target mirando la imagen de correspondencia entre ambos. Pero si quisiéramos saberlo con systemd, podemos filtrar los targets activos con list-units.
Vamos a decirle a systemd que nos liste todas las unidades activas (list-units) de tipo (-t) target y las filtramos con egrep para que sólo muestre las que empiecen por res (rescue), mu (multi-user) o gra (graphical):

systemctl list-units -t target | egrep ‘res|mu|gra’ (list-units se puede omitir).

root:~# systemctl -t target | egrep 'res|mu|gra'
graphical.target       loaded active active Graphical Interface        
multi-user.target      loaded active active Multi-User System 

Podemos ver que hay dos activos. Debemos tener en cuenta la jerarquía, es decir, multi-user.target es necesario como base para correr graphical.target. Por tanto graphical será target actual.

Gestión de servicios

Arrancar y parar servicios

systemctl:

  • start: Arranca un servicio
  • stop: Para un servicio
  • restart: Reinicia un servicio

Ver el estado

systemctl status: Muestra el estado de un servicio. Además, indica información interesante como si está activo, habilitado, si ha dado algún error, etc.

root:~# systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/lib/systemd/system/ssh.service; disabled; vendor preset: enabled)
     Active: inactive (dead)
       Docs: man:sshd(8)
             man:sshd_config(5)

Recargar un servicio

Algunos servicio permiten modificar su configuración sin tener que parar el servicio. La configuración no se aplica justo después de modificarla sino que habría que parar y arrancar de nuevo el servicio. Con systemctl reload se aplica la nueva configuración sin tener que parar el servicio.

Habilitar o deshabilitar

systemctl enable/disable: Habilita o deshabilita un servicio para que se ejecute al inicio del sistema. Sin embargo, un servicio con estado «disabled»se puede ejecutar manualmente con la orden start.

Enmascarar o desenmascarar

systemctl mask/unmask: Enmascara o desenmascara un servicio. Un servicio enmascarado no puede ser ejecutado, ni automáticamente ni manualmente, por ningún usuario.

Tareas programadas y trabajos

Los timers son un tipo de unidades que están activas y programadas para ejecutar un servicio en un momento determinado.

Listar timers

Podemos listar los timers activos y ver desde cuando están activos, la última vez que se ejecutaron y cuando se volverán a ejecutar.
systemctl list-timers: Lista todos los timers activos. Se le puede añadir un patrón para listar sólo los que coincidan con el patrón. Si añadimos –all vemos también los inactivos.

root:~# systemctl list-timers
NEXT        LEFT           LAST         PASSED       UNIT        
2020-01-25  27min left     2020-01-25   35min ago    anacron.time
2020-01-25  12h 40min left 2020-01-24   1 day 2h ago apt-daily.ti
2020-01-26  10h left       2020-01-25   2h 29min ago exim4-base.t
2020-01-27  1 day 10h left 2020-01-20   5 days ago   fstrim.timer    

4 timers listed.
Pass --all to see loaded but inactive timers, too.

Cada unidad timer tiene asociada otra con el mismo nombre pero service. De esta forma el timer lanza el servicio que tenga su mismo nombre.

Vamos a ver como ejemplo fstrim.timer. Si vemos su contenido:

root:~# systemctl cat fstrim.timer
# /lib/systemd/system/fstrim.timer
[Unit]
Description=Discard unused blocks once a week
Documentation=man:fstrim

[Timer]
OnCalendar=weekly
AccuracySec=1h
Persistent=true

[Install]
WantedBy=timers.target

Vemos que se ejecuta semanalmente y además es persistente. Esto significa que si el equipo está apagado en el momento en el que debería ejecutarse el timer, este se ejecutará la próxima vez que se encienda el equipo.

Veamos ahora su servicio asociado, es decir fstrim.service:

root:~# systemctl cat fstrim.service
# /lib/systemd/system/fstrim.service
[Unit]
Description=Discard unused blocks on filesystems from /etc/fstab
Documentation=man:fstrim(8)

[Service]
Type=oneshot
ExecStart=/sbin/fstrim --fstab --verbose --quiet
ProtectSystem=strict
ProtectHome=yes
PrivateDevices=no
PrivateNetwork=yes
PrivateUsers=no
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
MemoryDenyWriteExecute=yes
SystemCallFilter=@default @file-system @basic-io @system-service

ExecStart indica lo que hace el servicio al ser lanzado.

Si quisiéramos crear nosotros un timer, tendríamos que crear ambos archivos (timer y service), copiarlos en alguna de las rutas donde systemd busca las unidades y activar el timer con systemctl enable. Para conocer estas rutas podemos ver las páginas man de systemd.unit.

Listar trabajos en curso

systemctl list-jobs: Lista todos los trabajos en progreso.

Los registros: journalctl

Otra de las tareas que hace Systemd es anotar todo lo que pasa en el sistema. Vamos, los logs de siempre. Para obtenerlos usaremos journalctl.

  • -S y -U: Con esta opciones pediremos los registros desde (since) una fecha determinada o hasta (until) una fecha determinada.

El formato de la fecha será: YYYY-MM-DD [HH:MM:SS], yesterday, today, tomorrow, ‘N day ago’, -/+ NhMmin (-3h10min, -2h, -15min, …).

  • -k y -b: -k muestra sólo los mensajes del Kernel y -b muestra sólo los mensajes del arranque. Por tanto -kb sería el equivalente a dmseg.
  • -p: Filtra por tipos (info, err, warn, etc).
  • -u: Filtra por tipo de unidad.
  • PARAM=VALUE: Podemos indicar algunos parámetros como _PID (PID del proceso), _UID (UID de usuario), _COMM (comando), etc. Para saber más podemos consultar los manuales de systemd.journal-fields.

En fin, creo con esto ya tenéis una buena base para empezar y trabajar con Systemd. Siempre podéis profundizar más, leyendo las páginas man de cada comando. También hay una documentación muy interesante en https://systemd.io/.
Espero que os haya gustado el artículo y nos vemos en el próximo.

Si os gustó este artículo podéis echar un vistazo a Reinstalando GRUB de forma indolora, Hablemos de Rsync o Jugando con la Raspberry Pi: Configuración inicial

Saludos linuxeros.

Deja un comentario

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.