¿Quién teme al systemd feroz?

, , 5 comments
(no era éste el artículo que quería publicar como primero de Linux Técnico, pero es mejor que seguir otros seis meses sólo con el artículo de bienvenida :-))

(pequeña actualización: hice este artículo en Google Docs y luego corté y pegué aquí, y eso ha cambiado un poco el formato del texto; estoy arreglándolo, y si ven algo extraño que no habían visto antes, posiblemente sea por eso; si el artículo aparece de nuevo en su lector RSS, también será por eso; disculpas por adelantado)
Aprendimos que en UNIX init es el PID 1, el proceso que lanza todos los demás. Y fue así durante mucho tiempo, pero apareció Ubuntu y, entre otras herejías (como Unity), decidió programar su propio init y llamarle upstart. Por si no fuera suficiente, ahora hay otro contendiente, systemd. Y entre otras cosas, quiere quitarnos a syslog.


Un proceso para gobernarlos a todos

En los viejos tiempos de los UNIXes tradicionales, no había discusión: el kernel arrancaba y lanzaba init, el proceso padre de todos los procesos, el demiurgo del sistema. Luego init se las componía por su cuenta para lanzar el resto de procesos.

Ya en aquellos tiempos había desacuerdos sobre cómo hacer esto. En concreto, las escuelas de BSD y System V defendían formas distintas de lanzar los procesos en el arranque. Si sólo has usado Linux, sólo habrás usado algo tipo BSD si llegaste a probar Slackware o Arch Linux (Gentoo, para variar, usa algo que no es ni BSD ni System V); si no, todo lo que has visto es System V (o SysV, para abreviar).

La forma en que arranca el sistema BSD es la más primitiva y menos flexible, y también la primera en aparecer. Todo se lanza desde /etc/rc, un script shell. Ahí pones todo lo que quieres que haga el sistema al arrancar, como en el AUTOEXEC.BAT de MS-DOS. Los BSDs han parcheado el sistema inventándose un /etc/rc.conf en el que hay variables que definen qué es lo que se arranca y lo que no, para que no haya que tocar /etc/rc. ¿Y sabes esa cosa tan moderna de los runlevels, que tienen los UNIX desde hace veinte años? No existe en este tipo de arranque. Es un concepto SysV, pero tan extendido que ya se acepta como estándar.

En SysV, el proceso init tiene un fichero de configuración: /etc/inittab. Por qué ese fichero tiene un formato tan extraño y críptico no lo sé, pero es una de esas herencias molestas que nos han tocado. En ese fichero se definen varios runlevels, niveles de ejecución que corresponden a las distintas fases por las que pasa el sistema: runlevel 1 (o “S”, de single user) es el arranque, y de ahí hacia arriba se pasa por varios runlevels hasta llegar al runlevel 6, que es un reinicio. El runlevel 0 es para apagar el sistema. De los runlevels entre el 1 y el 6, el 4 no se usa, y las distribuciones adoptan como el runlevel “normal” el 2, el 3 o el 5. No hay un estándar: Debian usa el 2, y Red Hat y derivadas usan cada uno para algo diferente (2 para arranque multiusuario sin red, 3 para arranque multiusuario con red pero sin interfaz gráfico, y 5 para el escritorio full blown).

Además, para SysV se inventó el directorio /etc/init.d, donde los servicios del sistema tienen un script de control que se ejecuta de forma diferente en cada runlevel. Para eso, hay directorios /etc/rcX.d, donde “X” es el número del runlevel, y en ellos están enlazados los scripts de /etc/init.d. Cada vez que se entra a un nuevo runlevel, se ejecutan los scripts del directorio correspondiente con un argumento “start” o “stop”, dependiendo del runlevel (“start” para 2, 3 y 5; “stop” para 0 y 6).

En ambos casos es el mismo proceso init el que inicia todo. De hecho, hasta hace unos pocos años el código fuente de init era el mismo en todas las distribuciones (el init de GNU). Hasta que alguien suficientemente atrevido y sin respeto por las tradiciones decidió que era hora de hacer algún cambio.

upstart
Hubo otros antes de upstart, como initng, pero éste fue el único suficientemente popular como para significar algo en el mundo Linux. Creado por y para Ubuntu, viene de serie desde la versión 6.10. Al principio era una sustitución pura y dura de init, que hacía exactamente lo mismo que el tradicional, sin afectar al resto del sistema. Pero en la versión 9.10 cambiaron las cosas, y se empezó a usar de forma nativa.

Si hacemos un “ps aux” en una Ubuntu moderna no veremos un proceso “upstart”, sino un “/sbin/init”, como en cualquier otra distribución. Pero si buscamos ese fichero en los paquetes del sistema, veremos que viene en el paquete upstart:

