Comprendiendo los Targets de Systemd: Conceptos Esenciales Explicados

Comprende los targets de systemd, los targets de arranque predeterminados, las asignaciones de niveles de ejecución, el aislamiento, los targets personalizados y los comandos de solución de problemas.

Comprendiendo los Targets de Systemd: Conceptos Esenciales Explicados

Los targets de systemd son más fáciles de entender si dejas de pensar en ellos como servicios. Un servicio inicia un proceso. Un target agrupa unidades en un estado del sistema con nombre. Cuando una máquina arranca en multi-user.target, systemd no está iniciando un programa llamado "multi-user". Está intentando alcanzar un estado donde las unidades deseadas por ese target se hayan iniciado o al menos se haya intentado su inicio.

Esa distinción ayuda cuando estás depurando problemas de arranque. Si graphical.target es lento, el target en sí rara vez es el problema. Una de las unidades de pantalla, inicio de sesión, red, montaje o aplicación incluidas en ese target es lenta o está fallando. Los targets te dan el mapa.

¿Qué son los Targets de Systemd?

En el ecosistema de systemd, un target es un tipo especial de archivo de unidad (como los archivos .service o .socket) que cumple un propósito organizativo crítico. A diferencia de las unidades de servicio que definen cómo iniciar o detener un proceso específico, las unidades de target definen un estado del sistema o una colección de unidades que deben estar activas juntas. Actúan como puntos de agrupación lógica y puntos de sincronización para otras unidades de systemd.

Piensa en los targets como hitos en el viaje operativo del sistema. Cuando systemd arranca, no solo lanza una lista de servicios arbitrariamente; trabaja para alcanzar un target específico. Este target, a su vez, incorpora todos los servicios, sockets, puntos de montaje y otros targets necesarios para que ese estado se cumpla. Este enfoque basado en dependencias asegura un proceso de arranque predecible y eficiente.

Para aquellos familiarizados con sistemas init de Linux más antiguos como SysVinit, los targets de systemd son el equivalente moderno de los niveles de ejecución. Mientras que SysVinit tenía un conjunto fijo de niveles de ejecución (por ejemplo, nivel de ejecución 3 para modo texto multiusuario, nivel de ejecución 5 para modo gráfico multiusuario), los targets de systemd son más flexibles. Tienen nombre, no número, y puedes definir targets personalizados, ofreciendo mayor granularidad y extensibilidad.

Cómo Funcionan los Targets: Agrupación y Dependencias

Los targets logran su agrupación y capacidades de definición de estado a través de dependencias explícitas definidas dentro de sus archivos de unidad. Las directivas principales utilizadas para esto son Wants=, Requires=, After= y Before=.

  • Wants=: Especifica dependencias "débiles". Si target A Wants= unidad B, systemd intentará iniciar unidad B cuando target A se active. Sin embargo, target A aún se iniciará incluso si unidad B falla al iniciar. Esto se usa comúnmente para agrupar servicios relacionados que son deseables pero no estrictamente esenciales.
  • Requires=: Especifica dependencias "fuertes". Si target A Requires= unidad B, entonces unidad B debe iniciarse correctamente para que target A se active. Si unidad B falla, target A también fallará o no se iniciará. Esto se usa para dependencias críticas.
  • After=: Define una dependencia de orden. Si target A tiene After= unidad B, entonces target A solo se iniciará después de que unidad B se haya iniciado. Esto no implica una dependencia de éxito, solo de orden.
  • Before=: Lo inverso de After=. Si target A tiene Before= unidad B, entonces unidad B solo se iniciará después de que target A se haya iniciado.
  • Conflicts=: Asegura que ciertas unidades no estén activas simultáneamente. Si target A Conflicts= unidad B, entonces activar target A detendrá unidad B si se está ejecutando, y viceversa.

Estas directivas permiten que los targets actúen como orquestadores robustos, incorporando servicios y otros targets según sea necesario, y definiendo el orden en que deben iniciarse. Por ejemplo, multi-user.target típicamente Wants= network.target y varios otros servicios, asegurando que estén activos cuando el sistema alcance un estado multiusuario.

Puedes inspeccionar el contenido de un archivo de unidad de target para ver sus dependencias:

systemctl cat multi-user.target

