Linux – El sistema de inicio Systemd

por | 22 octubre, 2015

Según la definición oficial, systemd es un gestor del sistema y de los servicios para Linux, compatible con los initscript SysV y LSB. Systemd utiliza la activación de socket y D-Bus para iniciar los servicios y permite el inicio de los demonios bajo demanda, realiza un seguimiento de los procesos con el uso de los grupos de control de Linux, apoya snapshotting y la restauración del estado del sistema, mantiene los puntos montaje y servicios de montaje automático e implementa un elaborado sistema de gestión de dependencias basado en un control lógico de los servicios.

Como paquete integral de software, systemd remplaza a la secuencia de arranque de Linux y los niveles de ejecución controlados por el demonio de inicio tradicional , junto con la ejecución de los scripts bajo su control.

En systemd el primer demonio de ejecución se llama precisamente systend y es el que tiene PID 1.

Los Units

En systemd los servicios se denominan units. Cada unit se define en un archivo donde se especifica un proceso para arrancar por systemd. Evidentemente el arranque de un unit puede estar supeditado a determindas circunstancias como la dependencia de otros units.

Existen varios tipos de units, no sólo servicios, cuyos archivos se nombran con la extensión correspondiente:

  • servicios (.service)
  • puntos de montaje (.mount)
  • dispositivos (.device)
  • sockets (.socket)

Los archivos que definen los units (y los targets) se pueden encontrar básicamente en tres ubicaciones distintas:

/usr/lib/systemd/system/: unidades distribuidas con paquetes RPM instalados.

/run/systemd/system/: unidades creadas en tiempo de ejecución. Tiene precedencia sobre el directorio anterior.

/etc/systemd/system/: unidades creadas y administradas por el administrador del sistema. Este directorio tiene precedencia sobre el directorio anterior.

El formato de un archivo unit sigue unas reglas y nomenclatura específicas. Básicamente se divide en varias secciones se las cuales las principales son:

[Unit]
[Service]
[Install]

A continuación se indican esquemáticamente las opciones más importantes dentro de cada sección.

[Unit]

Description=<descrición del unit>

Una descripción del servicio que se muestra al consultar el status del servicio.

After=<units>

Define el orden en el cual los unist se inician. El unit se inicia sólo después de que los units especificados en esta línea estén activos. La diferencia con Require es que After no activa explícitamente los units indicados aquí. La opción Before tiene la funcionalidad opuesta a After.

Requires=<units>

Configuras las dependencias sobre otras units. Los units listados aquí serán activados junto con este unit. Si alguno de los units requeridos falla en el arranque, este unit tampoco se activa.

Wants=<units>

Activa los units indicados aquí. Wants configura dependencias de manera más débil que Require. Si alguno de los units indicados por Wants no se inician correctamente no tienen ningún efecto en el estado de este unit. Wants es la manera recomendada para establecer dependencias personalizadas.

Conflicts=<units>

Configura dependencias negativas, es decir, es un opuesto a Requires. El servicio no se inicia si el servicio indicado en esta línea está activo.

[Service]

TimeoutStartSec=<n>

Tiempo tras el cuál, si el servicio no ha arrancado, se considera fallo y se detiene.

ExecStart=<ejecutable>

comando a ejecutar.

Type=<opción>

Configura el tipo de arranque del procesos de la unidad la cual afecta a la funcionalidad ExecStart. Las opciones son:

  • simple – Es el valor por defecto. El proceso arrancado con ExecStart es el proceso principal del servicio. Este proceso se arranca inmediatamente. El proceso no debe desencadenar otros procesos que requieran ejecución en el algún orden. No utilizar este tipo si otros servicios necesitan ejecutarse en orden con él.
  • forking – El proceso iniciado con ExecStart genera un proceso hijo que se convierte en el proceso principal del servicio. Se sale del proceso padre cuando el arranque se completa. El uso de esta opción es importante cuando ejecutamos un script que a su vez ejecuta otros procesos. Sin la opción forking estos subprocesos podrían salir inesperadamente al concluir el proceso principal.
  • oneshot – Similar a simple, pero se sale del proceso  antes de que se arranquen los subsiguientes units. Es útil para la ejecución de scripts que hacen un trabajo sencillo y luego salen. Con la opción RemainAfterExit=yes systemd considerará su proceso como activo después de que el proceso haya salido.
  • dbus – Similar a simple, pero los subsiguientes units sólo son arrancados después de que el proceso principal adquiera un nombre D-Bus.
  • notify – Similar a simple, pero los subsiguientes units sólo son arrancados después de que un mensaje de notificación se haya enviado mediante una función sd_notify().
  • idle – Similar a simple, la ejecución actual del binario del servicio se retrasa hasta que todos los trabajos se terminan, lo que evita la mezcla de la salida de estados con las salidas de los servicios por la Shell.

