Migrando a systemd en ArchLinux

Saturday 1 de September de 2012, 11:57 am 230 Comments

Aunque ya son meses de planes y avisos, hace apenas un par de semanas se dió a conocer que ArchLinux reemplazará sysvinit (así como initscripts) por systemd, lo cual ha causado mucha polémica. El cambio ha sido gradual: Hace tres meses, udev fue reemplazado por (fusionado en) el paquete systemd-tools, y hace apenas unas horas este último, al igual que libsystemd, acaban de ser reemplazados por el mismísimo paquete systemd. La migración definitiva está muy próxima, ¡debes estar preparado!

Si eres usuario de ArchLinux seguro te estás preguntando: ¿Debemos migrar en este momento?, ¿qué implica usar systemd?, ¿qué ventajas me ofrece con respecto a sysvinit?, o peor aún, ¿qué rayos es eso de systemd y sysvinit?

Luego de haber leído bastante documentación (referencias al final de este post) y de haber realizado varias pruebas (primero en una máquina virtual y luego en mi sistema principal), trataré de responder a cada una de esas preguntas.

Un poco de historia

En los sistemas operativos basados en UNIX (Linux, FreeBSD, MacOS X, etc) existe un proceso especial, el primero generado por el kernel y en ejecutarse durante el booteo, conocido como init (el cual obviamente tiene el PID número 1), el cual se encarga de ejecutar el resto de los procesos del sistema, e incluso sigue activo como daemon (comunicándose constantemente con el kernel) hasta que el usuario apaga o reinicia el equipo, momento en que dicho proceso ejecuta todo lo necesario para cerrar el sistema.

Desde sus inicios, y hasta la fecha, la mayoría de las distros de Linux utilizan sysvinit. A primera vista podemos darnos cuenta que su nombre proviene de SysV init, o UNIX System V init system, con lo cual nos damos una idea de lo veterano que es este proceso de inicialización (por no decir viejo y obsoleto).

¿Qué alternativas modernas existen?

  • Existe launchd, pero es exclusivo del sistema MacOS X.

  • En 2006 fue liberado Upstart, desarrollado por Scott James Remnant (ex empleado de Canonical, ahora trabaja en Google). Este proceso es usado principalmente por Ubuntu y Chrome OS. Algunas otras distros, como Fedora, lo implementaron en algunas de sus versiones, pero han optado por una mejor opción (sigue leyendo).

  • ¡Y llegó systemd!, liberado apenas en 2010. Su desarrollador principal es Lennart Poettering, creador del conocido PulseAudio (actualmente labora para RedHat). Debido a sus fantásticas características, hoy día es usado de manera predeterminada en distros populares como Fedora y OpenSUSE, por lo que podemos inferir que, a pesar de su corta vida, systemd ya está listo para nivel producción.

Beneficios de systemd

Los principales beneficios de systemd comparado con sysvinit / initscripts son:

  • Tiene capacidades “hotplug”, o sea, systemd asume que todos los recursos del sistema pueden aparecer o desaparecer en cualquier momento. Si conectamos un disco duro externo después de que systemd ha iniciado, se encargará de aplicarle fsck y montarlo correctamente, a diferencia de initscripts que necesita que todos los discos se encuentren enumerados y listos cuando ejecuta fsck para luego montarlos.

  • Podemos saber el estado del sistema en cualquier momento, ya que systemd lleva un registro (journal) mediante cgroups (ya no más PIDs) de todos los daemons y procesos que ha iniciado, quién es el dueño, cuál ha fallado, etc.

  • Es modular. Todo el contenido ejecutado por initscripts en /etc/rc.sysinit ahora es dividido en varios servicios independientes, cada uno de ellos bien documentado y de fácil comprensión. ¡Puedes crear tus propios servicios!

  • Actualmente udev (que incluso ha sido fusionado en systemd) y dbus son usados (inapropiadamente) para iniciar daemons y servicios sobre demanda. Con systemd todo ese trabajo está cubierto, pues es una de sus funciones principales.

  • Actualmente debemos especificar y tener mucho cuidado en el orden de los daemons en la sección DAEMONS del archivo /etc/rc.config. Con systemd se utiliza la activación de daemons por medio de sockets, aportando capacidades de paralelización.

  • Actualmente es bastante complicado implementar seguridad vía sandboxing a cada script rc (/etc/rc.sysinit,/etc/rc.single,/etc/rc.multi, etc). Con systemd sólo necesitamos agregar unas simples opciones de configuración a los archivos de cada unit (de las cuales hablaré más adelante) para aislarlas del sistema de diversas maneras.

  • Los archivos de servicio de systemd pueden ser escritos y distribuidos por cualquier usuario, en vez de los scripts rc escritos específicamente para cada distro. De esta manera, la colaboración entre usuarios y desarrolladores de systemd puede lograr la creación de servicios “perfectos”, que deberían funcionar en cualquier distro.

  • Por origen, systemd es un proyecto “cross-distro“, donde colaboran desarrolladores de todas las grandes y muchas pequeñas distros.

  • Y como ya se lo pueden imaginar, ¡systemd es muy rápido!. Es notable la reducción del tiempo al momento del booteo, incluso al cerrar el sistema es mucho, ¡pero mucho más rápido! (comparado con sysvinit/initscripts, por supuesto). Toda esta velocidad es básicamente un “efecto secundario” de todas las bondades descritas en los puntos anteriores.