Este comando mostrará el contenido del archivo de unidad multi-user.target, mostrando su Description, Documentation y, crucialmente, sus directivas Wants=, Requires=, After= y otras que definen lo que constituye el estado multiusuario.

Targets Comunes de Systemd Explicados

Systemd proporciona una variedad de targets predefinidos, cada uno correspondiente a un estado o funcionalidad específica del sistema. Comprenderlos es crucial para la administración del sistema:

  • default.target: Este es el target más importante ya que define el estado predeterminado en el que arrancará tu sistema. Generalmente es un enlace simbólico a graphical.target (para escritorios) o multi-user.target (para servidores).
  • graphical.target: Este target se usa típicamente para sistemas con un entorno de escritorio gráfico. Incorpora multi-user.target y luego agrega servicios necesarios para el gestor de inicio de sesión gráfico y el servidor de visualización (por ejemplo, GDM, LightDM, Xorg, Wayland).
  • multi-user.target: Este es el estado estándar para sistemas multiusuario sin interfaz gráfica. Es común para servidores y proporciona todos los servicios necesarios para el acceso por línea de comandos, redes y la mayoría de las operaciones de demonios.
  • basic.target: Un estado mínimo que incluye servicios básicos del sistema necesarios para operaciones fundamentales, pero antes de multi-user.target. Típicamente incorpora sysinit.target y otros servicios esenciales.
  • sysinit.target: Este target se alcanza muy temprano en el proceso de arranque. Es responsable de tareas de inicialización central del sistema como montar sistemas de archivos /etc/fstab (excluyendo remotos), configurar swap y otras inicializaciones relacionadas con hardware.
  • local-fs.target: Asegura que todos los sistemas de archivos locales especificados en /etc/fstab estén montados.
  • remote-fs.target: Asegura que todos los sistemas de archivos remotos (por ejemplo, NFS, CIFS) especificados en /etc/fstab estén montados.
  • network.target: Indica que la conectividad de red básica está disponible (por ejemplo, las interfaces de red están activas). No garantiza conectividad total a Internet o asignación de dirección IP.
  • network-online.target: Un punto de sincronización para servicios que quieren esperar hasta que el gestor de red considere que la red está en línea. No prueba que Internet, DNS o una API remota sean accesibles, y solo funciona como se espera cuando el servicio wait-online relevante está habilitado.
  • rescue.target: Proporciona un shell de un solo usuario con servicios mínimos en ejecución y sistemas de archivos locales montados. Útil para recuperación del sistema y solución de problemas.
  • emergency.target: Un entorno aún más mínimo que rescue.target. Proporciona un shell en el sistema de archivos raíz, que típicamente está montado como solo lectura. No se inician otros servicios. Para situaciones de emergencia críticas.
  • poweroff.target, reboot.target, halt.target: Estos targets se utilizan para apagar, reiniciar o detener el sistema, respectivamente. Cuando se activan, detienen la mayoría de los servicios y preparan el sistema para el estado de energía deseado.

Gestión de Targets de Systemd

La interacción con los targets de systemd implica principalmente la utilidad de línea de comandos systemctl.

Visualización de Targets Activos y Predeterminados

Para ver en qué target se está ejecutando actualmente tu sistema:

systemctl get-default

Para listar todas las unidades de target cargadas actualmente:

systemctl list-units --type=target

Este comando muestra targets activos, cargados y estáticos, junto con sus descripciones.

Cambio del Target de Arranque Predeterminado

Puedes cambiar el target en el que arranca tu sistema de forma predeterminada. Por ejemplo, para establecer multi-user.target como predeterminado:

sudo systemctl set-default multi-user.target

Para revertir a graphical.target:

sudo systemctl set-default graphical.target

Este comando crea un enlace simbólico desde /etc/systemd/system/default.target al archivo de target deseado.

Arranque en un Target Diferente Temporalmente

A veces necesitas arrancar en un target específico solo una vez (por ejemplo, para solucionar problemas). Puedes lograr esto agregando un parámetro de kernel durante el arranque. Cuando aparezca el menú de arranque GRUB, edita la entrada de arranque (generalmente presionando e) y agrega systemd.unit=nombre_del_target.target a la línea de comandos del kernel.

Por ejemplo, para arrancar en modo rescate:

systemd.unit=rescue.target

Cambio de Targets Durante la Ejecución

