Niveles de ejecución y targets de systemd
Introducción
Los niveles de ejecución (runlevels) definen el estado operativo del sistema: qué servicios están activos, si hay interfaz gráfica, si se admiten múltiples usuarios, etc. En los sistemas modernos con systemd los runlevels clásicos han sido reemplazados por targets, que ofrecen mayor flexibilidad.
Runlevels clásicos (SysV init)
El sistema SysV tradicional definía 7 niveles de ejecución (0-6):
Runlevel Descripción
──────── ──────────────────────────────────────────
0 Apagado del sistema (halt)
1 Modo monousuario (single user, sin red, solo root)
2 Multiusuario sin red (Debian/Ubuntu lo usa como multiusuario normal)
3 Multiusuario con red, sin entorno gráfico (Red Hat / Fedora)
4 Sin uso estándar (reservado para uso personalizado)
5 Multiusuario con red y entorno gráfico
6 Reinicio del sistema (reboot)
La definición exacta de los runlevels 2, 3 y 4 variaba según la distribución. En Debian/Ubuntu los niveles 2-5 eran equivalentes (multiusuario con gráficos). En Red Hat/Fedora el nivel 3 era sin gráficos y el 5 con gráficos.
Targets de systemd
systemd reemplaza los runlevels por targets, que son unidades (.target) que
agrupan servicios con dependencias entre sí. Son más expresivos y flexibles que los runlevels.
Equivalencias entre runlevels y targets:
Runlevel Target systemd Descripción
──────── ─────────────────────────── ────────────────────────────
0 poweroff.target Apagar el sistema
1 rescue.target Modo monousuario / rescate
2, 3, 4 multi-user.target Multiusuario, sin gráficos
5 graphical.target Multiusuario con entorno gráfico
6 reboot.target Reiniciar el sistema
Los symlinks de compatibilidad existen en /lib/systemd/system/runlevel*.target.
Consultar y cambiar el target
Ver el target por defecto:
$ systemctl get-default
graphical.target
Cambiar el target por defecto (persiste tras reinicio):
# systemctl set-default multi-user.target # sin entorno gráfico por defecto
# systemctl set-default graphical.target # con entorno gráfico por defecto
Internamente crea o modifica el enlace simbólico
/etc/systemd/system/default.target apuntando al target elegido.
Cambiar el target en la sesión actual (sin reiniciar):
# systemctl isolate multi-user.target # cambia al target ahora
# systemctl isolate rescue.target # entra en modo rescate ahora
# systemctl isolate graphical.target # activa el entorno gráfico ahora
isolate activa el target indicado y detiene todos los servicios que no pertenecen a él. Solo funciona
con targets que tienen AllowIsolate=yes en su definición.
Targets especiales
emergency.target ← mínimo absoluto: solo shell root, sin servicios, sin montajes
rescue.target ← monousuario: shell root + sistemas de ficheros montados
multi-user.target ← multiusuario completo sin gráficos
graphical.target ← multiusuario con entorno gráfico
network.target ← la red está disponible
sysinit.target ← inicialización básica del sistema completada
Entrar en modo de emergencia desde GRUB:
Editar la línea del kernel en GRUB y añadir:
systemd.unit=emergency.target
telinit — Compatibilidad con SysV
El comando clásico telinit N para cambiar de runlevel sigue funcionando en sistemas con systemd por
compatibilidad. Internamente se traduce al systemctl isolate correspondiente.
# telinit 3 ← equivale a: systemctl isolate multi-user.target
# telinit 0 ← equivale a: systemctl poweroff
# telinit 6 ← equivale a: systemctl reboot
Cómo aplica systemd los targets
Cuando systemd activa un target, no ejecuta una lista fija de servicios — lee ficheros de unidad (.target, .service, .mount…) y resuelve un grafo de dependencias.
Fichero de unidad de un target:
Los targets se definen en /lib/systemd/system/*.target. Por ejemplo,
multi-user.target:
$ cat /lib/systemd/system/multi-user.target
[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
-
Requires=→ dependencias obligatorias: si fallabasic.target, falla este también. After=→ orden de arranque: este target arranca después de los listados.Conflicts=→ unidades incompatibles: activar este target detiene las listadas.AllowIsolate=yes→ permite usarsystemctl isolatecon este target.
Directorios .wants/ y .requires/:
Los servicios se asocian a un target mediante symlinks en los directorios
/lib/systemd/system/<target>.wants/. Cuando se activa el target, systemd carga
automáticamente todos los servicios enlazados en ese directorio.
$ ls /lib/systemd/system/multi-user.target.wants/
getty.target remote-fs.target systemd-ask-password-wall.path ...
$ ls /etc/systemd/system/multi-user.target.wants/
cron.service nginx.service ssh.service ...
Los symlinks en /lib/ son los que pone el paquete. Los de /etc/
son los que crea el administrador con systemctl enable.
Cómo un servicio declara su target:
En el fichero .service, la sección [Install] indica en qué target quiere participar el
servicio:
# /lib/systemd/system/ssh.service (fragmento)
[Unit]
Description=OpenBSD Secure Shell server
After=network.target
[Service]
ExecStart=/usr/sbin/sshd -D
[Install]
WantedBy=multi-user.target
Cuando se ejecuta systemctl enable ssh, systemd crea el symlink
/etc/systemd/system/multi-user.target.wants/ssh.service. Cuando se ejecuta systemctl disable ssh, lo elimina.
Inspeccionar las dependencias de un target:
$ systemctl list-dependencies multi-user.target
multi-user.target
● ├─cron.service
● ├─dbus.service
● ├─getty.target
● │ └─getty@tty1.service
● ├─nginx.service
● ├─ssh.service
● └─basic.target
● ├─sysinit.target
● └─...
$ systemctl list-dependencies --reverse ssh.service
ssh.service
└─multi-user.target
└─graphical.target
La opción --reverse muestra qué targets dependen del servicio dado, útil para entender en qué punto
del arranque se activa.
Ver el estado completo del arranque:
$ systemctl list-units --type=target # targets activos
$ systemctl list-units --type=target --all # todos (activos e inactivos)
$ systemctl status multi-user.target # estado detallado del target
Secuencia de targets durante un arranque normal:
local-fs-pre.target
│
local-fs.target ← sistemas de ficheros locales montados
│
swap.target ← swap activada
│
sysinit.target ← hostname, reloj, udev, selinux...
│
basic.target ← sockets, timers, paths básicos
│
multi-user.target ← servicios de red y sistema
│
graphical.target ← gestor de pantalla (si procede)
Cada target garantiza que los anteriores están listos antes de activarse, gracias a las directivas After= y Requires= encadenadas.