[Install]

WantedBy=multi-user.target

Indica el target al que pertenece este unit. Esto provoca que el comando systemctl enable <servicio>.service cree los enlaces simbólicos necesarios dentro del target multi-user.target.wants sin necesidad de hacerlo manualmente.

Lo que se consigue con esto es que el servicio se ejecute automáticamente al arrancar el target.

Los Targets

Un conjunto de units definen un target. El target es el equivalente al concepto de runlevel, es decir un conjunto de servicios que se ejecutan en determinadas circunstancias. Así por ejemplo, el runlevel 3 de System V corresponde al target multi-user.target en systemd y el runlevel 5 correspondería al target llamado  graphical.target

Nivel de ejecución SystemV

Target de Systemd

Notas

0 runlevel0.target, poweroff.target Apaga el sistema
1, mono usuario runlevel1.target, rescue.target Modo mono-usuario
2, 4 runlevel2.target, runlevel4.target, multi-user.target Modo de inicio definido por el usuario/sistema, por default identico a 3
3 runlevel3.target, multi-user.target Multiusuario, entorno grafico
5 runlevel5.target, graphical.target Multiusuario, entorno grafico, todos los servicios del nivel 3 mas un entorno grafico
6 runlevel6.target, reboot.target reinicio
emergency emergency.target Shell de emergencia

A diferencia de los runlevels, los targests se pueden ejecutar a la vez.

systemctl

En Systemd la forma de controlar los servicios del sistema cambia. Los servicios ya no se controlan a través de /etc/init.d y tampoco se utiliza el comando «service». Aquí se utiliza el gestor de servicios llamado systemctl.

La principal orden para controlar systemd es systemctl. systemctl sustituye a chkconfig de System V.

systenctl es una herramienta potente con muchas opciones. A continuación se listan las más importantes atendiendo su funcionalidad.

GESTION DE SERVICIOS

systemctl

Sin argumentos muestra una lista de todos los servicios  y otras unidades disponibles en el sistema.

systemctl list-unit-files

Lista todos los ficheros de unidades conocidos independientemente de su estado.

systemctl list-units

Los servicios disponibles que se encuentra listados en los directorios /lib/systemd/system y /etc/systemd/system.

systemctl list-dependencies <servicio>.service

Lista las dependencias de un servicio

systemctl show <service>.service

Visualizar las propiedades del unit.

systemctl start <servicio>.service

Arrancar servicios.

systemctl stop <servicio>.service

Parar servicios.

systemctl status <service>.service

Visualiza el estado e información de ejecución de un servicio.

systemctl is-active <service>.service

Muestra simplemente si el servicio está activo, es decir, en ejecución. De manera similar se dispone de las opciones «is-enabled» y «is-failed».

systemctl enable <servicio>.service

Habilitar servicios en el arranque.

systemctl disable <servicio>.service

Deshabilitar servicios en el arranque.

systemctl restart <servicio>.service

Reiniciar un servicio.

systemctl reload <servicio>.service

Recarga la configuración de un servicio si reiniciarlo. No todos los servicios lo permiten.

systemctl mask <servicio>.service

Marca un servicio como completamente inarrancable. Previene que un servicio sea arrancado ni automáticamente y manualmente.

GESTION DE NIVELES DE EJECUCIÓN (TARGETS):

systemctl get-default

Muestra el target por defecto.

systemctl list-unit-files –type=target

Lista los targets disponibles.

systemctl list-units –type=target

Lista los targests activos. A diferencia de los runlevels, varios targets pueden estar activos al mismo tiempo.

systemctl list-dependencies <nivel_ejecución>..target

Muestra las depencencias de un target.

systemctl set-default <nivel_ejecución>.target

Configura el target por defecto en el próximo arranque.

systemctl isolate <nivel_ejecución>.target

Similar al cambio de runlevel el SysV. Arranca todos los units del target indicado y para todos los units que no son parte del árbol de ejecución del mismo.

Existen targets definidos para eventos importantes, como parar o reiniciar la máquina. systemctl posee atajos para algunos de ellos:

systemctl halt

Parada del sistema. Equivale a systemctl isolate halt.target.

systemctl poweroff

Shutdown completo del sistema. Equivale a systemctl isolate poweroff.target.