robe@raven:~$ dpkg -S /sbin/init
upstart: /sbin/init
Y sobre todo, notaremos una gran diferencia:
robe@raven:~$ ls /etc/inittab
ls: cannot access /etc/inittab: No such file or directory
Como decía la canción, “se fue, se fue”. Con upstart ya no existe /etc/inittab, sino un directorio /etc/init en el que hay un fichero de configuración (“*.conf”) por cada servicio del sistema. Y son muchos: aparte de los procesos típicos, upstart también se encarga de levantar la red, montar los discos, activar las TTYs y configurar la consola. En Ubuntu 11.10 muchos programas ya han migrado su script en /etc/init.d a un fichero de configuración de upstart, y es de esperar que en algún momento /etc/init.d y los directorios /etc/rcX.d desaparezcan.

Como los ficheros de /etc/init.d dejan de servir, para lanzar, parar y consultar el estado de los servicios hay tres nuevos comandos: start, stop y status. Así como te lo cuento. Para lanzar ssh, harías:

start ssh
Y para ver si está funcionando:
robe@raven:~$ status ssh
ssh start/running, process 1322
Fundamental en el diseño de upstart son los eventos. A diferencia de init, que lanzaba los procesos siguiendo una secuencia prefijada en /etc/inittab, upstart reacciona a eventos que genera el sistema o él mismo. Todos los ficheros de configuración de upstart contienen una línea “start on” y “stop on”, seguida de uno o varios eventos del sistema. Por ejemplo, /etc/init/mountall.conf viene con éstas:
start on startup
stop on starting rcS
Que significa: empieza cuando detectes el evento “startup”, y detente cuando detectes que está lanzándose el proceso rcS. upstart se basa en estas líneas para determinar las dependencias entre servicios, y paraleliza el arranque todo lo que puede. Por eso, al menos durante un tiempo, Ubuntu fue la distribución con arranque más rápido.

Pero no sólo se usan eventos durante el arranque y la parada del sistema. Puedes generar un evento en cualquier momento, usando “initctl emit <nombre del evento>”, y crear un fichero de generación que haga cualquier cosa para reaccionar a él.

systemd
Y cuando estábamos empezando a aceptar que upstart podía ser algo bueno, a pesar de ser tan distinto del init tradicional, viene un tío de Red Hat y dice que tiene una opción diferente llamada systemd.

De systemd apenas sé nada, pero fue una discusión sobre él lo que hizo que escriba este artículo. Implica muchos cambios en init, pero aparte se mete con otra vaca sagrada de UNIX: syslog. Sí, systemd también quiere sustituir a syslogd. Y no sólo eso: pretende que los logs del sistema sean binarios.

Puede que esta idea les haya hecho abrir los ojos como platos y blindar su mente ante ella. Pasar de los logs en texto, tan maleables y manejables, a “algo” binario que requerirá herramientas específicas para analizar, tiene todos los boletos para convertirse en un “WTF”. Pero si encima les digo que el autor es Lennart Poettering, el autor del infame Pulseaudio, posiblemente su sangre entre en ebullición y piensen lo mismo que yo: “es la hora de las tortas”.

Pero antes de ponerse los capuchones, ensillar los caballos y prender las antorchas, vamos a ver de qué va esto de systemd. Sólo por tener algún fundamento para nuestra ira, más que nada.

Para empezar, el (mastodóntico) artículo de presentación de systemd está aquí:

http://0pointer.de/blog/projects/systemd.html

Y una explicación en castellano, resumida y muy bien escrita (como todos los artículos de ese blog, por cierto) está aquí:

http://diegocg.blogspot.com/2010/05/systemd-otro-reemplazo-de-init.html

Muchos de los argumentos para crear systemd son los mismos que para upstart: necesidad de un sistema init más moderno, capaz de lanzar servicios en paralelo y reaccionar ante los cambios del sistema. Una vez que has aceptado que upstart es bueno, aceptar este razonamiento para justificar systemd es sencillo.

systemd también introduce varias mejoras respecto a upstart, en especial a la hora de arrancar sólo los servicios necesarios. La lógica es ésta: muchos procesos se comunican mediante sockets UNIX, y systemd crea esos sockets aunque los procesos que tendrían que escuchar en ellos no estén levantados. Si ningún proceso necesita escribir o leer en ese socket, nos hemos ahorrado la ejecución de un programa; y si lo hacen, systemd lo detecta y es entonces, y no antes, cuando levanta el proceso. Como cada socket tiene un buffer, puede haber varias escrituras en el socket antes de que esté levantado el proceso (por ejemplo, porque es el arranque del sistema y todavía no hemos levantado todos los procesos necesarios). Cuando esté listo, el proceso leerá el buffer y atenderá lo que tenga que hacer.

