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


Tal vez pueda interesarte


Compartí este artículo