systemctl reboot

Reinicio del sistema. Equivale a systemctl isolate reboot.target.

systemctl rescue

Pone el sistema en modo monousuario. Equivale a systemctl isolate rescue.target.

Por último, systemctl posee un frontend gráfico oficial llamado systemadm. Proporcionado por el paquete systemd-ui-git.

Arranque del sistema

Por defecto en el arranque del sistema systemd activa el target default.target el cual a través de sus dependencias activa a su vez los demás units y servicios.

El parámetro systemd.unit= en línea de comando del kernel controla el primer unit a arrancar y puede ser utilizada para iniciar temporalmente una unidad de arranque distinto.

systemd.unit=rescue.target es una unidad target especial para configurar el sistema base y un shell de rescate (similar al nivel 1 de ejecución).
systemd.unit=emergency.target, es muy similar a passing init=/bin/sh pero con la opción para arrancar el sistema completo desde allí.
systemd.unit=multi-user.target para configurar un sistema multiusuario no gráfico.
systemd.unit=graphical.target para configurar una pantalla gráfica de inicio de sesión.

Systemd utiliza un enlace simbólico en /etc/systemd/system/default.target para apuntar al target que se arranca por defecto. Para cambiar el target por defecto hay que eliminar el enlace y crear uno nuevo:

rm /etc/systemd/system/default.target
ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
ln -sf /lib/systemd/system/graphical.target /etc/systemd/system/default.target

Aranque y personalización del sistema

Arranque

En un encendido del sistema, la BIOS inicialmente arranca desde el medio seleccionado e inicia el kernel. Systemd lee el archivo:

/etc/systemd/system/default.target

que no es más que un enlace a un archivo de target en /lib/systemd/system/, habitualmente graphical.target para un entorno gráfico (equivalente el runlevel 5) o bien multi-user.target que es un entorno no gráfico multiusuario (equivalente el runlevel 3).

Nota: En realidad se llama a /usr/lib/systemd/system ya que en la actualidad /lib es un enlace a /usr/lib y se mantiene por compatibilidad, al menos en Centos 7.

En el caso se arranque de multi-user.target la secuencia de arranque es habitualmente:

/etc/systemd/system/default.target enlaza a /lib/systemd/system/multi-user.target (o lo que es lo mismo /usr /lib/systemd/system/multi-user.target ).

En este archivo de multi-user.target, se indica mediante formato específico, qué debe arrancar antes que este target (Requires) y qué debe arrancar después (Wants). También se indica que este target se arranque sólo después de estar arrancados otras cosas (After). El contenido de multi-user.target es:

[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes

[Install]
Alias=default.target

De donde vemos:

  • basic.target debe ejecutarse antes (Require).
  • Sólo debe ejecutarse después de basic.target, rescue.service y rescue.target.

A partir de ahí se ejecuta cada cosa del /usr/lib/systemd/system/basic.target antes de nada. Una vez hecho lo cual, se ejecutarán todos los unit (services, targets, etc.) en los directorios /etc/systemd/system/multi-user.target.wants y /usr/lib/systemd/system/multi-user.target.wants.

Al habilitar un servicio, un enlace simbólico se coloca en el directorio /etc/systemd/system/multi-user.target.wants.

En dicho directorio es donde encontraremos enlaces a la mayoría de los servicios que se inician en modo multiusuario (impresión, cron, auditoría, SSH, etc.).

Por su parte el archivo /usr/lib/systemd/system/basic.target inicia los servicios básicos asociados con todos los sistemas que ejecutan Red Hat Enterprise Linux 7. Dicho fichero llama target sysinit.target.

El archivo /usr/lib/systemd/system/sysinit.target arranca los servicios de inicialización del sistema, como el montaje de sistemas de archivos y el dispositivo swap.

A partir de ahí se ejecutan otros targests como local-fs.target y swap.target.

En el caso se arranque de graphical.target la secuencia de arranque es habitualmente:

etc/systemd/system/default.target enlaza a lib/systemd/system/graphical.target.

El contenido de  /usr/lib/systemd/system/es:

Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes

Lo que quiere decir que el target multi-user.target se ejecuta lo primero (todo lo que hemos visto antes) antes que el graphical.target. Luego se ejecutará /etc/systemd/system/display-manager.service el cual arrancará a su vez el GNOME display manager.

Personalización

Por supuesto es posible personalizar los units existentes e incluir units nuevos que arranquen servicios personalizados.

Como hemos visto los archivos de units disponibles en el sistema se ubican en:
/usr/lib/systemd/system y /etc/systemd/system.

Los archivos en /etc/systemd/system tienen una mayor precedencia sobre archivos unidad de /lib/systemd/system, por lo que podemos copiar units existentes desde  /lib/systemd/system hacia /etc/lib/systemd/system y personalizarlos allí.

Si lo que queremos es crear un servicio nuevo basado en un script u otra aplicación, podemos hacer lo siguiente:

Crear un nuevo archivo llamado script.service en /etc/systemd/system.

[Unit]
Description=My script
[Service]
ExecStart=/usr/bin/script.sh
[Install]
WantedBy=multi-user.target

En donde se está indicando que se ejecute el escipt =/usr/bin/script.sh después de la ejecución del target multi-user.target.

A continuación este service lo habilitamos como cualquier servicio:

# systemctl enable script.service

lo cual ejecuta un:

ln -s ‘/etc/systemd/system/schipt.service’ ‘/etc/systemd/system/multi-user.target.wants/script.service’

Arranque personalizado por parámetros al GRUB

Systemd permite especificar un montón de parámetros al kernel en el inicio. Estos parámetros se escriben en la línea de arranque desde el grub:

systemd.unit=<target>
Sobreescribe de manera temproal en que target iniciará, es usado para iniciar de manera temporal en otro nivel de ejecución, como nivel mono usuario: systemd.unit=rescue.targeto

emergencia: systemd.unit=emergency.target, el default es default.target

systemd.dump_core=<yes,no>
Si es cierto tirara lo registros cuando truene. De otra forma ningun registro se crea (ideal para averiguar que genera un kernel panic)

systemd.crash_shell=<yes,no>
Si es cierto systemd iniciara una shell cuando truene. De otra forma no hará nada, el default es no hacer nada, por razones de seguridad está desactivado ya que la shell a donde llega está desprotegida por contraseña.

systemd.crash_chvt=<n>
Si n es positivo, systemd activará la terminal virtual especificada (el default es -1).

systemd.confirm_spawn=
Toma un argumento booleano. Si es verdadero, systemd pedira configmacion para iniciar procesos (default es falso)

systemd.show_status=<yes,no>
Si es verdadero systemd envia mensajes de estatus a la consola durante el inicio (default en verdadero).

systemd.sysv_console=<yes,no>
Si es verdadero, la salida de los scripts de sysvinit seran mostrados en cosola. El default es verdadero, a menos que el parametro quiet sea pasado como argumento de inicio

systemd.log_target=<target>
Establece el objetivo del registro. el argumento debe ser uno de estos: console, syslog, kmsg, syslog-or-kmsg, null.

systemd.log_level=<level>
Establece un nivel de registro. Como argumento acepta un numero o los conocidos nombres de syslog: emerg, alert, crit, err, warning, notice, info, debug. 

systemd.log_color=<yes, no>
Subraya importantes mensajes de registro. Por defecto es verdadero.

systemd.log_location=
Especifica la ruta a donde guardar los registros a efectos de debugging.

ALGUNOS EJEMPLOS DE ENCADENAMIENTO DE SERVICIOS

Servicio A personalizado se ejecuta automáticamente en el arranque con el target multi-user.target:

[Unit]
Description=Servicio A
Requires=multi-user.target
[Service]
Type=simple
ExecStart=/bin/servicioA.sh
[Install]
WantedBy=multi-user.target

Servicio A se ejecuta automáticamente con el arranque en el target multi-user.target. El servicio A una vez iniciado, lanza al servicio B:

[Unit]
Description=Servicio A
Requires=multi-user.target
Wants=ServicioB.service
[Service]
Type=simple
ExecStart=/bin/servicioA.sh
[Install]
WantedBy=multi-user.target
 [Unit]
Description=Servicio B
[Service]
Type=simple
ExecStart=/bin/servicioB.sh
[Install]

Servicio A se ejecuta automáticdamnete con el arranque en el target multi-user.target. Una vez inicado el servicio A, éste lanza al servicio B cuando el servico A concluye:

[Unit]
Description=Servicio A
Requires=multi-user.target
[Service]
Type=simple
ExecStart=/bin/servicioA.sh
ExecStop=/usr/bin/systemctl start ServicioB.service
[Install]
WantedBy=multi-user.target
 [Unit]
Description=Servicio B
[Service]
Type=simple
ExecStart=/bin/servicioB.sh
[Install]

 

 

 

Un pensamiento en “Linux – El sistema de inicio Systemd

Deja un comentario

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