El “Journal”


Pero lo que me dolió, como les decía antes, era eso de sustituir syslogd. Lennart, que debe dedicarse a poco más que programar y escribir artículos muy extensos justificando lo que hace, tiene un texto con las explicaciones pertinentes aquí:

https://docs.google.com/document/pub?id=1IC9yOXj7j6cdLLxWEBAGRL6wl97tFxgjLUEHIX3MSTs&pli=1


El sustituto de syslog (tanto el protocolo como el proceso syslogd) se llama “Journal”. Su objetivo es solucionar los inconvenientes de syslog:


  • Falta de autenticación (cualquier proceso puede escribir diciendo que es otro cualquiera)
  • Heterogeneidad en el formato de las líneas de log
  • Falta de unificación de logs (cada aplicación lo hace en un sitio diferente)
  • No hay indexación de logs, que cuando crecen mucho significa que buscar algo puede ser muy lento
  • El protocolo de red es muy sencillo, vulnerable a pérdidas de paquetes y efecto Thundering Herd (cuando muchos logs vienen de repente contra un mismo sistema y crean un DoS)
  • Es fácil falsificar los logs en disco
  • Complejidad del rotado de logs
  • Falta de logs durante momentos críticos, como el arranque o la parada
  • No se pueden loggear datos binarios

Para solucionar todo esto, systemd tiene una lista de propósitos como simplicidad, zero maintenance, robustez, portabilidad, “performancia”, etc etc. Las mejores intenciones, vaya.

Los procesos que hagan logging contra Journal crearán “entradas”, no líneas como hasta ahora. En cada entrada hay sitio para todos los metadatos que hagan falta, porque están formadas por varias líneas: pares clave-valor con la clave en mayúsculas y un signo de subrayado antes de ella como marca de un cliente “fiable”. Un ejemplo:
_SERVICE=systemd-logind.serviceMESSAGE=User harald logged inMESSAGE_ID=422bc3d271414bc8bc9570f222f24a9_EXE=/lib/systemd/systemd-logind_COMM=systemd-logind_CMDLINE=/lib/systemd/systemd-logind_PID=4711_UID=0_GID=0_SYSTEMD_CGROUP=/system/systemd-logind.service_CGROUPS=cpu:/system/systemd-logind.servicePRIORITY=6_BOOT_ID=422bc3d271414bc8bc95870f222f24a9_MACHINE_ID=c686f3b205dd48e0b43ceb6eda479721_HOSTNAME=waldiLOGIN_USER=500
Este formato está inspirado por los ficheros de log tradicionales y por los repositorios git. Dice el artículo que, a pesar de que hay mucho más que escribir, esto no afectará negativamente al espacio que ocupen los logs en disco: aparte de que los campos de datos serán comprimidos antes de ser grabados en disco, cada clave será guardada como un objeto individual, y luego otras entradas que hagan referencia a ellas no tendrán que incluirlas explícitamente.

Como no podía ser de otra manera, hay una biblioteca para clientes que accedan al Journal. El acceso no será sólo secuencial, como con los logs de ahora, sino también indexado por clave y con acceso aleatorio. En mi opinión, ésta podría ser la killer feature que favoreciera la adopción rápida de Journal, como cualquiera que haya tenido que analizar un log de 1GB o más podrá entender. Por lo que entiendo al leer el artículo, también será fácil mezclar logs de varios sitios y sistemas distintos.

Conclusión
¿Es systemd malvado? Indudablemente. Pero aún así, es posible que acabemos usándolo todos, así que habrá que irse acostumbrando.

Después de leer algo más sobre systemd, estoy casi dispuesto a aceptar que hay muchas buenas ideas en su diseño. Todo lo relativo a paralelizar procesos en el arranque está bien, y la idea de los sockets si programas detrás es muy ingeniosa. En cuanto a syslog, por mucho que me duela reconocerlo, nadie puede negar que después de 30 años no necesita, como poco, alguna revisión.

Lo que no me ha gustado es la intransigencia de Lennart en cuanto a la “compatibilidad hacia atrás”. En la FAQ, ante preguntas del tipo “¿qué hago si necesito syslog?”, la respuesta siempre es “instalar un syslogd además de Journal”. Y de hecho, se menciona que The journal daemon does not speak the RFC syslog protocol, and it is unlikely it ever will. A mí me suena un poco a my way or the highway.

Veremos cómo avanza el tema. En el peor caso, tendremos una variedad todavía mayor entre distribuciones, con Ubuntu y upstart, Fedora/Red Hat y systemd, Debian entre dos aguas, incluyendo todas las variantes de init para que cada uno use la que más le guste, y Arch/Gentoo haciendo algo totalmente distinto.