La lista anterior no es exhaustiva, ¡hay más beneficios al usar systemd!

Preparando nuestro ArchLinux para systemd

Seguro que después de haber leído la lista anterior quieres salir corriendo para instalar systemd… ¡no lo hagas! Antes necesitas preparar tu sistema antes de la migración.

Lo primero que debemos hacer, es revisar nuestro querido y viejo archivo /etc/rc.conf (el cual es usado por initscripts), pues prácticamente ya no será utilizado con systemd, por lo que debemos migrar toda las configuraciones ahí contenidas por el nuevo esquema de configuración:

  • El valor de HOSTNAME ahora se establece en el archivo /etc/hostname (el nombre de nuestro hostname, por ejemplo localhost, es lo único que debe tener dicho archivo). También hay que ajustar el archivo /etc/hosts para que coincidan.

  • El valor de TIMEZONE ahora se establece por medio de un symlink de /etc/localtime a /usr/share/zoneinfo/<ZONA>/<SUBZONA> (reemplaza <ZONA> y <SUBZONA> según tu ubicación geográfica). Por ejemplo, para México:

    ln -s /usr/share/zoneinfo/America/Mexico_City /etc/localtime
  • Los valores de KEYMAP, CONSOLEFONT y CONSOLEMAP ahora se establecen en el archivo /etc/vconsole.conf (el cual debes crear).

    • KEYMAP especifica la distribución del teclado. Las opciones disponibles se encuentran en /usr/share/kbd/keymaps.

    • CONSOLEFONT especifica la fuente (tipo de letra) a usar en la consola (el programa setfont toma este valor durante el booteo). Las opciones disponibles se encuentran en /usr/share/kbd/consolefonts. También puede usarse FONT. Esta configuración es opcional.

    • CONSOLEMAP especifica el mapa de consola correspondiente, que también es leído por setfont. Las opciones disponibles se encuentran en /usr/share/kbd/consoletrans. También puede usarse FONT_MAP. Esta configuración es opcional.

    Por ejemplo:

    KEYMAP=es
    CONSOLEFONT=lat9w-16
    CONSOLEMAP=8859-1_to_uni
  • El valor de LOCALE (el cual especifica el idioma del sistema y de la mayoría de las aplicaciones) ahora se establece en el archivo /etc/locale.gen, donde debemos descomentar (eliminar el “#” al inicio de la línea) la localización deseada. Por ejemplo, para soporte UTF-8 en Español para México:

    ...
    #es_HN ISO-8859-1
    es_MX.UTF-8 UTF-8
    #es_MX ISO-8859-1
    ...

    Para aplicar los cambios realizados, debemos ejecutar el comando locale-gen.

    También es buena idea establecer dicho valor con la variable LANG en el archivo /etc/locale.conf, donde también podemos establecer otros valores interesantes, como LC_COLLATE, que especifica cómo se ordenan los archivos al ejecutar el comando ls. Ejemplo:

    LANG="es_MX.UTF-8"
    LC_COLLATE="C"
  • Los valores (lista separada por espacios) de MODULES ahora deben establecerse en uno o más archivos del tipo <MODULO>.conf: En el directorio /etc/modules-load.d/ los módulos para ser cargados incondicionalmente durante el booteo, y en /etc/modprobe.d/ (normalmente usado por udev para cargar módulos sobre demanda) los módulos que no se auto ejecutarán (anteponiendo la palabra blacklist). Ejemplos:

    # /etc/modules-load.d/virtualbox.conf
    vboxdrv
    # /etc/modprobe.d/nobeep.conf
    blacklist pcspkr

Puedes poner varios módulos en un sólo archivo .conf, pero cada uno en una línea aparte.

¿Y los valores de DAEMONS? Esos no los cambiaremos por el momento (es lo único que debemos dejar habilitado en /etc/rc.conf). Lo que si haremos es tener muy presente qué daemons son los que ahí se encuentran. Posteriormente (luego de instalar systemd), migraremos cada daemon a su respectiva unidad de servicio (no se desesperen, ya llegaremos a este punto).

Instalación de systemd en ArchLinux

¡Por fin! Luego de tanta introducción y preparación, hemos llegado al punto clave, ¡instalemos systemd en nuestro querido ArchLinux!

  1. Antes que nada, ¡actualiza tu sistema!

    sudo pacman -Syu
  2. Ya debes tener instalado el paquete systemd (vuelve a leer el primer párrafo de este post). De todas formas, lo puedes instalar con el comando:

    sudo pacman -S systemd
  3. A pesar de que ya instalamos systemd, si reiniciamos nuestro equipo, de nuevo sysvinit e initscripts se ejecutarán, ya que aún estamos en un “esquema mixto” (para ver que todo funciona bien). Lo que haremos entonces, es agregar init=/bin/systemd a los parámetros del kernel del bootloader que utilices.

    • Si usas Grub Legacy, edita el archivo /boot/grub/menu.lst y modifica la línea que inicia con kernel.

      title Arch Linux
      root (hd0,0)
      kernel /vmlinuz-linux root=/dev/sda3 ro quiet init=/bin/systemd
      initrd /initramfs-linux.img
    • Si usas Grub2, edita el archivo /etc/default/grub y modifica la línea que inicia con GRUB_CMDLINE_LINUX_DEFAULT.

      GRUB_DISTRIBUTOR="Arch Linux"
      GRUB_CMDLINE_LINUX_DEFAULT="quiet init=/bin/systemd"
      GRUB_CMDLINE_LINUX=""

      Es necesario actualizar Grub2 con el comando

      sudo grub-mkconfig -o /boot/grub/grub.cfg
    • Si usas syslinux, edita el archivo /boot/syslinux/syslinux.cfg y modifica la línea que inicia con APPEND.

      LABEL arch
      MENU LABEL Arch Linux
      LINUX ../vmlinuz-linux
      APPEND root=/dev/sda3 ro quiet init=/bin/systemd
      INITRD ../initramfs-linux.img

    ¡Nota! A pesar de que en los ejemplos incluí el parámetro quiet, es recomendable no incluirlo las primeras veces que iniciamos el sistema con systemd, para poder verificar que todo esté funcionando adecuadamente.

  4. ¡Reinicia el sistema! Ahora el proceso de booteo estará a cargo de systemd. ¿Algún problema? Ya que seguimos en un esquema mixto, puedes eliminar init=/bin/systemd de los parámetros del kernel para bootear nuevamente con sysvinit e initscripts, y así puedas corregir algún error.

    ¿Todo bien? ¡Sigue leyendo!

  5. ¿Recuerdas que mencioné que no olvidaras qué daemons teníamos en /etc/rc.conf? ¡Ahora es momento de migrarlos a systemd! Cada daemon debe tener su correspondiente unidad de servicio (las que explicaré a fondo en la siguiente sección), y cada una de ellas debemos habilitarlas (para que se ejecuten automáticamente al momento del booteo) por medio del comando:

    sudo systemctl enable <NOMBRE_DEL_SERVICIO>.service

    Algunos ejemplos (daemons con sus respectivas unidades de servicio):

    • network (Conexión ethernet por DHCP)

      sudo systemctl enable dhcpcd@eth0.service
    • networkmanager (Reemplazo de network)

      sudo systemctl enable NetworkManager.service
    • wicd (Reemplazo de network, más ligero que networkmanager)

      sudo systemctl enable wicd.service
    • crond (Programación de eventos)

      sudo systemctl enable cronie.service
    • cupsd (Common UNIX Printing System)

      sudo systemctl enable cupsd.service
    • ntpd (Cliente y servidor del Network Time Protocol)

      sudo systemctl enable ntpd.service
    • samba (Servicios de archivos e impresión para clientes de Microsoft Windows)

      sudo systemctl enable smbd.service
    • nginx (Servidor Web Nginx)

      sudo systemctl enable nginx.service
    • mysqld (Servidor de Base de Datos MySQL)

      sudo systemctl enable mysqld.service
    • postgresql (Servidor de Base de Datos PostgreSQL)

      sudo systemctl enable postgresql.service
    • gdm (Gnome Display Manager)

      sudo systemctl enable gdm.service
    • kdm (KDE Display Manager)

      sudo systemctl enable kdm.service
    • slim (Simple Login Manager, ¡mi preferido!)

      sudo systemctl enable slim.service

    Algunas observaciones muy importantes:

    • Algunos daemons no tenemos que habilitarlos explícitamente, como es el caso de dbus y netfs.

    • Algunos daemons desgraciadamente aún no tienen unidades de servicio (como dropboxd y httpd). Si no puedes prescindir de ellos, te recomiendo continúes con el esquema mixto (para que sigan siendo llamados desde la línea DAEMONS del archivo /etc/rc.conf), hasta que hayan sido implementados, lo cual no debe demorar mucho tiempo… ¡hay que ser pacientes!

    • El daemon syslog-ng (que normalmente es el primero en la línea DAEMONS del archivo /etc/rc.conf), causa conflictos con el nuevo syslog.socket, por lo que es necesario eliminarlo de la lista si planeamos seguir con el esquema mixto.

    Cuando estés seguro que ya no ejecutas ningún daemon especificado en el archivo /etc/rc.conf, entonces éste deja de tener utilidad. Te recomiendo hacerle un respaldo para recordar a nuestro viejo amigo, que tantos años nos acompañó.

  6. ¿Tienes personalizados los archivos /etc/rc.local y/o /etc/rc.local.shutdown? ¡Debes convertirlos a unidades de servicio! Pero ya que aún no sabemos cómo hacer eso, podemos darles soporte usando unas unidades de servicio especiales que llaman a ambos archivos.

    cp /usr/lib/systemd/system/rc-local{,-shutdown}.service /etc/systemd/system/
  7. Reinicia el sistema nuevamente. Si hay algún error, verifica de nuevo los pasos previos. ¿Todo bien? ¡Sigue leyendo!

  8. Cuando ya todo funcione perfectamente, ya podemos dar el paso definitivo del esquema mixto a un sistema systemd puro, y eso lo logramos instalando el paquete systemd-sysvcompat, el cual al mismo tiempo eliminará sysvinit e initscripts (éste último es probable que previamente tengas que eliminarlo manualmente con pacman -R), y le aplicará un pacsave a rc.conf, rc.local and rc.local.shutdown.

    sudo pacman -S systemd-sysvcompat
  9. Ya podemos eliminar init=/bin/systemd de nuestro parámetro del kernel (lo que hicimos en el paso 4), ya que ahora /sbin/init es un symlink a systemd.

¡Eso es todo! Si gustas puedes reiniciar nuevamente, para disfrutar al 100% de systemd en tu ArchLinux.

¡Ya tengo systemd! ¿Y ahora qué?

¡Ahora muchas cosas han cambiado! Acciones como ejecutar daemons, cambiar de runlevel, revisar el log del sistema o usar pm-utils para suspender o hibernar, ahora tienen un enfoque diferente, básicamente nos estamos enfrentando a un nuevo paradigma. En la presente sección les mencionaré los conceptos básicos para que empiecen a familiarizarse con systemd.

Previamente he mencionado el término “unidades de servicio“, pero no había explicado de qué se trataban exactamente. Una unidad o unit, no es más que un archivo de configuración que contiene información no sólo de servicios (.service, los más comunes, nuestros conocidos daemons), si no también de sockets (.socket), dispositivos (.device), puntos de montaje (.mount), puntos de auto-montaje (.automount), e incluso grupos de otras unidades (.target).

Como dato adicional, es interesante saber que la sintaxis de la información contenida en los archivos de las unidades está inspirada en los archivos .desktop de la especificación XDG Desktop Entry, que a su vez estuvo inspirada por… wait for it… ¡los archivos .ini de Microsoft Windows!, ironías de la vida.

Los archivos de unidades disponibles en nuestro sistema podemos encontrarlos en /usr/lib/systemd/system/ y /etc/systemd/system/ (éste último directorio toma precedencia en caso de duplicados).

Básicamente estaremos trabajando con el comando systemctl para interactuar con las diversas unidades de systemd. Algunos comandos de uso común son:

  • Listar las unidades que se estén ejecutando actualmente.

    systemctl

    o bien,

    systemctl list-units
  • Listar las unidades con errores.

    systemctl --failed
  • Listar las unidades instaladas.

    systemctl list-unit-files
  • Activar una unidad inmediatamente.

    systemctl start <unit>
  • Desactivar una unidad inmediatamente.

    systemctl stop <unit>
  • Reiniciar una unidad.

    systemctl restart <unit>
  • Recargar la configuración de una unidad.

    systemctl reload <unit>
  • Mostrar el estado de una unidad, esté o no en ejecución.

    systemctl status <unit>
  • Verificar si una unidad está habilitada.

    systemctl is-enabled <unit>
  • Habilitar una unidad para ejecutarse en cada booteo.

    systemctl enable <unit>
  • Deshabilitar una unidad para que no se ejecute en cada booteo.

    systemctl disable <unit>
  • Mostrar la ayuda asociada a una unidad (si se encuentra disponible).

    systemctl help <unit>

En el caso de la administración de energía del sistema, también debemos usar el comando systemctl. Si nos encontramos en una sesión de usuario de ConsoleKit, podemos ejecutar los siguientes comandos sin necesidad de privilegios de root (a no ser que haya otra sesión activa):

  • Cerrar y reiniciar el sistema.

    systemctl reboot
  • Cerrar y apagar el sistema.

    systemctl poweroff
  • Cerrar y detener el sistema.

    systemctl halt
  • Suspender el sistema.

    systemctl suspend
  • Hibernar el sistema.

    systemctl hibernate

Ahora bien, los clásicos runlevels son un concepto de sysvinit, quien examinaba el archivo /etc/inittab (ahora obsoleto) para saber el valor de :initdefault:. El paradigma correspondiente en systemd son las unidades .target, que básicamente tienen el mismo propósito, pero con algunas diferencias, por ejemplo, cada target tiene un nombre, en vez de la clásica numeración de los runlevels:

  • Runlevel 0 = poweroff.target

  • Runlevel 1 = rescue.target

  • Runlevels 2, 3 y 4 = multi-user.target

  • Runlevel 5 = graphical.target

  • Runlevel 6 = reboot.target

Ejemplos de uso:

  • Para cambiarnos a otro target en la sesión actual (no afecta al siguiente booteo).

    systemctl isolate graphical.target
  • Para establecer un nuevo target predeterminado (el usado en cada booteo).

    systemctl enable multi-user.target

Por último, quisiera mencionarles un poco acerca del nuevo log del sistema, conocido como journal. Para revisarlo, basta usar el comando:

journalctl

El journal escribe en los archivos contenidos en el directorio /run/systemd/journal/, y por lo mismo, se pierden al reiniciar el sistema. Si deseamos logs persistentes, sólo debemos crear el directorio /var/log/journal/:

mkdir /var/log/journal/

¡Aclaración! En todos los comandos de esta sección omití el uso de sudo para facilitar la lectura de los comandos; no olviden incluirlo al inicio de ellos cuando sea necesario.

Referencias

Es importante que tomes en cuenta que todo lo expuesto en el presente post es meramente un resumen (si, ¡por largo que se vea!), y sólo describe los pasos generales al instalar y usar systemd en ArchLinux. Siempre habrán excepciones o casos especiales, por lo que les recomiendo leer, investigar y documentarse a fondo sobre el tema. Aquí les dejo una lista de referencias, que son las que usé para elaborar este tutorial.

Share

Post tags