Puedes cambiar a un target diferente mientras el sistema está en ejecución usando el comando systemctl isolate. Este comando detendrá todos los servicios no requeridos por el nuevo target e iniciará todos los servicios requeridos por él.

Advertencia: Usar systemctl isolate puede interrumpir la operación de tu sistema, especialmente si cambias a un target de nivel mucho más bajo como multi-user.target desde graphical.target en una máquina de escritorio. Úsalo con precaución.

Para cambiar de graphical.target a multi-user.target:

sudo systemctl isolate multi-user.target

Para volver a graphical.target (asumiendo que era el estado anterior):

sudo systemctl isolate graphical.target

Creación de Targets Personalizados

Si bien systemd proporciona muchos targets útiles, es posible que encuentres situaciones donde crear un target personalizado sea beneficioso. Esto es particularmente cierto para implementaciones de aplicaciones complejas donde necesitas agrupar varios servicios que siempre deben iniciarse y detenerse juntos, o para definir un entorno específico para tu aplicación.

Para crear un target personalizado:

  1. Crea un archivo .target: Colócalo en /etc/systemd/system/. Por ejemplo, mi-aplicacion.target.
    # /etc/systemd/system/mi-aplicacion.target
    [Unit]
    Description=Target de Mi Aplicación Personalizada
    Wants=mi-base-de-datos.service mi-servidor-web.service
    After=mi-base-de-datos.service mi-servidor-web.service
    
    • Description: Una descripción legible por humanos.
    • Wants=: Lista los servicios u otros targets que este target debe incorporar.
    • After=: Define el orden. El target se iniciará después de estas unidades.
  2. Crea los servicios: Asegúrate de que mi-base-de-datos.service y mi-servidor-web.service (o los servicios que listes) existan y estén configurados correctamente.
  3. Recarga systemd: Informa a systemd sobre el nuevo archivo de unidad.
    
    

