La lección anterior terminó con una limitación clara de la shell: un script suelto no es un sistema. Alguien tiene que arrancar meteo-api cuando la máquina enciende, esperar a que /var/lib/meteora esté montado, reiniciarlo si cae, ejecutar el agregador cada hora aunque el servidor estuviera apagado a las 03:00, aplicarles los límites y el endurecimiento del módulo 5, y recoger sus registros. Ese alguien es el gestor de servicios: el proceso con PID 1 que el núcleo arranca al final del arranque y que no muere hasta que la máquina se apaga.
Esta lección tiene dos mitades. En la primera seguimos el encendido de meteo-01 fase por fase, desde que el firmware toma el control hasta que aparece el PID 1, y aprendemos qué se puede observar y tocar en cada fase —porque la mitad de las incidencias graves de arranque se resuelven sabiendo pasar un parámetro al núcleo desde GRUB—. En la segunda desmontamos systemd: su modelo de unidades, la anatomía completa de la unidad de meteo-api, las dependencias, los temporizadores que sustituyen a cron, y el guion de diagnóstico de "mi servicio no arranca", que es una de las cosas que más veces harás en tu vida profesional.
La monitorización de rendimiento es la lección siguiente; aquí nos ocupamos de qué corre, cuándo y bajo qué reglas.
Contenido
- El arranque de
meteo-01, fase a fase - Qué problema resolvió systemd
- El modelo de unidades
- Anatomía de un fichero de unidad:
meteo-apicompleto - Tipos de servicio y cómo elegir bien
- Dependencias frente a orden
- Objetivos y niveles de ejecución
- El manejo diario con
systemctl - Políticas de reinicio y el bucle que oculta un fallo
- Temporizadores frente a
cron - Activación por socket y por ruta
- Unidades de usuario y
loginctl - Análisis y depuración del arranque
- Apagado ordenado:
SIGTERM,SIGKILLyTimeoutStopSec
El arranque de meteo-01, fase a fase
graph TD
A["Firmware UEFI<br/>POST + inicialización de hardware"] --> B["Lee la ESP (FAT32)<br/>y ejecuta shimx64.efi / grubx64.efi"]
B --> C["GRUB: menú, grub.cfg<br/>carga vmlinuz + initrd"]
C --> D["Núcleo: descomprime, monta initramfs<br/>como raíz temporal en RAM"]
D --> E["initramfs: carga módulos<br/>(RAID, LUKS, LVM), ensambla /dev/md0"]
E --> F["switch_root a la raíz real<br/>y execve de /sbin/init"]
F --> G["systemd, PID 1<br/>alcanza default.target"]
G --> H["meteo-api escucha en :443"]
Fase 1: firmware. Al pulsar el botón, la CPU empieza a ejecutar código del firmware de la placa. Hay dos mundos:
| BIOS heredada | UEFI | |
|---|---|---|
| Dónde está el arranque | MBR: 446 bytes en el sector 0 | Ficheros .efi en la ESP, una partición FAT32 |
| Tamaño del código inicial | Ridículo: cabe una carga en cadena | Un ejecutable completo, con controladores |
| Tabla de particiones | MBR (máx. 2 TB, 4 primarias) | GPT (sin esos límites, con CRC) |
| Arranque seguro | No existe | Secure Boot: firmas verificadas por el firmware |
| Diagnóstico | Casi nulo | Shell EFI, efibootmgr, variables NVRAM |
meteo-01 arranca por UEFI. Su ESP está montada en /boot/efi y contiene EFI/debian/grubx64.efi y el shimx64.efi firmado por Microsoft que hace posible Secure Boot: el firmware verifica la firma de shim, shim la de GRUB, GRUB la del núcleo y el núcleo la de los módulos. La cadena existe para impedir un bootkit, código malicioso que se ejecuta antes que el sistema operativo y que por tanto ningún antivirus del sistema puede ver. Su precio práctico es que un módulo compilado a mano (por ejemplo un controlador propietario) no cargará sin firmarlo.
[ -d /sys/firmware/efi ] && echo "Arranque UEFI" || echo "Arranque BIOS heredada"
efibootmgr -v | head -3 # entradas de arranque en la NVRAM
mokutil --sb-state # SecureBoot enabledQué demuestran. El núcleo solo crea /sys/firmware/efi si arrancó por UEFI: es la comprobación canónica. efibootmgr lee las variables NVRAM donde el firmware guarda el orden de arranque, y permite añadir o reordenar entradas sin entrar en la pantalla de configuración. mokutil informa del estado de Secure Boot.
Fase 2: gestor de arranque. GRUB lee /boot/grub/grub.cfg —fichero generado, nunca editado a mano: se produce con update-grub a partir de /etc/default/grub y /etc/grub.d/— y presenta el menú. Cada entrada indica un núcleo, un initrd y una línea de parámetros:
Pulsando e sobre la entrada puedes editar esa línea para un solo arranque, sin tocar el disco. Es la herramienta de rescate más importante que existe:
| Parámetro | Para qué |
|---|---|
single o systemd.unit=rescue.target |
Modo mínimo con shell de root, sin servicios |
systemd.unit=emergency.target |
Aún más mínimo: solo la raíz montada en solo lectura |
Quitar quiet y añadir debug |
Ver todos los mensajes del núcleo en pantalla |
init=/bin/bash |
Saltarse systemd por completo (raíz en solo lectura; mount -o remount,rw /) |
nomodeset |
Arrancar sin el controlador gráfico que cuelga la máquina |
systemd.mask=meteo-api.service |
Arrancar sin un servicio que impide el arranque |
Fase 3: núcleo e initramfs. GRUB carga en memoria el núcleo comprimido y el initrd, y salta al núcleo, que se descomprime, inicializa la gestión de memoria del módulo 2 y monta el initramfs como raíz temporal en RAM.
¿Por qué existe el initramfs? Por un problema de huevo y gallina. La raíz real de meteo-01 está en /dev/md0, un RAID 1 sobre ext4. Para montarla hace falta el módulo raid1 y el de ext4… que están dentro de esa misma raíz. El initramfs rompe el círculo: es un cpio comprimido con los módulos imprescindibles y un /init mínimo que carga los controladores, ensambla el RAID, abre el LUKS si lo hay, activa los volúmenes LVM y solo entonces monta la raíz real. Después ejecuta switch_root, que sustituye la raíz temporal por la real, libera la RAM del initramfs y hace execve de /sbin/init —un enlace a /lib/systemd/systemd— con PID 1.
lsinitramfs /boot/initrd.img-$(uname -r) | grep -E 'raid1|ext4' # qué módulos lleva
update-initramfs -u -k all # regenerarlo tras un cambio
dmesg -T | head -40 # el diario del núcleo
dmesg -T --level=err,warn # solo errores y avisosQué hacen y por qué importan. Si añades un disco o cambias el esquema de almacenamiento y olvidas update-initramfs, la máquina arrancará hasta el initramfs y se quedará ahí con un prompt (initramfs) porque no encuentra la raíz: es uno de los ladrillazos más frecuentes. Y dmesg es el búfer circular del núcleo, donde queda todo lo ocurrido desde la primera instrucción: detección de hardware, errores de disco, el OOM killer de 02-04, los mensajes de RAID. -T traduce las marcas de tiempo relativas a fechas legibles.
Fase 4: PID 1. El PID 1 es especial por tres motivos que vienen de 02-01: no se le pueden aplicar las señales por defecto (el núcleo ignora SIGTERM y SIGKILL hacia él, para que nadie pueda matarlo por accidente), adopta a los huérfanos y recoge sus estados de salida evitando los zombis, y si muere, el núcleo entra en pánico. Todo lo demás en el sistema desciende de él.
Qué problema resolvió systemd
Antes de systemd, el arranque lo gobernaba SysV init: guiones de shell en /etc/init.d/ que se ejecutaban en orden alfabético desde /etc/rc3.d/ (S01, S02, S03…), uno detrás de otro, cada uno arrancando su demonio con un start-stop-daemon. El modelo tenía cinco problemas graves:
| Problema de SysV init | Respuesta de systemd |
|---|---|
Ejecución secuencial: si S20 tarda 30 s, todo lo demás espera |
Paralelismo real: solo se serializa lo que declara depender |
| Las dependencias se codificaban en el número del enlace | Dependencias declaradas (After=, Requires=) y resueltas por un grafo |
| Todo se arranca siempre, se use o no | Activación bajo demanda por socket, ruta o dispositivo |
| Si el demonio moría, nadie se enteraba | Supervisión: systemd es el padre y reinicia según política |
Un demonio podía dejar procesos sueltos que stop no mataba |
Cada servicio vive en su cgroup: se para el grupo entero |
Ese último punto es el más subestimado y conecta directamente con 06-02. Un guion SysV rastreaba a su demonio por un fichero .pid; si el proceso se demonizaba mal, cambiaba de PID o lanzaba hijos, el stop mataba el PID equivocado y dejaba procesos huérfanos consumiendo recursos. systemd pone cada servicio en un grupo de control propio, así que la pertenencia es una propiedad del núcleo, no una suposición: parar el servicio significa señalar a todo el cgroup, y las cuentas de CPU, memoria y E/S del servicio son exactas.
systemctl status meteo-api.service | tail -6
# CGroup: /system.slice/meteo-api.service
# ├─1834 /usr/local/bin/meteo-api --config /etc/meteora/meteora.conf
# └─1847 /usr/local/bin/meteo-api --worker 1
systemd-cgls /system.slice | head -20 # el árbol de cgroups por servicioQué demuestra. El campo CGroup de status lista todos los procesos del servicio, incluidos los que él haya lanzado. Ningún proceso se le escapa a systemd, porque el cgroup lo asigna el núcleo en el fork y se hereda.
El modelo de unidades
Todo en systemd es una unidad: un fichero de texto en formato INI que describe algo que se gestiona. Los tipos que necesitas conocer:
| Tipo | Extensión | Qué describe | Ejemplo en meteo-01 |
|---|---|---|---|
| Servicio | .service |
Un proceso supervisado | meteo-api.service |
| Socket | .socket |
Un punto de escucha que puede activar un servicio | meteo-api.socket |
| Objetivo | .target |
Un punto de sincronización, un "estado" | multi-user.target |
| Temporizador | .timer |
Ejecución programada de otra unidad | agregador.timer |
| Montaje | .mount |
Un punto de montaje (generado desde /etc/fstab) |
var-lib-meteora.mount |
| Ruta | .path |
Vigila un fichero o directorio | lecturas-nuevas.path |
| Porción | .slice |
Un nodo del árbol de cgroups para agrupar límites | meteora.slice |
Dónde viven, por orden de prioridad creciente:
| Directorio | Quién lo escribe | Se pierde al actualizar |
|---|---|---|
/lib/systemd/system/ |
El paquete de la distribución | Sí: nunca edites aquí |
/etc/systemd/system/ |
El administrador | No: es tu territorio |
/run/systemd/system/ |
Unidades transitorias en memoria | Sí, al reiniciar |
Un fichero en /etc/systemd/system/meteo-api.service sustituye por completo al del paquete. Casi nunca es lo que quieres: si el paquete mejora su unidad, te quedas con la vieja. Lo correcto es un drop-in, un fragmento que se fusiona con el original:
systemctl edit meteo-api.service # crea .../meteo-api.service.d/override.conf
systemctl cat meteo-api.service # muestra el original Y todos los drop-ins aplicados
systemctl edit --full meteo-api.service # copia entera a /etc (usar solo si no hay más remedio)Qué hacen. systemctl edit abre un editor sobre /etc/systemd/system/meteo-api.service.d/override.conf, y al guardar ejecuta daemon-reload automáticamente. systemctl cat es la orden que deberías usar siempre antes de tocar nada: muestra el fichero de origen y, debajo, cada drop-in con su ruta, de modo que ves la configuración efectiva y de dónde sale cada directiva.
Una trampa que hay que conocer: en un drop-in, las directivas que aceptan listas (como ExecStart o Environment) se acumulan. Para reemplazar un ExecStart hay que vaciarlo primero con una línea ExecStart= sin valor y luego poner el nuevo.
Anatomía de un fichero de unidad: meteo-api completo
# /etc/systemd/system/meteo-api.service
[Unit]
Description=API de consultas meteorológicas de Meteora
Documentation=https://docs.meteora.example/api
After=network-online.target var-lib-meteora.mount
Wants=network-online.target
RequiresMountsFor=/var/lib/meteora /var/log/meteora
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=notify
NotifyAccess=main
User=meteora
Group=meteora
ExecStartPre=/usr/local/bin/verificar-lecturas.sh -d /var/lib/meteora/lecturas
ExecStart=/usr/local/bin/meteo-api --config /etc/meteora/meteora.conf --listen 0.0.0.0:443
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s
TimeoutStartSec=60
TimeoutStopSec=30
WatchdogSec=30
# --- Endurecimiento (mecanismo explicado en 05-03) ---
NoNewPrivileges=yes
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/var/lib/meteora /var/log/meteora /run/meteora
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
LockPersonality=yes
MemoryDenyWriteExecute=yes
UMask=0027
# --- Límites de recursos (cgroups v2, de 06-02) ---
MemoryMax=2G
MemoryHigh=1500M
CPUWeight=200
IOWeight=200
TasksMax=512
[Install]
WantedBy=multi-user.targetSección por sección:
[Unit]describe la unidad y sus relaciones.Descriptiones lo que aparece ensystemctl statusy en los registros: escríbela para un humano medio dormido.After=fija orden, no dependencia.RequiresMountsFor=es la forma correcta de decir "no arranques si estas rutas no están montadas": systemd deduce solo las unidades.mountimplicadas, y es más robusto que nombrarlas a mano, porque el nombre de una unidad de montaje se codifica de forma peculiar (/var/lib/meteora→var-lib-meteora.mount).[Service]define cómo se ejecuta.ExecStartPrecorre antes y, si falla, el servicio no arranca: aquí reutilizamos el script de verificación de 07-01 como comprobación previa.ExecStartes el proceso principal, siempre con ruta absoluta (systemd no usa elPATHde tu shell).ExecReloadrecarga la configuración sin cortar las conexiones;$MAINPIDes una de las pocas variables que systemd expande.- El bloque de endurecimiento es el módulo 5 hecho directivas.
NoNewPrivilegespone el bit del núcleo que impide ganar privilegios por setuid, así que ni un binario setuid comprometido serviría de escalón.AmbientCapabilities=CAP_NET_BIND_SERVICEes lo que permite escuchar en el puerto 443 sin ser root, yCapabilityBoundingSetfija el techo: aunque el proceso quisiera otra capability, el núcleo no se la concede.ProtectSystem=strictmonta todo el sistema de ficheros en solo lectura para el servicio, yReadWritePathsabre las tres excepciones necesarias.PrivateTmple da un/tmppropio en un namespace de montaje, lo que elimina de raíz los ataques por ficheros temporales predecibles.SystemCallFilter=@system-serviceaplica un filtro seccomp que deja pasar el conjunto habitual de un servicio y bloquea el resto devolviendoEPERM.UMask=0027fija los permisos de creación acordados para Meteora. [Install]solo se usa al hacerenable.WantedBy=multi-user.targetsignifica "cuando se habilite, crea un enlace enmulti-user.target.wants/". Sin sección[Install], un servicio no se puede habilitar: se puede arrancar a mano, pero no arranca solo. Es un despiste frecuente.
Verifica siempre lo que has escrito antes de confiar en ello:
systemd-analyze verify /etc/systemd/system/meteo-api.service # errores de sintaxis y referencias
systemd-analyze security meteo-api.service # puntuación de exposición
# → Overall exposure level for meteo-api.service: 1.9 OKQué aportan. verify detecta directivas mal escritas y unidades referenciadas inexistentes, que de otro modo solo darían la cara al arrancar. security puntúa de 0 (blindado) a 10 (expuesto) evaluando decenas de directivas de aislamiento, y lista una por una las que faltan: es una lista de tareas de endurecimiento generada automáticamente.
Y la unidad del ingestor, más sencilla porque no escucha en un puerto privilegiado:
# /etc/systemd/system/ingestor.service
[Unit]
Description=Receptor de lecturas de las estaciones de Meteora
After=network-online.target var-lib-meteora.mount
RequiresMountsFor=/var/lib/meteora
[Service]
Type=exec
User=meteora
Group=meteora
RuntimeDirectory=meteora
RuntimeDirectoryMode=0750
ExecStart=/usr/local/bin/ingestor --fifo /run/meteora/lecturas.fifo --out /var/lib/meteora/lecturas
Restart=always
RestartSec=2s
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/meteora
PrivateTmp=yes
Nice=-5
[Install]
WantedBy=multi-user.targetLo nuevo aquí. RuntimeDirectory=meteora hace que systemd cree /run/meteora con el propietario y el modo indicados al arrancar y lo borre al parar: es la forma correcta de gestionar el directorio donde vive la FIFO /run/meteora/lecturas.fifo, en lugar de crearlo a mano en un script. Nice=-5 da al ingestor algo más de prioridad de CPU (02-02) porque perder lecturas entrantes es irrecuperable, mientras que una consulta lenta de la API solo molesta.
Tipos de servicio y cómo elegir bien
Type= le dice a systemd cuándo considerar que el servicio ya está arrancado, lo que gobierna cuándo pueden arrancar los que dependen de él.
| Tipo | Se considera arrancado cuando… | Cuándo usarlo |
|---|---|---|
simple |
Se hace fork+exec (¡inmediatamente!) |
Por defecto; el proceso no se demoniza |
exec |
El execve ha tenido éxito |
Mejor que simple: detecta binario inexistente o sin permisos |
forking |
El proceso padre termina y el hijo queda | Demonios clásicos al estilo UNIX; requiere PIDFile= |
oneshot |
El proceso termina (con éxito) | Tareas puntuales: migraciones, limpiezas, scripts |
notify |
El proceso envía READY=1 por sd_notify() |
Servicios que tardan en estar listos de verdad |
idle |
Como simple, pero espera a que no haya más trabajos |
Solo para no ensuciar la consola |
El fallo típico, y es tan frecuente que merece detalle: declarar Type=simple un programa que se demoniza (hace fork, el padre sale, el hijo sigue). systemd ve que el proceso que lanzó ha terminado inmediatamente y, según la política de reinicio, o lo da por muerto y lo reinicia en bucle, o lo da por arrancado y correcto mientras el demonio real corre sin supervisión. El síntoma es un status que dice active (exited) o un ciclo de reinicios de un servicio que en realidad funciona. La solución no es pelearse con forking: es decirle al programa que no se demonice (casi todos tienen --foreground o -D) y usar Type=exec.
Hemos elegido Type=notify para meteo-api por una razón concreta: el servicio tarda unos 8 segundos en cargar el índice y calentar la caché en /dev/shm/meteora-cache. Con simple, systemd lo daría por listo al instante y cualquier unidad que dependa de él —o el balanceador que mira el estado— actuaría sobre un servicio que todavía devuelve errores. Con notify, el programa llama a sd_notify(0, "READY=1") cuando de verdad puede atender, y systemd espera. WatchdogSec=30 añade lo contrario: el servicio debe enviar WATCHDOG=1 cada 30 segundos o systemd lo considera colgado y lo reinicia, lo que detecta bloqueos internos que no matan el proceso.
Dependencias frente a orden
Esta es la distinción que más confusión causa, y es muy simple: son ejes independientes.
| Directiva | Significa |
|---|---|
Requires=B |
Dependencia: si arranco yo, arranca B; si B falla o se para, yo también me paro |
Wants=B |
Dependencia débil: intenta arrancar B, pero si falla, sigo igualmente |
BindsTo=B |
Como Requires, y además me paro si B desaparece (útil con dispositivos) |
Conflicts=B |
B y yo no podemos estar activos a la vez |
After=B |
Orden: no arranco hasta que B haya terminado de arrancar |
Before=B |
Orden: B no arranca hasta que yo termine |
La ilustración crucial. Si escribes solo Requires=var-lib-meteora.mount, systemd arrancará el montaje y tu servicio a la vez, en paralelo: puede que meteo-api intente abrir /var/lib/meteora/lecturas/2026-08-31.dat antes de que el sistema de ficheros esté montado, y falle con ENOENT. Y si escribes solo After=var-lib-meteora.mount, ordenas correctamente pero no pides el montaje: si nadie más lo activa, tu servicio arranca sin datos. Casi siempre necesitas las dos, y por eso RequiresMountsFor= existe: genera ambas de golpe.
Otro matiz importante: en el apagado, el orden se invierte automáticamente. After=network-online.target implica que en la parada meteo-api se detiene antes que la red, que es justo lo que quieres para poder cerrar las conexiones limpiamente.
Y network-online.target merece una advertencia: no significa "hay conectividad a Internet", sino "el gestor de red declara que ha terminado de configurar las interfaces". Necesita que un servicio como systemd-networkd-wait-online esté habilitado; sin él, el objetivo se alcanza de inmediato y no garantiza nada. Un servicio robusto reintenta la conexión en vez de confiar en el orden de arranque.
systemctl list-dependencies meteo-api.service # qué necesita (árbol hacia abajo)
systemctl list-dependencies --reverse meteo-api.service # quién lo necesita a él
systemctl show meteo-api.service -p After -p Requires # las relaciones efectivas, ya resueltasObjetivos y niveles de ejecución
Un objetivo (target) no hace nada por sí mismo: es un punto de sincronización que agrupa unidades. Sustituye a los niveles de ejecución de SysV:
| Nivel SysV | Objetivo systemd | Estado |
|---|---|---|
| 0 | poweroff.target |
Apagado |
| 1 | rescue.target |
Monousuario, shell de root |
| 3 | multi-user.target |
Multiusuario en red, sin gráficos (el de un servidor) |
| 5 | graphical.target |
Multiusuario con entorno gráfico |
| 6 | reboot.target |
Reinicio |
| — | emergency.target |
Solo la raíz montada en solo lectura |
systemctl get-default # multi-user.target
systemctl set-default multi-user.target # objetivo por defecto al arrancar
systemctl isolate rescue.target # cambiar AHORA (para todo lo que no pertenezca)Cuidado con isolate. Para todas las unidades que no formen parte del objetivo destino: ejecutado por error en producción, tumba los servicios. Como diagnóstico previo, systemctl list-units --type=target muestra qué objetivos están activos ahora mismo.
El manejo diario con systemctl
systemctl status meteo-api.service
# ● meteo-api.service - API de consultas meteorológicas de Meteora
# Loaded: loaded (/etc/systemd/system/meteo-api.service; enabled; preset: enabled)
# Active: active (running) since Mon 2026-08-31 02:14:07 CEST; 1h 3min ago
# Main PID: 1834 (meteo-api)
# Status: "Sirviendo; caché 94% llena"
# Tasks: 17 (limit: 512)
# Memory: 1.1G (high: 1.4G, max: 2.0G)
# CPU: 12min 4.031s
# CGroup: /system.slice/meteo-api.service
# └─1834 /usr/local/bin/meteo-api --config /etc/meteora/meteora.confCampo a campo, que es donde está la información:
| Campo | Qué te dice | Trampa |
|---|---|---|
Loaded |
Si el fichero se leyó, su ruta y si está habilitado | enabled ≠ active: habilitado es "arranca al iniciar", activo es "corre ahora" |
Active |
Estado y desde cuándo | Si el "desde cuándo" es de hace 40 segundos y no has tocado nada, se está reiniciando en bucle |
Main PID |
El proceso principal | Si cambia entre dos status, hay reinicios |
Status |
Texto que el propio servicio publica con sd_notify |
Solo aparece en Type=notify |
Tasks |
Hilos y procesos, frente al límite TasksMax |
Rozar el límite provoca fallos de clone() |
Memory |
Uso real del cgroup, con high y max |
Es la cifra fiable, no la de top (07-03) |
CGroup |
Todos los procesos del servicio | Aquí ves los hijos que se te escapaban con SysV |
| Orden | Qué hace |
|---|---|
systemctl start/stop/restart NOMBRE |
Arrancar, parar, reiniciar ahora |
systemctl reload NOMBRE |
Ejecutar ExecReload sin cortar el servicio |
systemctl enable NOMBRE |
Que arranque en los próximos arranques (crea el enlace de [Install]) |
systemctl enable --now NOMBRE |
Habilitar y arrancar de una vez |
systemctl disable / mask |
Quitar del arranque / prohibir que arranque de ninguna forma |
systemctl daemon-reload |
Releer los ficheros de unidad tras editarlos |
systemctl list-units --failed |
La primera orden de cualquier diagnóstico |
systemctl is-active NOMBRE |
Estado en una palabra, con código de salida (para scripts) |
enable frente a start es la confusión número uno del principiante: start arranca ahora y no sobrevive al reinicio; enable prepara el arranque futuro pero no arranca nada hoy. Y daemon-reload frente a reload: el primero le dice a systemd que relea las unidades; el segundo le dice al servicio que relea su configuración. Editar una unidad sin daemon-reload es un clásico: systemd sigue usando la versión vieja y te vuelves loco.
Los registros por unidad, con el journalctl que ya conoces de 05-04:
journalctl -u meteo-api.service -n 50 --no-pager # últimas 50 líneas
journalctl -u meteo-api.service -f # seguimiento en vivo
journalctl -u meteo-api.service --since "2026-08-31 03:00" --until "03:30"
journalctl -u meteo-api.service -p err -b # solo errores del arranque actual
journalctl -u meteo-api.service -b -1 # del arranque ANTERIOR: clave tras un cuelgue
journalctl -u meteo-api.service -o json-pretty -n 1 # todos los campos estructuradosPor qué esto es mejor que un fichero de registro. Como systemd es el padre del proceso y captura su stdout y stderr, cualquier cosa que el servicio imprima queda registrada, incluidos los mensajes de un fallo al arrancar que nunca llegaría a escribir en su propio fichero. Cada entrada lleva la unidad, el PID, el UID y el arranque en que ocurrió, lo que permite filtrar con precisión. -b -1 es la orden que salva la investigación tras un reinicio inesperado.
Políticas de reinicio y el bucle que oculta un fallo
Restart= |
Reinicia cuando… |
|---|---|
no |
Nunca (por defecto) |
on-failure |
Código de salida ≠ 0, señal, tiempo agotado o fallo del watchdog |
on-abnormal |
Solo señal, tiempo agotado o watchdog (no por código de salida) |
always |
Siempre, incluso tras una parada limpia |
on-success |
Solo si terminó bien (útil en tareas cíclicas) |
Para meteo-api usamos on-failure: si alguien lo para a propósito, debe quedarse parado. Para el ingestor usamos always, porque no hay ninguna razón legítima para que termine.
El peligro real es el bucle de reinicio que oculta el fallo. Imagina que alguien introduce un error de sintaxis en /etc/meteora/meteora.conf: el servicio arranca, falla en 200 ms, systemd lo reinicia, vuelve a fallar… A 200 ms por vuelta son 5 intentos por segundo, que llenan el diario, consumen CPU y —lo peor— hacen que un monitor que muestrea cada 30 segundos vea a veces active y a veces failed, con lo que la alerta no acaba de dispararse y nadie investiga.
Por eso están el limitador de arranques y RestartSec:
StartLimitIntervalSec=300 # ventana de observación
StartLimitBurst=5 # máximo de arranques en esa ventana
RestartSec=5s # espera entre intentosQué consiguen. Con estos valores, si el servicio arranca más de 5 veces en 300 segundos, systemd deja de intentarlo y lo marca failed con el motivo start-limit-hit. Eso convierte un bucle silencioso en un estado estable y visible, que sí dispara la alerta. RestartSec=5s evita además el martilleo. Si el fallo es transitorio (una dependencia que tarda), 5 reintentos separados por 5 segundos dan margen suficiente. Tras corregir la causa hay que ejecutar systemctl reset-failed meteo-api.service para limpiar el contador antes de volver a arrancar; olvidarlo es otro despiste habitual.
Temporizadores frente a cron
El agregador debe ejecutarse cada hora. En systemd son dos unidades: el trabajo y su reloj.
# /etc/systemd/system/agregador.service
[Unit]
Description=Cálculo de medias horarias de Meteora
RequiresMountsFor=/var/lib/meteora
[Service]
Type=oneshot
User=meteora
Group=meteora
ExecStart=/usr/local/bin/agregador --entrada /var/lib/meteora/lecturas --hora-anterior
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/var/lib/meteora
PrivateTmp=yes
IOSchedulingClass=idle
Nice=10
TimeoutStartSec=900# /etc/systemd/system/agregador.timer
[Unit]
Description=Ejecuta el agregador de Meteora cada hora
[Timer]
OnCalendar=hourly
AccuracySec=1min
RandomizedDelaySec=180
Persistent=true
Unit=agregador.service
[Install]
WantedBy=timers.targetDirectiva por directiva, con el porqué:
OnCalendar=hourlyequivale a*-*-* *:00:00. La sintaxis admite expresiones comoMon..Fri 06:00,*-*-01 03:30odaily. Compruébala siempre antes de confiar:systemd-analyze calendar 'Mon..Fri 06:00' --iterations=3imprime las próximas ejecuciones reales.Persistent=trueguarda en disco la marca de la última ejecución y, si la máquina estaba apagada a la hora prevista, ejecuta el trabajo en cuanto arranca. Es lo que en el mundo clásico hacíaanacron, aquí con una sola línea.RandomizedDelaySec=180dispersa el arranque hasta 3 minutos al azar. Con una máquina da igual, pero con cincuenta servidores que agregan a las 03:00 en punto evita la estampida que satura la cabina de almacenamiento compartida.AccuracySec=1minpermite además a systemd agrupar despertares y ahorrar energía; ponlo a1ussolo si de verdad necesitas precisión.IOSchedulingClass=idleyNice=10en el servicio hacen que elagregadorceda antemeteo-api, tanto en disco como en CPU. Esta es exactamente la mitigación que se aplicará en el caso práctico de 07-04.Type=oneshotconTimeoutStartSec=900: la tarea termina, no se queda corriendo, y si a los 15 minutos no ha acabado se la considera colgada.
systemctl enable --now agregador.timer
systemctl list-timers --all
# NEXT LEFT LAST PASSED UNIT
# Mon 2026-08-31 04:00:00 CEST 47min left Mon 2026-08-31 03:01:12 CEST 11min agregador.timer
systemctl start agregador.service # ejecutarlo AHORA, sin esperar al reloj
journalctl -u agregador.service -n 30Detalle importante: se habilita el .timer, no el .service. Si habilitaras el servicio, arrancaría también en cada inicio del sistema. Y para probar la tarea a mano se arranca el .service, que es la unidad que hace el trabajo.
Comparación con cron:
| Aspecto | cron / anacron |
Temporizador de systemd |
|---|---|---|
| Sintaxis | 0 * * * *, compacta pero críptica |
OnCalendar=hourly, legible y verificable |
| Ejecución perdida por apagado | Solo con anacron, y con granularidad diaria |
Persistent=true, a cualquier granularidad |
| Registros | A stdout → correo local que nadie lee |
Al diario, con journalctl -u |
| Aislamiento y límites | Ninguno: hereda el entorno de cron |
Todas las directivas de [Service] |
| Supervisión de solapamiento | Manual, con flock |
Automática: no arranca si ya está activo |
| Dispersión de carga | Manual | RandomizedDelaySec |
| Dependencias | No existen | Requires=, After= |
| Ubicuidad | Está en todas partes | Solo en sistemas con systemd |
Ese último punto es el que justifica conocer crontab: sigue siendo omnipresente. Los cinco campos son minuto, hora, día del mes, mes y día de la semana (0 3 * * 1 = lunes a las 03:00); crontab -e edita el del usuario y crontab -l lo lista; en /etc/cron.d/ los ficheros llevan un campo extra con el usuario. Y una advertencia que causa incidentes: cron ejecuta con un PATH mínimo (/usr/bin:/bin) y sin las variables de tu sesión, que es exactamente el error de 07-01 sobre ficheros de configuración de shell. Usa rutas absolutas siempre.
Como regla: en sistemas con systemd, temporizador; y aun así, mantén el flock dentro del script, porque protege también frente a una ejecución manual simultánea.
Activación por socket y por ruta
La activación por socket invierte el orden habitual: systemd abre el punto de escucha y solo arranca el servicio cuando llega la primera conexión.
# /etc/systemd/system/meteo-api.socket
[Socket]
ListenStream=0.0.0.0:443
Backlog=2048
NoDelay=true
[Install]
WantedBy=sockets.targetQué consigue. El socket lo crea systemd (con privilegios) y lo pasa al servicio como descriptor de fichero heredado, de modo que meteo-api ni siquiera necesita CAP_NET_BIND_SERVICE. Además, como el socket existe desde el arranque, las conexiones que lleguen mientras el servicio se reinicia se encolan en el backlog en vez de rechazarse: se pueden hacer despliegues sin conexiones perdidas. Y las unidades que dependen del servicio pueden arrancar en cuanto el socket está listo, no cuando el proceso está listo, lo que paraleliza el arranque. Es el mismo mecanismo que usa inetd desde los años 80, pero integrado con el resto del modelo.
La activación por ruta vigila el sistema de ficheros:
# /etc/systemd/system/lecturas-nuevas.path
[Path]
PathExistsGlob=/var/lib/meteora/entrada/*.dat
Unit=procesar-entrada.service
[Install]
WantedBy=paths.targetQué consigue. En cuanto aparece un fichero que encaja con el patrón, systemd arranca procesar-entrada.service. Es la alternativa correcta al bucle while true; do ls ...; sleep 10; done, porque usa inotify del núcleo: cero consumo mientras no pasa nada y reacción inmediata cuando pasa.
Unidades de usuario y loginctl
Cada usuario con sesión tiene su propia instancia de systemd, que gestiona unidades en ~/.config/systemd/user/ sin privilegios de root:
systemctl --user status # el gestor del usuario actual
systemctl --user enable --now informe-personal.timer
loginctl list-sessions # sesiones activas, con TTY y tipo
loginctl show-user joan -p Linger # ¿sobreviven sus servicios al cierre de sesión?
loginctl enable-linger joan # que sí sobrevivanPor qué importa. Por defecto, las unidades de usuario mueren al cerrar la última sesión: es lo correcto para un escritorio, pero sorprende en un servidor. enable-linger mantiene la instancia viva. Y loginctl es la ventana a systemd-logind, el componente que gestiona sesiones, asientos y el pam_systemd que viste en 05-02. Regla práctica: los servicios de infraestructura, como los de Meteora, van siempre en el gestor del sistema; las unidades de usuario son para tareas personales.
Análisis y depuración del arranque
systemd-analyze time
# Startup finished in 4.216s (firmware) + 3.104s (loader) + 2.891s (kernel) + 11.402s (userspace) = 21.613s
systemd-analyze blame | head -5
# 6.812s meteo-api.service
# 3.204s systemd-networkd-wait-online.service
# 1.118s var-lib-meteora.mount
systemd-analyze critical-chain meteo-api.service
# multi-user.target @11.380s
# └─meteo-api.service @4.568s +6.812s
# └─var-lib-meteora.mount @3.402s +1.118sCómo leerlos, que es donde falla todo el mundo. blame ordena por duración, no por impacto: un servicio que tarda 6 segundos pero arranca en paralelo con otros veinte no retrasa nada. critical-chain sí muestra el camino crítico: @ es el instante en que la unidad empezó y + lo que tardó, así que solo reduciendo lo que aparece en esa cadena se acorta el arranque. En el ejemplo, meteo-api sí está en el camino crítico y su ExecStartPre de verificación es parte de esos 6,8 segundos: una decisión consciente de cambiar arranque rápido por arranque seguro.
El guion de "mi servicio no arranca", en orden:
systemctl status meteo-api.service -l --no-pager— el motivo casi siempre está en las últimas líneas. Mira elActive:(¿failed,activating,inactive?) y el código:status=203/EXECes "no se pudo ejecutar el binario" (ruta mal escrita, sin permiso de ejecución, shebang inválido);status=200/CHDIRes unWorkingDirectoryinexistente;status=1es el propio programa saliendo con error.journalctl -u meteo-api.service -n 100 --no-pager— el mensaje real del programa. Si está vacío, el fallo es anterior al programa.systemctl cat meteo-api.service— comprueba que la unidad efectiva es la que crees, con sus drop-ins. ¿Hicistedaemon-reload?systemd-analyze verify /etc/systemd/system/meteo-api.service— sintaxis y referencias.- Ejecuta el comando a mano, como el usuario del servicio:
sudo -u meteora /usr/local/bin/meteo-api --config /etc/meteora/meteora.conf. Si a mano funciona y como servicio no, la diferencia está en el entorno:PATH, directorio de trabajo, variables, o el endurecimiento. - Sospecha del endurecimiento, que es la causa moderna más frecuente. Comenta temporalmente
ProtectSystem=strictoSystemCallFilter=en un drop-in y prueba. Si con eso arranca, ya sabes qué directiva afinar; búscalo conjournalctl -k | grep -i seccompo_AUDIT_FIELD_SYSCALL. - Comprueba permisos y SELinux/AppArmor:
namei -l /var/lib/meteora/lecturasrecorre la ruta entera mostrando propietario y modo de cada componente, ydmesg | grep -i denieddelata al control de acceso obligatorio de 05-01. - Dependencias:
systemctl list-dependencies --failedysystemctl show -p After -p Requires.
Apagado ordenado: SIGTERM, SIGKILL y TimeoutStopSec
Cuando ejecutas systemctl stop meteo-api.service, systemd sigue una secuencia estricta:
- Envía
SIGTERMal proceso principal (o ejecutaExecStopsi existe). - Espera hasta
TimeoutStopSec(30 s en nuestra unidad). - Si no ha terminado, envía
SIGKILLa todos los procesos del cgroup.
La diferencia entre las dos señales es la de siempre (03-03): SIGTERM es una petición educada que el programa puede capturar para terminar las peticiones en curso, volcar la caché de /dev/shm/meteora-cache, hacer fsync de lo pendiente y cerrar; SIGKILL la ejecuta el núcleo y no se puede capturar, así que el proceso desaparece a mitad de lo que estuviera haciendo.
Por qué el valor de TimeoutStopSec importa de verdad. Si es demasiado corto, un meteo-api que está terminando de escribir un bloque recibe SIGKILL a mitad y deja un fichero de lecturas truncado —exactamente el caso que detecta la comprobación tam % 24 != 0 del script de 07-01—. Si es demasiado largo, un reinicio del sistema se queda colgado minutos esperando a un proceso que nunca va a responder. El valor correcto es el peor caso razonable de cierre limpio, más un margen: para meteo-api, con hasta 2 GB de caché que volcar, 30 segundos.
En el apagado completo (systemctl poweroff), systemd para las unidades en orden inverso al de arranque, desmonta los sistemas de ficheros, sincroniza el disco y apaga. Si alguna vez ves el mensaje A stop job is running for ... (1min 30s / 2min) durante un apagado eterno, estás viendo exactamente este mecanismo: una unidad que no responde a SIGTERM y agota su temporizador. journalctl -b -1 -p warning te dirá cuál fue.
Errores Comunes y Consejos
| Error | Consecuencia | Solución |
|---|---|---|
Editar una unidad y no hacer daemon-reload |
systemd usa la versión antigua | systemctl daemon-reload, o usa systemctl edit |
Copiar la unidad del paquete a /etc |
Te pierdes las mejoras del mantenedor | Drop-in con systemctl edit |
Confundir enable con start |
El servicio no sobrevive al reinicio, o no arranca hoy | enable --now |
Olvidar [Install] |
enable responde que no hay nada que hacer |
Añade WantedBy=multi-user.target |
Type=simple en un demonio que se demoniza |
Bucle de reinicios o supervisión falsa | --foreground + Type=exec |
After= sin Requires= (o al revés) |
Arranca sin su dependencia, o en paralelo con ella | RequiresMountsFor=, o ambas directivas |
Rutas relativas en ExecStart |
status=203/EXEC |
Ruta absoluta siempre |
Varias órdenes con ; o && en ExecStart |
No hay shell: se pasan como argumentos literales | ExecStart=/bin/bash -c '...' o varias ExecStartPre= |
Habilitar el .service en vez del .timer |
La tarea se ejecuta también en cada arranque | enable --now agregador.timer |
No hacer reset-failed tras corregir |
El servicio no arranca por el límite alcanzado | systemctl reset-failed NOMBRE |
TimeoutStopSec demasiado corto |
SIGKILL a mitad de una escritura, datos truncados |
Ajústalo al peor cierre limpio |
Editar grub.cfg a mano |
Se pierde en el siguiente update-grub |
Edita /etc/default/grub y regenera |
Consejos: usa siempre systemctl cat antes de modificar nada, porque muestra la configuración efectiva; añade Documentation= a tus unidades para que quien te releve sepa dónde mirar; ejecuta systemd-analyze security sobre cada servicio nuevo y trátalo como lista de tareas; y prueba los reinicios de verdad: un servidor que lleva 400 días encendido y nunca se ha reiniciado esconde, casi con seguridad, un servicio que no está habilitado.
Ejercicios
Ejercicio 1: unidad para el verificador de lecturas
Convierte el script verificar-lecturas.sh de 07-01 en un servicio con temporizador que se ejecute cada día a las 06:15, recupere la ejecución si la máquina estaba apagada, corra como meteora sin más privilegios de los necesarios, no pueda escribir en ningún sitio y se dé por colgado a los 10 minutos. Escribe las dos unidades y las órdenes para activarlas y probarlas.
Ejercicio 2: diagnóstico de un servicio que no arranca
Tras un cambio, meteo-api no arranca. systemctl status muestra:
Active: failed (Result: exit-code) since Mon 2026-08-31 03:02:11 CEST; 12s ago Process: 4471 ExecStart=/usr/local/bin/meteo-api --config /etc/meteora/meteora.conf (code=exited, status=203/EXEC)
Enumera, en orden, las comprobaciones que harías y qué causa confirmaría cada una.
Ejercicio 3: bucle de reinicio
Un compañero define el ingestor con Restart=always y RestartSec=0, sin límite de arranques. Un error de configuración hace que falle al arrancar. Describe qué ocurre en la máquina en los 60 segundos siguientes, por qué la monitorización podría no avisar, y qué tres directivas añadirías.
Soluciones
Solución 1
# /etc/systemd/system/verificar-lecturas.service
[Unit]
Description=Verificación de integridad de los datos de Meteora
RequiresMountsFor=/var/lib/meteora
[Service]
Type=oneshot
User=meteora
Group=meteora
ExecStart=/usr/local/bin/verificar-lecturas.sh -d /var/lib/meteora/lecturas
TimeoutStartSec=600
SuccessExitStatus=0 1
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
CapabilityBoundingSet=
SystemCallFilter=@system-service
Nice=10
IOSchedulingClass=idle# /etc/systemd/system/verificar-lecturas.timer
[Unit]
Description=Verificación diaria de los datos de Meteora
[Timer]
OnCalendar=*-*-* 06:15:00
Persistent=true
RandomizedDelaySec=300
Unit=verificar-lecturas.service
[Install]
WantedBy=timers.targetsystemctl daemon-reload
systemctl enable --now verificar-lecturas.timer
systemctl list-timers verificar-lecturas.timer
systemctl start verificar-lecturas.service # prueba inmediata
journalctl -u verificar-lecturas.service -n 40 --no-pager
systemd-analyze calendar '*-*-* 06:15:00' --iterations=3Puntos clave. ProtectSystem=strict sin ReadWritePaths deja todo el sistema en solo lectura, que es justo lo que pide el enunciado: el verificador solo lee (su directorio temporal lo cubre PrivateTmp). CapabilityBoundingSet= vacío elimina todas las capabilities, porque un script de comprobación no necesita ninguna. TimeoutStartSec=600 da los 10 minutos pedidos, y como es Type=oneshot systemd sabe que la unidad ha terminado cuando el proceso sale. SuccessExitStatus=0 1 es el detalle fino: nuestro script devuelve 1 cuando hay advertencias, y no queremos que eso marque la unidad como failed; el 3 (crítico) sí debe hacerlo. Y Persistent=true cubre el requisito de recuperar la ejecución perdida.
Solución 2
status=203/EXEC significa que el execve falló: systemd no llegó a ejecutar nada, así que el diario del servicio estará vacío y el problema es del binario o de su entorno, no del programa. Comprobaciones, de más a menos probable:
ls -l /usr/local/bin/meteo-api— ¿existe? ¿Es la ruta exacta, sin errata? Un despliegue que dejó el binario en/usr/local/sbinda este error.stat -c '%A %U %G' /usr/local/bin/meteo-api— ¿tiene bit de ejecución? Unscpo ungit checkoutmal hecho puede quitarlo.namei -l /usr/local/bin/meteo-api— ¿el usuariometeorapuede atravesar todos los directorios de la ruta? Basta que un directorio intermedio pierda el bitxpara que falle.head -c2 /usr/local/bin/meteo-apiyfile— si es un script, ¿su shebang apunta a un intérprete que existe? Un#!/usr/bin/env python3sin python3 instalado produce exactamente 203/EXEC.ldd /usr/local/bin/meteo-api | grep 'not found'— ¿falta alguna biblioteca compartida?mount | grep ' /usr/local '— ¿está montado connoexec? Es raro pero ocurre, sobre todo en particiones separadas endurecidas.systemctl cat meteo-api.service— ¿hay un drop-in reciente que cambióExecStarto añadió unWorkingDirectoryinexistente (eso daría 200/CHDIR)?- Prueba directa:
sudo -u meteora /usr/local/bin/meteo-api --config /etc/meteora/meteora.conf. Si funciona a mano, revisa el endurecimiento, empezando porSystemCallFilteryProtectSystem.
Solución 3
Qué ocurre. Con RestartSec=0 y sin límite, el ciclo arrancar-fallar se repite tan rápido como el sistema pueda hacer fork+execve: si el fallo tarda 50 ms en manifestarse, son unas 20 ejecuciones por segundo, es decir en torno a 1.200 en el primer minuto. Consecuencias: consumo continuo de CPU en creación de procesos, miles de entradas en el diario que pueden llegar a los límites de tasa de journald (RateLimitBurst) y hacer que se descarten mensajes —perdiendo justo los que explican el fallo—, y presión de E/S sobre /var/log.
Por qué la monitorización podría no avisar. Un chequeo que ejecuta systemctl is-active ingestor cada 30 segundos tiene una probabilidad alta de caer justo en una ventana en que el servicio está activating o active, porque el estado oscila decenas de veces por segundo. El resultado es una alerta intermitente ("flapping") que muchos sistemas suprimen por ruidosa, o directamente una serie de comprobaciones correctas. El servicio nunca llega a un estado estable de fallo, que es lo que las alertas saben detectar.
Las tres directivas:
RestartSec=5s # separa los intentos: 12 por minuto, no 1.200
StartLimitIntervalSec=300 # ventana de observación
StartLimitBurst=5 # tras 5 arranques en 300 s, se rinde y queda en 'failed'Con esto, el peor caso son 5 reintentos en 25 segundos y después un estado failed estable, que dispara la alerta a la primera comprobación y deja el diario legible. Añadiría además Restart=on-failure en lugar de always si hubiera algún motivo legítimo para parar el servicio, y una alerta específica sobre la salida de systemctl list-units --failed, que es la señal más barata y fiable de que algo va mal en la máquina.
Conclusión
Has seguido el encendido de meteo-01 completo: el firmware UEFI leyendo la ESP y verificando firmas con Secure Boot; GRUB presentando el menú cuya línea de parámetros es la herramienta de rescate más valiosa que tienes; el núcleo y el initramfs, que existe para romper el círculo de necesitar los módulos de RAID y ext4 que viven dentro de la raíz que aún no puede montar; el switch_root y, por fin, el PID 1, que no se puede matar, adopta huérfanos y cuya muerte provoca un pánico.
Y has desmontado systemd, que resolvió cinco carencias reales de los guiones secuenciales de SysV: paralelismo, dependencias declaradas, activación bajo demanda, supervisión y —la más subestimada— un cgroup por servicio, que convierte "los procesos de este servicio" en un hecho del núcleo y no en una suposición de un fichero .pid. Sobre ese modelo has escrito la unidad completa de meteo-api, donde cada bloque tiene su razón: Type=notify porque tarda 8 segundos en estar realmente listo, AmbientCapabilities=CAP_NET_BIND_SERVICE para escuchar en el 443 sin ser root, ProtectSystem=strict con tres ReadWritePaths, un filtro seccomp, y los límites de memoria y E/S del cgroup.
Y has visto los mecanismos que se usan a diario: la distinción entre dependencia y orden, que explica la mitad de los arranques rotos; enable frente a start y daemon-reload frente a reload; status leído campo a campo; el bucle de reinicio que oculta un fallo y las tres directivas que lo convierten en un estado visible; los temporizadores con Persistent=true y RandomizedDelaySec frente a cron; la activación por socket, que permite reiniciar sin perder conexiones; critical-chain frente a blame; el guion de ocho pasos para "no arranca"; y la secuencia SIGTERM → TimeoutStopSec → SIGKILL, cuyo valor mal elegido produce exactamente los ficheros truncados que detectábamos en la lección anterior.
Con esto, meteo-01 arranca solo, se recupera solo y ejecuta sus tareas a su hora. Pero un sistema que arranca correctamente puede funcionar mal. El servicio está active (running), el temporizador se dispara puntualmente, no hay ninguna unidad en failed… y aun así los usuarios se quejan de que la API va lenta. Ninguna de las herramientas de esta lección responde a "¿por qué?": para eso hacen falta un método y unos números.
Es el tema siguiente: Monitorización y Diagnóstico de Rendimiento, donde aprenderás qué mirar en los primeros 60 segundos de una incidencia y cómo pasar de un síntoma vago a una causa concreta.
Fundamentos de Sistemas Operativos
Módulo 1: Introducción a los Sistemas Operativos
- Conceptos Básicos de Sistemas Operativos
- Historia y Evolución de los Sistemas Operativos
- Tipos de Sistemas Operativos
- Funciones Principales de un Sistema Operativo
- Arquitectura del Núcleo: Monolítico, Microkernel e Híbrido
- Modo Usuario, Modo Núcleo y Llamadas al Sistema
Módulo 2: Gestión de Recursos
- Gestión de Procesos
- Planificación de la CPU
- Gestión de Memoria
- Memoria Virtual y Paginación
- Gestión de Almacenamiento
- Gestión de Dispositivos
- Controladores, Interrupciones y Operaciones de E/S
Módulo 3: Concurrencia
- Conceptos de Concurrencia
- Hilos y Procesos
- Comunicación entre Procesos (IPC)
- Sincronización y Exclusión Mutua
- Problemas Clásicos de Concurrencia
- Interbloqueos: Prevención, Detección y Recuperación
Módulo 4: Estructuras de Archivos
- Sistemas de Archivos
- Estructuras de Directorios
- Particiones, Montaje y Sistema de Archivos Virtual
- Gestión de Archivos
- Asignación de Espacio, Journaling e Integridad
- Seguridad y Permisos de Archivos
Módulo 5: Protección y Seguridad del Sistema
- Principios de Protección y Control de Acceso
- Usuarios, Autenticación y Escalada de Privilegios
- Amenazas Comunes y Endurecimiento del Sistema
- Auditoría, Registros y Respuesta a Incidentes
Módulo 6: Virtualización y Contenedores
- Virtualización: Hipervisores y Máquinas Virtuales
- Contenedores: Namespaces y cgroups
- El Sistema Operativo en la Nube
- Sistemas Operativos Móviles y de Tiempo Real
