Tradicionalmente en los sistemas Unix, init es el primer proceso que se ejecuta durante el inicio del sistema en modo usuario (userland), luego de la carga del kernel. El proceso init es un demonio que continua su ejecución hasta que el sistema se apaga. Es el padre de todos los procesos (de forma directa o indirecta) y es quien adopta automáticamente los procesos huérfanos. Es iniciado por el kernel utilizando un nombre de archivo hard-coded, y si el kernel no es capaz de iniciarlo, el resultado es un kernel panic. Típicamente tiene el ID de proceso (PID) 1
.
El diseño de init tuvo una divergencia entre los sistemas Unix System V y BSD. En el esquema System V se utiliza el archivo /etc/inittab
para establecer los runlevels disponibles. Los runlevels determinan el nivel de ejecución del sistema. En términos prácticos, cada runlevel determina el subconjunto de servicios o demonios que serán iniciados durante el inicio del sistema, exceptuando el runlevel 0 que se utiliza para apagar el sistema y el runlevel 6 que se utiliza para reiniciar. El init de BSD ejecuta el script de inicialización /etc/rc
, de forma similar a como se hacía en el sistema Unix original de Bell Labs. No hay runlevels, sino que el archivo /etc/rc
determina qué servicios se inician. La ventaja de este sistema es que es simple y fácil de mantener, aunque es propenso a errores, ya que un simple error en el script puede detener el inicio del sistema.
La mayoría de las distribuciones GNU/Linux adoptaron el diseño de System V (SysVinit), aunque algunas (notablemente Slackware) utilizan el esquema BSD y otras utilizan una versión personalizada (por ejemplo Gentoo).
Para solucionar limitaciones de diseño en las versiones estándar, se han desarrollado diferentes implementaciones de init, como systemd y Upstart. Una de las principales limitaciones o desventajas de los diseños tradicionales, es que los servicios se inician de forma secuencial. Quienes hayan trabajado con sistemas RHEL 5 o CentOS 5 (por citar un ejemplo) recordaran la gran cantidad de tiempo que duraba el inicio del sistema, ya que hasta que el proceso de inicio de un servicio o demonio no devolvía el control, no se iniciaba el siguiente. Además podía suceder que si un servicio fallaba, el proceso de inicio quedaba bloqueado. Un caso particular sucedía con el servicio NTP, por citar un ejemplo. Al ejecutar el demonio NTP inicialmente intentaba contactar a un servidor de tiempo. Si por alguna razón el sistema no tenía red, el cliente NTP quedaba ciclando tratando de contactar un servidor de tiempo en un bucle infinito y el sistema no terminaba de iniciar nunca. La única solución era reiniciar y deshabilitar NTP durante el inicio selectivo.
systemd
systemd ha sido diseñado exclusivamente para el kernel Linux. Durante el proceso de inicio de Linux, es el primer proceso en ejecutar en modo usuario y es el padre de todos los procesos. Fue desarrollado para reemplazar al viejo sistema init heredado de System V y BSD. Al igual que init, es el demonio que se encarga de gestionar el resto de los demonios del sistema. Todos los demonios (incluyendo systemd) son procesos en segundo plano. systemd es el primer demonio en iniciar (durante el inicio) y el último en terminar (durante el apagado).
systemd fue pensado para mejorar la eficiencia del proceso de inicio init de System V. Se cambió la forma en la que se expresan las dependencias entre servicios para incrementar el paralelismo y concurrencia del proceso de inicio (permitir que los demonios y servicios inicien de forma concurrente en vez de secuencial) y para reducir la sobrecarga computacional de la shell.
Las instrucciones de inicialización de cada demonio se almacenan en un archivo de configuración declarativo mas que en un shell script. systemd hace el seguimiento de procesos demonios utilizando grupos de control (cgroups) en lugar de PIDs, por lo tanto los demonios no pueden escapar al control de systemd, ni siquiera haciendo fork.
Fedora fue la primera distribución GNU/Linux en adoptar a systemd, es por ello que si ejecutamos ps 1
en Fedora veremos [systemd]
en lugar de init
, /sbin/init
, [init]
o algo por el estilo.
Upstart
Upstart es un reemplazo basado en eventos al tradicional demonio init. Fue desarrollado por Scott James Remnant, un ex empleado de Canonical Ltd. Upstart opera de manera asincrónica, además de gestionar el inicio y detención de tareas y servicios durante el inicio y apagado, supervisa mientras el sistema está en funcionamiento. Una de las metas de diseño fue hacerlo totalmente compatible con SysVinit y de fácil transición, por ello es capaz de ejecutar scripts SysVinit sin modificaciones.
Ubuntu utiliza Upstart por defecto, al igual que Red Hat 6 y derivados (CentOS 6, Scientific Linux 6, Oracle Linux 6), Chrome OS, openSUSE 11 (aunque no por defecto) y posiblemente Debian en un futuro cercano (ya que systemd es exclusivo para el kernel Linux y no funcionaría con los kernels Hurd y kFreeBSD). Fedora utilizó Upstart desde la versión 9 hasta la 15 donde fue reemplazado por systemd, por lo que se estima que en un futuro Red Hat usará systemd.
¿Quién juega de init en mi sistema: SysVinit, systemd o Upstart?
La entrada Debian y el final de SysVinit en el blog Crónicas de Software Libre en español fue la que me motivó a escribir este artículo (recomiendo leerla), ya que soy un dinosaurio que todavía utiliza Debian y administra viejos servidores Red Hat y CentOS estoy más familiarizado con SysV que con systemd o Upstart. Debian (al igual que Red Hat, Slackware, Gentoo, entre otras) es una distribución robusta, sólida como una roca, que se niega a cambiar sólo por cambiar. Si algo funciona bien, ¿por qué cambiarlo?.
Luego de analizar las diferentes alternativas, ¿cómo puedo saber qué gestor de control del proceso de inicialización está utilizando mi sistema operativo? La respuesta fácil es: leyendo la documentación de mi distribución. Aunque podemos determinarlo más rápidamente desde las man pages o ejecutando ps. Veamos algunos ejemplos.
Debian 6 (System V)
# cat /etc/issue Debian GNU/Linux 6.0 \n \l
Tal como mencionaba anteriormente, Debian aún utiliza SysVinit, el tradicional proceso init heredado de los sistemas Unix System V. Al ejecutar ps 1
en la línea de comandos podemos obtener información de estado del proceso cuyo PID es 1, o sea init:
# ps 1 PID TTY STAT TIME COMMAND 1 ? Ss 1:22 init [2]
La información del proceso nos da la pauta de que se trata de init. Podemos observar que el binario init se encuentra en /sbin/init
:
# which init /sbin/init # ll /sbin/init -rwxr-xr-x 1 root root 37K Jan 1 2011 /sbin/init
Si abrimos el manual de init (man init
), nos encontramos con que se trata de SysVinit:
INIT(8) Linux System Administrator's Manual INIT(8) NAME init, telinit - process control initialization SYNOPSIS /sbin/init [ -a ] [ -s ] [ -b ] [ -z xxx ] [ 0123456Ss ] /sbin/telinit [ -t SECONDS ] [ 0123456sSQqabcUu ] /sbin/telinit [ -e VAR[=VAL] ] DESCRIPTION Init Init is the parent of all processes. Its primary role is to create processes from a script stored in the file /etc/inittab (see init‐ tab(5)). This file usually has entries which cause init to spawn get‐ tys on each line that users can log in. It also controls autonomous processes required by any particular system. RUNLEVELS A runlevel is a software configuration of the system which allows only a selected group of processes to exist. The processes spawned by init for each of these runlevels are defined in the /etc/inittab file. Init can be in one of eight runlevels: 0–6 and S (a.k.a. s). The runlevel
En la sección "CONFORMING TO" podemos confirmar que se trata de SysVinit:
CONFORMING TO Init is compatible with the System V init. It works closely together with the scripts in the directories /etc/init.d and /etc/rc{runlevel}.d. If your system uses this convention, there should be a README file in the directory /etc/init.d explaining how these scripts work.
CentOS 6 (upstart)
$ cat /etc/issue CentOS release 6.4 (Final) Kernel \r on an \m
CentOS es un clon a nivel binario de Red Hat. Hasta la versión 5 utilizaba SysVinit, pero a partir de la 6 se reemplazó por upstart. La salida de ps reporta la siguiente información sobre init:
$ ps 1 PID TTY STAT TIME COMMAND 1 ? Ss 0:00 /sbin/init
Al igual que SysVinit en Debian 6, en CentOS 6 el binario init se encuentra en /sbin/init
:
$ ll /sbin/init -rwxr-xr-x 1 root root 150352 Jun 25 05:50 /sbin/init
Aunque al abrir el manual de init (man init
), podemos ver que en realidad se trata de Upstart:
init(8) init(8) NAME init - Upstart process management daemon SYNOPSIS init [OPTION]... DESCRIPTION init is the parent of all processes on the system, it is executed by the kernel and is responsible for starting all other processes; it is the parent of all processes whose natural parents have died and it is responsible for reaping those when they die. Processes managed by init are known as jobs and are defined by files in the /etc/init directory. See init(5) for more details on configuring Upstart. Events init(8) is an event-based init daemon. This means that jobs will be automatically started and stopped by changes that occur to the system state, including as a result of jobs starting and stopping.
Mageia 2 (systemd)
# cat /etc/issue Mageia release 2 (Official) for i586 Kernel 3.4.52-desktop-1.mga2 on an i686 / \l
Mageia (distro de origen francés perteneciente la comunidad y derivada de Mandriva) al igual que la mayoría de las distribuciones de punta (en lo que se refiere a actualizaciones) utiliza systemd.
La salida de ps reporta init:
# ps 1 PID TTY STAT TIME COMMAND 1 ? Ss 0:00 /sbin/init
Aunque en realidad /sbin/init
es un link simbólico al binario de systemd:
# ll /sbin/init lrwxrwxrwx 1 root root 22 Oct 4 00:48 /sbin/init -> ../lib/systemd/systemd*
El manual de init (man init
) corresponde con el manual de systemd:
SYSTEMD(1) systemd SYSTEMD(1) NAME systemd, init - systemd System and Service Manager SYNOPSIS systemd [OPTIONS...] init [OPTIONS...] {COMMAND} DESCRIPTION systemd is a system and service manager for Linux operating systems. When run as first process on boot (as PID 1), it acts as init system that brings up and maintains userspace services. For compatibility with SysV, if systemd is called as init and a PID that is not 1, it will execute telinit and pass all command line arguments unmodified. That means init and telinit are mostly equivalent when invoked from normal login sessions. See telinit(8) for more information. When run as system instance, systemd interprets the configuration file system.conf, otherwise user.conf. See systemd.conf(5) for more
¿Cómo controlar servicios en las tres variantes?
Como "viejo" admin GNU/Linux estoy acostumbrado a usar el tradicional comando service
para iniciar/detener/reiniciar servicios, un clásico de Red Hat. El comando service se utiliza para ejecutar un script SysV localizado dentro del directorio /etc/init.d/
. Por ejemplo, para reiniciar el servicio Cron (script "cron") en Debian 6 es posible ejecutar:
# service cron restart Restarting periodic command scheduler: cron.
Esto equivale a ejecutar directamente el script especificando la ruta al mismo:
# /etc/init.d/cron restart Restarting periodic command scheduler: cron.
A pesar de utilizar diferentes procesos de inicialización, las distribuciones GNU/Linux mantienen los scripts de inicialización System V dentro del directorio /etc/init.d/
. Por lo tanto en CentOS 6 con Upstart, también se puede utilizar el comando service
para controlar un servicio:
# service crond restart Stopping crond: [ OK ] Starting crond: [ OK ]
O ejecutar directamente el script:
# /etc/init.d/crond restart Stopping crond: [ OK ] Starting crond: [ OK ]
Aunque los procesos gestionados por Upstart no poseen un script de inicialización estilo System V, sino que se definen en mediante archivos de configuración dentro del directorio /etc/init/
. Por lo tanto no es posible utilizar el comando service
para controlar estos demonios, sino que se debe utilizar el comando initctl
.
initctl
La herramienta initctl
permite a un administrador de sistemas GNU/Linux comunicarse e interactuar con el proceso init. La instrucción list
permite listar instancias y tareas (jobs) gestionadas por init.
# initctl help Job commands: start Start job. stop Stop job. restart Restart job. reload Send HUP signal to job. status Query status of job. list List known jobs. Event commands: emit Emit an event. Other commands: reload-configuration Reload the configuration of the init daemon. version Request the version of the init daemon. log-priority Change the minimum priority of log messages from the init daemon usage Show job usage message if available. help display list of commands For more information on a command, try `initctl COMMAND --help'.
Por ejemplo, es posible listar las tareas mediante la instrucción list
:
# initctl list rc stop/waiting tty (/dev/tty3) start/running, process 3486 tty (/dev/tty2) start/running, process 3484 tty (/dev/tty6) start/running, process 3493 tty (/dev/tty5) start/running, process 3490 tty (/dev/tty4) start/running, process 3488 plymouth-shutdown stop/waiting control-alt-delete stop/waiting rcS-emergency stop/waiting readahead-collector stop/waiting kexec-disable stop/waiting quit-plymouth stop/waiting rcS stop/waiting prefdm start/running, process 3477 init-system-dbus stop/waiting readahead stop/waiting splash-manager stop/waiting start-ttys stop/waiting readahead-disable-services stop/waiting rcS-sulogin stop/waiting serial stop/waiting
Documentación oficial de Upstart en ubuntu.com
En Mageia 2 con systemd sucede algo similar. Aquellos servicios que aún se gestionan con scripts System V se pueden controlar con el comando service
:
# /etc/init.d/crond restart Restarting crond (via systemctl): [ OK ]
O ejecutar directamente el script:
# service crond restart Restarting crond (via systemctl): [ OK ]
Aunque los servicios gestionados por systemd no poseen un script de inicialización estilo System V, sino que se denominan "unidades" (units) definidas dentro de los directorios /etc/systemd/system
y (con menor prioridad) /lib/systemd/system
. Por lo tanto no es posible utilizar el comando service
para controlar estos demonios, sino que se debe utilizar el comando systemctl
.
systemctl
systemctl
es la herramienta principal para controlar a init. Combina las funcionalidades de service
y chkconfig
en una única herramienta, la cual se puede utilizar para iniciar/detener servicios o para habilitar/deshabilitar permanentemente.
Utilizando systemctl
es posible reiniciar el servicio crond de la siguiente forma:
Buscar la unidad que define al servicio cron mediante la instrucción "list-units":
# systemctl list-units | grep cron crond.service loaded active running Command Scheduler
Reiniciar el servicio mediante la instrucción "restart":
# systemctl restart crond.service
Documentación de systemd en la wiki de fedoraproject.org