(Actualización a 17/02/2012: OpenSUSE incorpora systemd de serie empezando en 12.1)

5 comentarios:

  1. journal reemplaza a syslogd (o la variante que use tu distribución). Los programas siguen llamando a syslog() para "logear" información. Journal es mucho más sencillo que syslogd, y no acepta todas son funciones (pero si las más importantes). Lo que dice Lennart es que es fácil ejecutar los dos a la vez, journal y syslogd. Con lo que si necesitas una funcionalidad que no esta en journal, puedes usar syslogd y listo. Yo diría que en vez de "my way or the highway" es más del estilo: Estoy haciendo un reemplazo de syslogd más sencillo y escalable. Con lo que no voy a implementar "todas" las opciones de syslogd. Con respecto a systemd, no solo replaza init, reemplaza (ahora) syslogd, y estaba reemplazando ConsoleKit y "posiblemente" gnome-session (o lo que sea que uses para entrar en las X). Básicamente ambas hacían lo mismo que hace init (systemd) pero para un usuario en vez de para un servicio, con lo que es fácil "unificarlos todos". Otra de las ventajas que no comentas en que journal garantiza que _no se pierden_ mensajes mientras "rearrancas" por cualquier razón el journal, con syslogd si los pierdes. (Por si aún no lo habías adivinado, creo que las ventajas de systemd son mucho mayores que las desventajas).

    ResponderEliminar
    Respuestas
    1. Gracias por el comentario :-)

      Pero no estoy de acuerdo. ¿Journal más sencillo que syslogd? Hombre, más potente quizás, pero más sencillo ...

      Acepto que tiene muchas ventajas, pero no me ha gustado que intente abarcar tanto ni que deje de lado a la gente que necesite syslog. Puede que sea un protocolo obsoleto, pero es un estándar y por eso merecería la pena que hubiera, al menos, ciertos visos de compatibilidad hacia atrás.

      Pero bueno, ya veremos qué pasa. Posiblemente lo pruebe (en un entorno controlado :-)), y para equipos con muchos, muchos logs, seguro que es mejor que lo que hay ahora.

      Eliminar
  2. Ya era hora!

    Veremos en que queda todo esto, espero que no signifique más guerras entre las distros, sino simplemente más opciones mientras que no hay un triunfador claro.

    Por cierto: Buena suerte con el Blog.

    ResponderEliminar
    Respuestas
    1. Antes de nada, gracias por el comentario y los buenos deseos :-)

      No tengo tan claro que signifique sólo más opciones. RH ahora tiene el papel que tiene MS, pero en Linux: lo que impongan ellos es lo que va a misa. A nivel corporativo, al menos: las empresas que tienen Linux y quieren una distribución "enterprise" tiran por RHEL o Suse, y no veo a Suse haciendo grandes innovaciones. Eso significa que habrá tres variantes mayoritarias de init: upstart (Ubuntu), systemd (RHEL/CentOS/Fedora) y lo que usen en Suse (que me parece que es el init de toda la vida).

      Donde sí que significará más opciones es en Debian, que tiene paquetes para todos :-) Pero a menos que haya un cambio a nivel oficial (que se cambie el init y el sistema de arranque de ahora por otro), tampoco creo que mucha gente lo cambie de motu propio. No es algo trivial.

      Eliminar
  3. Falta de autenticación (bien )
    Heterogeneidad en el formato de las líneas de log (bien todos los logs tienen que ser iguales no que uno dice primero la hora y otro dice la accion que se ejecuto )
    Falta de unificación de logs (bien siempre tenia que andar buscando donde esta el log de esto o de esto)
    No hay indexación de logs, que cuando crecen mucho significa que buscar algo puede ser muy lento(bien uno va ha buscar mas rapido que fue lo que paso ha esta hora, porque se cayo)
    El protocolo de red es muy sencillo, vulnerable a pérdidas de paquetes y efecto Thundering Herd (cuando muchos logs vienen de repente contra un mismo sistema y crean un DoS)(bien, eran como las enfermedades del Sr burns ninguna hacia nada porque todas querian hacer lo mismo a la vez)
    Es fácil falsificar los logs en disco(uff hago una copia de el original, luego hago los cambios que quiero,borro el nuevo log,y pego el original, nadie se daba cuenta de lo que hice)
    Complejidad del rotado de logs(esto no me preocupa mucho si ya estan indexados va ha ser facil buscar algo)
    Falta de logs durante momentos críticos, como el arranque o la parada(que paso porque antes aranco rapido y luego lento, "aaah aqui esta el problema")
    No se pueden loggear datos binarios (llego mi jefe no puedo escribir mas)

    ResponderEliminar