sudo systemctl daemon-reload 4. **Habilita e Inicia**: Ahora puedes habilitar e iniciar tu target personalizado, que a su vez iniciará sus servicios deseados. bash sudo systemctl enable mi-aplicacion.target sudo systemctl start mi-aplicacion.target ```

Esto te permite gestionar un grupo de servicios relacionados como una sola unidad lógica, simplificando implementaciones complejas de aplicaciones.

Niveles de Ejecución y Targets Sin Rodeos

Si vienes de SysVinit, la asignación aproximada es:

Idea de nivel de ejecución antiguo Target común de systemd
Modo de reparación de un solo usuario rescue.target
Modo texto multiusuario multi-user.target
Modo gráfico multiusuario graphical.target
Reinicio reboot.target
Apagado poweroff.target

Trata eso como una ayuda de traducción, no como un modelo perfecto. Los niveles de ejecución de SysV eran un pequeño conjunto fijo de estados numerados. Los targets de systemd son unidades con nombre con dependencias, y puede haber muchos de ellos. Un paquete puede instalar su propio target. Puedes crear uno para un flujo de trabajo de implementación. Algunos targets están destinados a ser aislados; otros son solo puntos de agrupación utilizados durante el arranque.

Puedes ver qué targets permiten aislamiento con:

systemctl show multi-user.target -p AllowIsolate
systemctl show basic.target -p AllowIsolate

Esto importa porque systemctl isolate no es un comando inofensivo de "cambiar vista". Detiene unidades que no forman parte de la transacción del nuevo target. En un escritorio, aislar multi-user.target generalmente detendrá la sesión gráfica. En un servidor remoto, aislar el target incorrecto puede detener los servicios de red o inicio de sesión y bloquearte.

Cómo los Servicios se Convierten en Parte de un Target

La mayoría de las membresías de target del día a día provienen de la sección [Install] de un archivo de servicio:

[Install]
WantedBy=multi-user.target

Cuando ejecutas:

sudo systemctl enable mi-app.service

systemd crea un enlace simbólico bajo un directorio como:

/etc/systemd/system/multi-user.target.wants/mi-app.service

Ese enlace simbólico es lo que hace que multi-user.target quiera el servicio durante el arranque. El archivo de servicio puede existir y ser perfectamente válido sin estar habilitado. En ese caso, iniciar multi-user.target no lo incorporará automáticamente.

Por eso systemctl start mi-app.service y systemctl enable mi-app.service resuelven problemas diferentes. start lo ejecuta ahora. enable lo conecta a un target de arranque futuro. enable --now hace ambas cosas.

Para verificar si un servicio está habilitado para un target:

systemctl is-enabled mi-app.service
systemctl list-dependencies multi-user.target | grep mi-app

Si un servicio se inicia manualmente pero no al arrancar, esto es una de las primeras cosas a verificar.

Un Pequeño Target Personalizado Que Realmente es Útil

Los targets personalizados son más útiles cuando le dan a los operadores un solo comando para un grupo de unidades relacionadas. Imagina una pila de aplicaciones simple:

app-api.service
app-worker.service
app-scheduler.service

Puedes crear:

# /etc/systemd/system/app-stack.target
[Unit]
Description=Pila de aplicaciones
Wants=app-api.service app-worker.service app-scheduler.service
After=network-online.target
Wants=network-online.target
AllowIsolate=no

Luego agrega cada servicio al target:

[Install]
WantedBy=app-stack.target

Después de daemon-reload, habilita los servicios o el target dependiendo del comportamiento que desees:

sudo systemctl daemon-reload
sudo systemctl enable app-api.service app-worker.service app-scheduler.service
sudo systemctl start app-stack.target

Esto te da una agrupación legible sin pretender que el target sea un supervisor de procesos. Si app-worker.service falla, inspecciona ese servicio. El target es solo el punto de agrupación.

Si deseas que detener el target detenga todos los servicios de la pila, agrega PartOf=app-stack.target a cada servicio:

[Unit]
PartOf=app-stack.target

Ahora systemctl stop app-stack.target se propaga a los servicios miembros. Eso es a menudo la pieza faltante en ejemplos de targets personalizados.

Solución de Problemas con Targets

Los targets también son invaluables para solucionar problemas de arranque o fallos de servicios:

  • Identificar dependencias: Si un servicio falla al iniciar, inspeccionar el target al que pertenece puede revelar dependencias faltantes o fallidas. Usa systemctl status <nombre_del_servicio> y systemctl list-dependencies <nombre_del_target>.
  • Arrancar en targets mínimos: Si tu sistema falla al arrancar en graphical.target o multi-user.target, intenta arrancar en rescue.target o emergency.target usando el método de parámetro del kernel. Esto proporciona un entorno mínimo donde puedes diagnosticar problemas sin la complejidad de muchos servicios en ejecución.
  • Verificar registros: Después de intentar iniciar un target o un servicio, siempre verifica los registros de journalctl para errores:
    journalctl -b -u <nombre_del_target_o_servicio>
    

Mejores Prácticas y Consejos

  • Usa network-online.target con cuidado: Si tu servicio necesita configuración de red antes del inicio, combina After=network-online.target con Wants=network-online.target y confirma que la unidad wait-online apropiada esté habilitada. Aún así, mantén la lógica de reintento en la aplicación para dependencias remotas.
  • Comprende el orden de arranque: Familiarízate con el flujo general desde sysinit.target hasta basic.target, luego multi-user.target/graphical.target. Esto ayuda en la depuración de servicios que fallan temprano en el proceso de arranque.
  • Ten cuidado con default.target: Cambiar default.target puede alterar significativamente el comportamiento de arranque de tu sistema. Siempre prueba configuraciones personalizadas en un entorno que no sea de producción primero.
  • Usa Wants= para dependencias no críticas: Para servicios que son útiles pero no estrictamente necesarios para que un target se considere "activo", usa Wants= en lugar de Requires=. Esto evita que un solo fallo de servicio opcional se propague e impida que todo el target se active.

El Modelo Mental a Mantener

Un target es un estado con nombre, no un demonio. default.target decide el destino de arranque normal. multi-user.target es el estado habitual del servidor. graphical.target agrega la pila de visualización. rescue.target y emergency.target son herramientas de reparación. Los targets personalizados son herramientas de agrupación cuando hacen las operaciones más claras.

Cuando algo relacionado con un target se rompe, evita culpar al target primero. Pregunta qué unidad fue incorporada, qué regla de orden la retrasó y qué dependencia falló. systemctl cat, systemctl list-dependencies, systemctl show y journalctl -b generalmente responderán esas preguntas más rápido que leer diagramas de arranque genéricos.