Procesos y servicios
Linux gestiona los recursos del sistema mediante procesos (unidades de ejecución), servicios (procesos gestionados por systemd) y una pila de red configurable a bajo nivel. Entender cómo se relacionan entre sí y cómo el kernel los gestiona es fundamental tanto para administración como para seguridad.
1. ⚙️ Procesos
1.1. ¿Qué es un proceso?
Un proceso es un programa en ejecución con su propio espacio de memoria, descriptores de archivo y contexto de seguridad. El kernel asigna a cada proceso un PID (Process ID) único.
disco: /usr/bin/nginx
│
│ execve()
▼
PROCESO (nginx)
├── PID: 1234
├── PPID: 1 ← proceso padre (systemd)
├── UID/GID: www-data ← contexto de seguridad
├── Estado: S ← sleeping
├── Memoria: espacio virtual propio
├── FDs: 0 (stdin), 1 (stdout), 2 (stderr), 3 (socket)...
└── Señales: máscara de señales pendientes/bloqueadas
1.2. Árbol de procesos
Todo proceso tiene un padre. El proceso raíz es systemd (PID 1), que arranca todos los demás.
systemd (1)
├── sshd (892) ← daemon SSH
│ └── sshd (1203) ← sesión de jessica
│ └── bash (1204)
│ └── ps (1250) ← proceso temporal
├── nginx (1100)
│ ├── nginx worker (1101)
│ └── nginx worker (1102)
├── cron (950)
└── ...
Creación de procesos
Linux crea nuevos procesos con dos syscalls fork y exec. Cuando se ejecuta un comando en bash, el sistema sigue este proceso:
-
bash llama a
fork()→ crea un proceso hijo idéntico a bash -
El hijo llama a
exec("/usr/bin/ls")→ su imagen se reemplaza con ls -
bash (padre) espera con
wait()a que el hijo termine
1.3. Estados de un proceso
| Estado | Código | Descripción |
|---|---|---|
| Running | R |
Ejecutándose en CPU o listo para ejecutarse |
| Sleeping | S |
Esperando un evento (interruptible — puede recibir señales) |
| Sleeping | D |
Espera en I/O de disco (ininterrumpible — no puede recibir señales) |
| Stopped | T |
Detenido por señal SIGSTOP o depurador |
| Zombie | Z |
Terminado pero no recogido por el padre (espera wait()) |
| Dead | X |
Muerto, pendiente de limpieza por el kernel |
Procesos zombie
Un proceso zombie no consume CPU ni memoria real, pero sí ocupa una entrada en la tabla de procesos. Si el padre nunca llama a wait(), los zombies se acumulan. Al matar al padre, los zombies son adoptados por systemd, que los recoge automáticamente.
1.4. /proc — el filesystem de procesos
/proc es un filesystem virtual en RAM que expone el estado interno del kernel y de cada proceso.
/proc/
├── <PID>/ ← directorio de cada proceso
│ ├── cmdline ← comando con el que se lanzó
│ ├── environ ← variables de entorno (separadas por \0)
│ ├── exe ← symlink al ejecutable
│ ├── fd/ ← descriptores de archivo abiertos
│ ├── maps ← regiones de memoria mapeadas
│ ├── mem ← memoria del proceso (requiere ptrace)
│ ├── net/ ← estado de red del proceso
│ ├── status ← estado: UID, GID, memoria, señales...
│ └── cwd ← directorio de trabajo actual (symlink)
├── cpuinfo ← información de la CPU
├── meminfo ← información de la RAM
├── net/ ← estado de la red del sistema
│ ├── tcp ← conexiones TCP activas
│ ├── udp ← conexiones UDP activas
│ └── if_inet6 ← interfaces de red IPv6
├── mounts ← filesystems montados
├── version ← versión del kernel
└── sys/ ← parámetros del kernel (sysctl)
| Acción | Comando |
|---|---|
| Comando del proceso 1234 | cat /proc/1234/cmdline \| tr '\0' ' ' |
| Archivos abiertos por el proceso | ls -la /proc/1234/fd/ |
| Variables de entorno del proceso | cat /proc/1234/environ \| tr '\0' '\n' |
| Ruta del ejecutable | readlink /proc/1234/exe |
1.5. Señales
Las señales son notificaciones asíncronas enviadas a un proceso para indicar un evento.
| Señal | Número | Descripción | Por defecto |
|---|---|---|---|
SIGHUP |
1 | Colgar terminal / recargar config | Terminar |
SIGINT |
2 | Interrupción (Ctrl+C) | Terminar |
SIGQUIT |
3 | Salir con core dump (Ctrl+) | Volcar y terminar |
SIGKILL |
9 | Matar inmediatamente (no se puede ignorar) | Terminar (forzado) |
SIGSEGV |
11 | Fallo de segmentación (acceso inválido a memoria) | Volcar y terminar |
SIGTERM |
15 | Terminar limpiamente (se puede ignorar/capturar) | Terminar |
SIGSTOP |
19 | Parar proceso (no se puede ignorar) | Parar |
SIGCONT |
18 | Continuar proceso parado | Continuar |
SIGUSR1/2 |
10/12 | Señales de usuario definidas por la aplicación | Terminar |
Tenemos estos comandos:
| Acción | Comando |
|---|---|
| Terminar limpiamente / Forzar terminación (SIGKILL) | kill -SIGTERM 1234 / kill -9 1234 |
| Recargar configuración | kill -SIGHUP 1234 |
| SIGTERM a todos los procesos nginx | killall nginx |
| SIGTERM a todos los procesos de jessica | pkill -u jessica |
| Enviar señal a un grupo de procesos - antes del PID | kill -SIGTERM -1234 |
3. 🔧 Servicios — systemd
3.1. La pila de red del kernel
Aplicación (nginx, curl...)
│ syscalls: send(), recv(), connect()...
▼
┌─────────────────────────────────┐
│ Sockets BSD (API) │ ← interfaz para las aplicaciones
├─────────────────────────────────┤
│ TCP UDP │ ← capa de transporte
├─────────────────────────────────┤
│ IP (IPv4 / IPv6) │ ← enrutamiento
├─────────────────────────────────┤
│ Netfilter (iptables/nftables) │ ← filtrado, NAT, mangling
├─────────────────────────────────┤
│ Driver de red (e1000, virtio) │ ← interfaz física
└─────────────────────────────────┘
│
eth0, lo, wlan0...
3.2. ¿Qué es systemd?
systemd es el sistema de init y gestor de servicios estándar en las distribuciones Linux modernas. Reemplaza al init clásico de SysV. Es el PID 1 del sistema — el primer proceso que arranca el kernel y del que dependen todos los demás.
Kernel arranca
│
▼
systemd (PID 1)
│ lee /etc/systemd/system/ y /lib/systemd/system/
├── Monta filesystems
├── Configura la red (NetworkManager / systemd-networkd)
├── Inicia servicios (nginx, sshd, cron...)
└── Activa targets (multi-user.target, graphical.target...)
3.3. Units — los bloques de systemd
Todo en systemd se gestiona mediante units (archivos de configuración):
| Tipo de unit | Extensión | Descripción |
|---|---|---|
| Service | .service |
Daemon o proceso gestionado |
| Timer | .timer |
Equivalente a cron, dispara services |
| Socket | .socket |
Activa un service cuando hay conexión al socket |
| Target | .target |
Agrupa units (como runlevels de SysV) |
| Mount | .mount |
Punto de montaje del filesystem |
| Path | .path |
Monitoriza un archivo/directorio y activa un service |
| Device | .device |
Dispositivo de hardware |
| Slice | .slice |
Jerarquía de cgroups para agrupar procesos |
Ubicación de los archivos unit
/lib/systemd/system/ # units del sistema (paquetes instalados)
/etc/systemd/system/ # units del administrador (sobreescribe a lib/)
~/.config/systemd/user/ # units del usuario (--user)
3.4. Anatomía de un archivo .service
Por ejemplo /etc/systemd/system/mi-app.service
[Unit]
Description=Mi aplicación web
Documentation=https://mi-app.com/docs
After=network.target # arrancar después de la red
Requires=postgresql.service # depende de postgresql
Wants=redis.service # preferible que redis esté, pero no obligatorio
[Service]
Type=simple # simple / forking / oneshot / notify / dbus
ExecStart=/usr/bin/mi-app --config /etc/mi-app/config.yaml
ExecReload=/bin/kill -HUP $MAINPID # recarga con SIGHUP
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure # reiniciar si falla
RestartSec=5 # esperar 5s antes de reiniciar
User=www-data # usuario bajo el que corre
Group=www-data
WorkingDirectory=/opt/mi-app
# Variables de entorno
Environment=NODE_ENV=production
EnvironmentFile=/etc/mi-app/env # o desde archivo
# Límites de recursos
LimitNOFILE=65536 # máximo de descriptores de archivo
MemoryMax=512M # límite de RAM (cgroup)
CPUQuota=50% # máximo 50% de CPU
# Seguridad
NoNewPrivileges=yes # no puede ganar privilegios
PrivateTmp=yes # /tmp privado
ReadOnlyPaths=/etc # /etc de solo lectura
ProtectSystem=strict # filesystem de solo lectura excepto los marcados
[Install]
WantedBy=multi-user.target # a qué target pertenece (arranca con el sistema)
| Tipo | Descripción |
|---|---|
simple |
El proceso de ExecStart es el proceso principal. Default |
forking |
El proceso hace fork y el padre termina (daemons clásicos) |
oneshot |
Ejecuta y termina. Útil para scripts de configuración |
notify |
El daemon avisa a systemd cuando está listo (via sd_notify) |
dbus |
Listo cuando adquiere un nombre en el bus D-Bus |
idle |
Como simple pero espera a que no haya otros jobs pendientes |
3.5. Logs — journalctl
systemd centraliza todos los logs en el journal (binario, en /var/log/journal/).
| Acción | Comando |
|---|---|
| Ver todos los logs | journalctl |
| Logs de un servicio en tiempo real | journalctl -u nginx -f |
| Logs de arranque actual / anterior tras un crash | journalctl -b / journalctl -b -1 |
| Solo errores | journalctl -p err |
| Filtrar por PID / nombre de proceso | journalctl _PID=1234 / _COMM=nginx |
| Eliminar logs de más de 30 días / reducir a 50 mb | journalctl --vacuum-time=30d / --vacuum-size=50M |
3.6. Timers — el cron de systemd
Los timers de systemd sustituyen a cron con más control y logging integrado.
# /etc/systemd/system/backup.timer
[Unit]
Description=Backup diario a las 2:00
[Timer]
OnCalendar=*-*-* 02:00:00 # todos los días a las 2:00
Persistent=true # ejecutar si se perdió la ejecución anterior
Unit=backup.service # service que dispara
[Install]
WantedBy=timers.target
Sintaxis de OnCalendar
| cada hora | una vez al día (00:00) | lunes 00:00 | días laborables a las 9 | cada 15 minutos |
|---|---|---|---|---|
OnCalendar=hourly |
OnCalendar=daily |
OnCalendar=weekly |
OnCalendar=Mon..Fri 09:00:00 |
OnCalendar=*:0/15 |
# /etc/systemd/system/backup.service
[Unit]
Description=Script de backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=backup
| Acción | Comando |
|---|---|
| Activar timer | systemctl enable --now backup.timer |
| Ver todos los timers y cuándo disparan | systemctl list-timers |
| Ver logs de las ejecuciones | journalctl -u backup.service |
3.7. cron — el gestor de tareas clásico
Aunque systemd timers son la alternativa moderna, cron sigue siendo muy usado.
| Acción | Comando |
|---|---|
| Editar el crontab del usuario actual | crontab -e |
| Ver el crontab del usuario actual | crontab -l |
| Crontab de root | sudo crontab -e |
| Archivos de cron del sistema / aplicaciones | cat /etc/crontab / ls /etc/cron.d/ |
# m h dom mon dow comando
# │ │ │ │ │
# │ │ │ │ └── día de la semana (0-7, 0 y 7 = domingo)
# │ │ │ └─────── mes (1-12)
# │ │ └──────────── día del mes (1-31)
# │ └──────────────── hora (0-23)
# └─────────────────── minuto (0-59)
*/5 * * * * /usr/local/bin/check.sh # cada 5 minutos
0 2 * * * /usr/local/bin/backup.sh # cada día a las 2:00
0 9 * * 1-5 /usr/local/bin/informe.sh # lunes a viernes a las 9:00
@reboot /usr/local/bin/arranque.sh # al iniciar el sistema
@hourly /usr/local/bin/limpieza.sh # cada hora