4.1.2.5. Personalización¶
Ya se ha explicado cómo consultar, arrancar y parar servicios y cómo funcionan los niveles de ejecución en systemd. Con esto es suficiente para manipular de modo básico los servicios. Sin embargo, en algunas ocasiones, es necesario manipular la manera en la que arrancan éstos (p.e. añadiendo o eliminando una opción a la orden que crea el proceso) o, incluso, crear lanzadores de un determinado servicio para systemd.
Bajo el presente epígrafe se describirá superficialmente cómo está organizado systemd, cuál es la estructura de los archivos que permiten arrancar y parar los servicios y cómo pueden modificarse éstos para modificar tales acciones.
4.1.2.5.1. Preliminares¶
Es muy importante tener presente que un servicio no es más que un proceso que actúa en segundo plano. Consecuentemente, tal servicio debió originarse cómo consecuencia de la invocación de una orden. Por ejemplo, el servicio ssh se crea mediante la ejecución del programa sshd, así que si nos aseguramos de que el servicio no está corriendo[1], podemos levantar el servidor directamente del siguiente modo:
# /usr/sbin/sshd -D
La terminal en este caso quedará ocupada y desde otras máquinas podremos acceder al servidor. Sin embargo, este manera de proceder sólo es útil cuando nos interesa ver mensajes de salida que pueda proporcionar el servidor en caso de depuración. Arrancar un servicio de forma adecuada exige más: controlar si el servicio está arrancado o no, hacerlo automáticamente, etc. Por este motivo, los servicios no se arrancar directamente, sino que el proceso init (en nuestro caso particular, systemd) se encarga de ello.
4.1.2.5.2. Estructura¶
Cada servicio[2] dispone de una unidad de systemd que describe los requisitos, el ejecutable y los parámetros con que tiene que arrancarse.
En Debian los archivos que representan las unidades se incluyen dentro del
directorio /lib/systemd/system
. Por ejemplo, para el servicio SSH la instalación del paquete openssh-server proporciona un
archivo llamado ssh.service
. En caso de que se desee hacer algún cambio,
es mejor no tocarlos, ya que dentro del directorio /etc/systemd/system
se pueden incluir archivos homónimos que sobrescriben el archivo instalado por
la distribución.
A partir de ahora nombraremos como unidad
al archivo que representa a la
unidad. Por tanto, tendremos un archivo proporcionado por la distribución que es
/lib/systemd/system/unidad
que puede ser remplazado por el archivo
/etc/systemd/system/unidad
.
Además de estos archivos, que representan la unidad completa, hay una serie de
subdirectorios dentro de /etc/systemd/system/unidad
asociados también a
ella:
unidad.d
, que permite incluir archivos con directivas adicionales al archivo de configuración principal. Si una directiva también existe en el archivo principal, el valor no se sobreescribirá, sino que pasará a tener ambos valores, lo cual puede ser lícito o no. Para sobreescribir el valor es necesario incluirla primero con valor vacío y luego con el nuevo calor:[Service] ExecStart = ExecStart = /usr/sbin/xxxx -p
unidad.wants
, que contiene enlaces simbólicos a unidades de las que depende opcionalmente la unidad.unidad.requires
, que contiene enlaces simbólicos a unidades de las que depende forzosamente la unidad.
Por tanto, la configuración de la unidad que procesa systemd, procede de diversas fuentes y, si presenta distintas, a priori es posible que no tengamos muy claro cuál es el valor de un determinada directiva de configuración. Para asegurarnos de cuál es la configuración final podemos optar por:
$ systemctl cat ssh.service
que mostrará las directivas contenidas en todos los archivos involucrados en la configuración del servicio, indicando a qué archivo pertenece cada una, o bien:
$ systemctl show ssh.service
que nos devolverá la configuración resultante para el servicio ssh que incluye
también las directivas que no se han escrito pero poseen valor predeterminado.
Como es larga y puede que nos interese sólo una directiva en particular, podemos
añadir la opción -p
:
$ systemctl show -p "Wants" ssh.service
Wants=systemd-journald.socket systemd-journald-dev-log.socket system.slice
Nota
Sabiendo cuál es la estructura de archivos, podemos crear y editar
archivos a mano, pero para ayudarnos en la labor existe systemctl edit
.
4.1.2.5.3. Archivos de unidad¶
4.1.2.5.3.1. Descripción¶
Nota
El epígrafe es un descripción muy somera. Para una en mayor profundidad puede consultarse este artículo en inglés.
Los archivos de configuración de las unidades son un conjunto de parejas parámetro-valor agrupadas en distintas secciones:
[Seccion1]
Parametro1=Valor1
# [... otras directivas de esta sección ...]
[Sección2]
Parametro2=Valoe2
# [... otras directivas de esta sección ...]
Las secciones[3] posibles son:
- [Unit]
Es una sección para describir la propia unidad y su relación con las restantes. Suele situarse al principio del archivo. Algunos de las directivas que se pueden definir en ella son:
- Description
Permite describir brevemente para qué sirve la unidad. Esta descripción, por ejemplo, es la que aparece para cada unidad al ejecutar:
$ systemctl list-units
- Documentation
Permite indicar URIs donde encontrar información sobre el servicio relacionado con la unidad.
- Wants
Lista otras unidades necesarias para el servicio, aunque no indispensables. Cumple la misma función que el directorio
unidad.wants
.- Requires
Lista otras unidades indispensables para el servicio. Si alguna de ellas falla, esta unidad también lo hará. Cumple la misma función que el directorio
unidad.requires
- After
Lista las unidades que deberán estar cargadas cuando se lanza la unidad. Sólo implica orden y no requisito.
- Before
Lista las unidades que requiren cargada la unidad representada por el archivo cuando sean lanzadas.
- Condition*
Familia de directivas que permite indicar condiciones que deben cumplirse para lanzar la unidad. Dependiendo de qué se compruebe, así es el hombre exacto de la directiva. Por ejemplo, ConditionPathExists comprueba si existe la ruta que se indica como valor. Para saber el nombre del resto de directivas de esta familia puede consultarse:
$ man systemd.unit
- [Install]
Contiene directivas relacionadas con acciones que deben realizarse al habilitar o deshabilitar la unidad. Suele incluirse al final del archivo. Algunas directivas interesantes son:
- WantedBy
Permite indicar las unidades que requieren la desarrollada en el archivo. Que una unidad aparezca aquí (llamémosla otraunidad):
[Install] WantedBy=otraunidad
implica que, al habilitarse la unidad del archivo, se creará en el directorio
/etc/systemd/system/otraunidad.wantsi/
un enlace simbólico a la unidad del archivo, a fin de que se registre la dependencia y Systemd la conozca al arrancar los servicios.Esta directiva es la complementaria a Wants de la sección Unit, de manera que esta directiva en el archivo unidad provoca el mismo efecto que esto otro en el archivo otraunidad:
[Unit] Wants=unidad
En cambio, la primera directiva permite mayor versatilidad. Por ejemplo, ssh.service es un servicio que se levanta en el modo multi-user.target El problema es que muchos otros servicios también se levantan en este modo (un servidor FTP o un web, por ejemplo). De la primera forma, no hay más que individualmente en la unidad de cada servicio indicar la dependencia de multi-user.target. En cambio, de la segunda forma, deberíamos tener presentes todos esos servicios al escribir la directiva Wants= en la unidad de multi-user.target.
- RequiredBy
Análoga a WantedBy, pero el requisito es indispensable.
- Alias
Permite indicar un nombre alternativo para el servicio.
- [Service]
Es una sección que incluye directivas exclusivas de unidades que son servicios. Permite muchas directivas:
- Type
El tipo de servicio. Son diversos. Consúltese la página recomendada para más información.
- EnvironmentFile
Indica un archivo que define variables que pueden usarse en las directivas de esta sección. Consúltese el ejemplo posterior.
- ExecStart
Orden que arranca el servicio.
- ExecStartPre
Expresa comandos que deben realizarse antes de la orden que arranca el servicio.
- ExecStartPost
Expresa comandos que deben ejecutarse tras haber arrancado el servicio.
- ExecStop
Orden para parar el servicio. Si no se indica ninguna, lo que se hace es matar el proceso al parar el servicio.
- ExecStopPost
Expresa comandos a ejecutar después de parar el servicio.
- ExecReload
Orden que permite recargar la configuración.
- Restart
Expresa la circunstancia bajo la cual se reiniciará el servicio. Hay varias distintas.
- TimeoutSec
Temporización en segundos después de la cual se marcará como fallado el arranque de un servicio o se forzará su parada.
- [Socket]
Directivas para unidades socket
- [Mount]
Directivas de unidades mount que gestionan puntos de montaje. Estas unidades (y las citadas a continuación= cumplen la función del archivo tradicional
/etc/fstab
. No obstante, systemd tiene un traductor que al vuelo traduce el contenido de este archivo a estas unidades, por lo que es perfectamente funcional seguir usando este archivo.- [Automount]
Directivas para las unidades automount que permiten montar automáticamente durante el arranque los dispositivos expresados en unidades mount.
- [Swap]
Directivas para unidades swap que permiten configurar la memoria de intercambio. Pero esto también sigue siendo posible a través del archivo
/etc/fstab
.- [Path]
Directivas para unidades path que sirven para definir rutas que se desean monitorizar mediante systemd. Puede consultar este enlace <http://www.ocsmag.com/2015/09/02/monitoring-file-access-for-dummies/> para ver cómo se definen y funcionan.
- [Timer]
Directivas para unidades timer cuya utilidad es la misma que la de los demonios cron y at. Véase Planificación con SystemD.
4.1.2.5.3.2. Análisis¶
Expuesto todo lo necesario para manipular de forma muy simple la gestión a
través de systemd, lo más adecuado es analizar en profundidad un servicio.
Tomemos a este efecto ssh.service
. El archivo de unidad proporcionado
por el paquete openssh-server se encuentra en /lib/systemd/system
y es
el siguiente:
1[Unit]
2Description=OpenBSD Secure Shell server
3After=network.target auditd.service
4ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
5
6[Service]
7EnvironmentFile=-/etc/default/ssh
8ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
9ExecReload=/bin/kill -HUP $MAINPID
10KillMode=process
11Restart=on-failure
12RestartPreventExitStatus=255
13Type=notify
14
15[Install]
16WantedBy=multi-user.target
17Alias=sshd.service
En la sección [Unit]
vemos la directiva Description
, que
describe qué servicio gestiona la unidad (OpenBSD Secure Shell server) y que
aparece regularmente en las salidas de systemctl. Por ejemplo:
$ systemctl status ssh.service
● ssh.service - OpenBSD Secure Shell server
[...]
La directiva After
obliga a que esta unidad levante el servicio después
de que se hayan activado por completo las unidades network.target
y
auditd.service
. Además, se incluye con la directiva
ConditionPathExists
para que el servicio no arranque en caso de que se
haya creado el archivo /etc/ssh/sshd_not_to_be_run
.
En la sección [Service]
encontramos la directiva EnvironmentFile
que expresa un archivo en que se definen variables de ambiente: /etC/default/ssh
:
# Default settings for openssh-server. This file is sourced by /bin/sh from
# /etc/init.d/ssh.
# Options to pass to sshd
SSHD_OPTS=
La ubicación del archivo no es caprichosa. Tradicionalmente con SystemV, los
archivos de configuración para los scripts de arranque los almacenaba
Debian bajo /etc/default
. Estos son archivos en que se incluyen
variables de entorno que tales scripts utilizan. Una variable muy comúnmente
usada es la que define las opciones con las que arrancará el ejecutable que
proporciona el servicio, como es el caso del ejemplo (variable
$SSHD_OPTS que se usa luego en la directiva ExecStart
). Con
systemd se puede mantener esta filosofía gracias a la existencia de la
directiva EnvironmentFile
.
Por último, está la sección [Install]
que se aplica al habilitar o
deshabilitar la unidad. Contiene dos directivas:
WantedBy=multi-user.target
que indica que el modo de operación multi-user implica arrancar el servidor SSH y:
Alias=sshd.service
que provoca que el servicio también pueda llamarse sshd.service
. Estas
dos directivas provocan cambios en el sistema al habilitarse la unidad. La
primera de las directivas provoca que aparezca un enlace simbólico bajo
/etc/systemd/system/multi-user.target
:
$ readlink /etc/systemd/system/multi-user.target.wants/ssh.service
/lib/systemd/system/ssh.service
La segunda que en /etc/systemd/system
aparezca un enlace simbólico con
nombre sshd.service
que apunte hacia ssh.service
:
$ readlink /etc/systemd/system/sshd.service
/lib/systemd/system/ssh.service
De hecho, si deshabilitamos la unidad veremos que tales enlaces simbólicos desaparacen.
4.1.2.5.3.3. Edición¶
Advertencia
Este apartado se refiere únicamente a alterar la configuración con
la que systemd lanza el servicio. Cada servicio, a su vez, tendrá muy
probablemente un archivo (o varios) de configuración particular (p.e.
ssh tiene /etc/ssh/sshd_config
). Si lo que se pretende
es alterar esta configuración, basta con alterar tal archivo y reiniciar el
servicio:
# systemctl reload-or-restart ssh.service
Si pretendemos modificar la configuración de arranque de un servicio, podemos optar por lo siguiente:
Reescribir por completo el archivo original dentro de
/etc/systemd/system/
, para lo cual em principio deberíamos hacer algo así:# cp /lib/systemd/system/ssh.service /etc/systemd/system # vim /etc/systemd/system/ssh.service
Sin embargo, el propio systemctl proporciona una herramienta que automatiza esto:
# systemctl edit --full ssh.service
que se encargará de tomar una copia del contenido original de la unidad (el situado dentro de
/lib/systemd/system
) y permitir su edición con el editor predefinido. El resultado se guardará dentro de/etc/systemd/system
.Redefinir sólo algunas directivas, para lo cual podríamos obrar a mano:
# mkdir -p /etc/systemd/system/ssh.service.d # cat > /etc/systemd/system/ssh.service.d/override.conf [Unit] Description=Servidor OpenSSH # systemctl stop ssh.service # systemctl daemon-reload # systemctl start ssh.service
que requiere también para el servicio, hacerle saber a systemd que hemos cambiado la unidad, e iniciarlo otra vez. En vez de todo ello, es infinitamente más cómodo (y seguro) utilizar systemctl:
# systemctl edit ssh.service
Advertencia
Al editar observe que aparece comentada la configuración del archivo con la configuración completa. No descomente y modifique, porque no funcionará: observe que todas esas líneas están la leyenda "Lines below this comment will be discarded".
Es posible conocer los archivos que parchean configuraciones del archivos principales:
$ systemd-delta --type extended
Notas al pie