ubuntuusers.de

systemd – Das Init-System

software.png

Einige Distributionen, allen voran Fedora, openSUSE und Arch Linux, verwenden schon das neue Init-System systemd. Dieser Artikel soll einen groben Überblick zu systemd liefern und zudem ein Vergleich zu Upstart beinhalten.

Was ist ein Init-System?

Beim Starten eines Rechners geschehen viele Dinge. Für viele ist bekannt, dass zuerst das sogenannte BIOS gestartet wird. Auf neueren Systemen kommt hingegen UEFI zum Einsatz. Beide sind zum Erkennen der installierten Hardware notwendig. Nach diesem Schritt wird der Bootloader gestartet, in der Regel ist GRUB 2 in Gebrauch. Dieser kümmert sich darum den Linux-Kernel und die Initial Ramdisk: zu laden. Nachdem auch dieser Vorgang abgeschlossen ist, folgt der Start des ersten „richtigen“ Prozesses auf einem Unix-System: Das Init-System.

Aufgabe dieses Init-Systems ist es, das System für den Benutzer in einen brauchbaren und definierten Zustand zu überführen: Ohne dieses würde man nur auf einer Shell sitzen, bei welcher die Übersetzung, Uhrzeit, Netzwerk oder viele andere Sachen fehlen würde. Auch ein Mehrbenutzerbetrieb wäre – mangels gestarteter Dienste hierzu – nicht möglich.

Um diesen definierten Zustand zu erreichen, folgt dieses Init-System bestimmten Regeln, welche beim gängigen SysVinit in Shellskripte niedergeschrieben sind. Dazu kommen noch einige Konfigurationsdateien der vielen Dienste, welche man heute auf einem modernen System vorfindet.

Geschichtliches

Im Laufe der Entwicklung hin zu modernen Unix-Systemen wurde vieles an grundlegender Software immer wieder modernisiert, dazu gehört auch das Init-System, welches für das Starten von Prozessen verantwortlich ist.

SysVinit

SysVinit ist ein sehr altes System zum Starten von Diensten, denn als Grundlage dient ein Design von 1983. Daher gibt es weder Abhängigkeiten, noch Events und so wird dieses System modernen Desktops und Notebooks nicht mehr gerecht. Dienste werden hier strikt der Reihe nach gestartet, unabhängig davon, ob diese parallel gestartet werden könnten.

SysVinit setzt auf viele Skripte, welche in weiten Teilen ähnliche oder sogar gleiche Aufgaben erledigen. Häufig benutzte Funktionen wurden aber mit der Zeit auf gemeinsam genutzte Skripte (Includes) ausgelagert, um zumindest im Ansatz dem DRY-Prinzip zu entsprechen.

Die Skripte können je nach Distribution an unterschiedlichen Orten, zum Beispiel /etc/rc.d oder /etc/init.d, liegen, und auch die Aktivierung und Deaktivierung von Diensten kann abhängig von der Distribution unterschiedlich erfolgen – zum Beispiel durch symbolische Links in /etc/rcX.d oder einem Eintrag in der /etc/rc.conf.

Für SysVinit ist es nicht zuverlässig möglich, Dienste sauber zu beenden. In der Regel wird das Skript entweder einen Prozess anhand seiner gespeicherten Prozess-ID beenden oder aber mit killall alle in Frage kommenden Prozesse beenden. Ausnahme hiervon sind Dienste, welche eine eigene Logik zum Beenden haben. Ein bekannter Dienst welcher sich beispielsweise nicht sauber beenden lässt, wäre NRPE, der für Monitoring über Nagios oder Icinga benötigt wird.

Upstart

Upstart ist eine relativ neue Entwicklung eines Init-Systems. Im Gegensatz zu dem nachfolgend beschriebenen systemd, welches mit Abhängigkeiten arbeitet, wird hier alles über Events geregelt. Upstart ist der erste Schritt zur Vereinfachung der Init-Skripte, welche nun unter /etc/init liegen. Ein weiterer Unterschied ist, dass zum Deaktivieren eines Services die Events im Init-Skript deaktiviert werden müssen (bis Version 1.3). systemd arbeitet hier wie auch schon SysVinit mit Symbolischen Verknüpfungen.

Upstart greift bei weitem nicht so tief in ein vorhandenes System ein. Unter anderem wird auch nicht verlangt Konfigurationen über bestimmte, vorgegebene, Konfigurationsdateien zu erledigen. Die Dokumentation wurde vor allem in den letzten Versionen stark ausgebaut. Dies war früher ein häufiger Kritikpunkt.

Upstart wurde neben Ubuntu auch eine Zeit lang von anderen Distributionen wie zum Beispiel Fedora verwendet. Viele Entwickler sind aber nicht bereit an Upstart mitzuentwickeln, da Canonical hierzu eine Beitragszustimmung 🇬🇧 verlangt.

OpenRC

Neben systemd, SysVinit und Upstart gibt es auch noch OpenRC, welches häufig bei Gentoo-Systemen verwendet wird. OpenRC wird in diesem Artikel der Einfachheit halber nicht weiter beschrieben.

Was ist systemd?

systemd ist ein neues Init-System, welches alle Möglichkeiten des Linux Kernels optimal ausnutzt und auf einige alte Konzepte verzichtet. Es wird weder bestehender Code verwendet, noch ist es zu bestehenden Init-Systemen kompatibel. systemd wird von Lennart Poettering entwickelt, welcher unter anderem für PulseAudio, Avahi und einige andere Programme verantwortlich ist, die bekannt und teilweise auch umstritten sind.

Ziel der Entwicklung ist es, ein Init-System zu schaffen, welches für den Anwender nachvollziehbar handelt, zuverlässig funktioniert und gleichzeitig einige Unzulänglichkeiten bisheriger Systeme behebt.

Die Vor- und Nachteile von systemd

systemd-analyze.png
Visualisierung der Aktivitäten, die systemd ausführt.

Vorteile

  • Die Arbeitsweise wird von vielen kleinen Skripten (SysVinit) nach systemd, also einem Skript, verlagert. Der Administrator beschäftigt sich also nicht mehr mit dem Schreiben von Init-Skripten, sondern erstellt lediglich Anweisungen („Unit Files”) wie ein Programm zu starten ist und welche Abhängigkeiten dieses hat.

  • systemd kann genau feststellen, ob ein bestimmter Dienst läuft und kann diesen darüber hinaus auch zuverlässig beenden.

  • Runlevel, bei systemd eigentlich Targets, können unabhängig von der aktuellen Position und unabhängig davon, ob andere Dienste zwischendurch gestartet oder beendet wurden, zielsicher erreicht werden. Gehört zum Beispiel zu einem Target „serverbetrieb.target“ kein Apache, wird dieser beim Wechsel vom Target „privatstuff.target“ zuverlässig beendet, und dafür gegebenenfalls ein anderer Dienst aktiviert.

  • Socket Activation: systemd ist in der Lage Dienste erst zu starten, wenn dies tatsächlich erforderlich ist. Dies ist vor allem hilfreich für Maschinen aus der Softwareentwicklung, welche wohl nicht immer alle Dienste benötigen, diese aber gerne bei Bedarf automatisch gestartet hätten.

  • Einheitliche Konfigurationsdateien: systemd definiert genau wo welche Informationen konfiguriert werden müssen, das heißt, dass sich jede Distribution mit systemd zu weiten Teilen gleich verhält – was zumindest Dienste angeht, Paketverwaltungen und Co. bleiben hiervon unberührt.

  • Dienste, welche nicht selbstständig in einen anderen Benutzerkontext wechseln, können dies in Zukunft ohne sudo oder su erledigen, da systemd hierzu Funktionen bereitstellt.

  • systemd kann sich zur Laufzeit durch eine neuere Version ersetzen, ein Neustart für ein Sicherheitsupdate oder neue Features am Init-System sind also nicht nötig.

Nachteile

  • systemd läuft nur auf einem Kernel, welcher bestimmte Features wie zum Beispiel Control Groups bereitstellt. Dies ist aktuell ausschließlich bei Linux der Fall, eine Portierung auf andere Unix-Derivate ist aktuell nicht geplant und daher unwahrscheinlich.

  • Bruch mit Bestehendem: systemd stellt zu weiten Teilen einen kompletten Neuanfang dar. Dies bedeutet aber auch, dass Bekanntes so nicht mehr funktioniert und ein Umdenken beim Anwender erforderlich ist.

  • systemd verlagert die Komplexität von vielen kleinen Skripten in eine zentrale Software.

journald

journald ist ein Teil von systemd und ist ein Ersatz für den bestehenden Syslog- und logrotate-Dienst. Nachteil ist, dass die Logdateien in einem bisher nicht dokumentiertem binärem Format, das nicht von Menschen gelesen werden kann, abgespeichert werden und somit ein Zugriff mittels den Tools wie less, more oder grep nicht mehr möglich ist.

journald definiert darüber hinaus aber auch die Möglichkeit, Metadaten in Logdateien zu schreiben oder Logdateien zu signieren (FSS). Das sorgt in manchen Anwendungsfällen dafür, dass Logdateien nicht manipuliert, aber dennoch auffällig gelöscht werden können.

Ebenfalls wurden bei journald einige Kritikpunkte der bisherigen syslog/logrotate-Lösung behoben. So war es möglich, dass diese einem das Dateisystem voll schreiben – journald passt hier automatisch auf – oder das Informationen über viele Dateien verstreut liegen. Zugriff auf diese Logfiles erfolgt über das Tool journalctl, welches auch einem normalen Benutzer das vollständige Systemlog anzeigt, sofern man Mitglieder der Gruppe adm ist.

systemd

systemd arbeitet anders. Es beschäftigt sich nur noch mit Abhängigkeiten und nicht mit Events und der Frage wie etwas zu tun ist. Beim Start des Systems laufen viele Prozesse gleichzeitig. Units werden, wenn möglich, gleichzeitig gestartet und die verschiedenen Targets bis zum gewünschten Ziel automatisch anhand der Konfiguration durchlaufen.

Anwendung

Eine kleine Liste gängiger Aktionen:
Auf Links wie zum Beispiel start oder stop, welche die Distributionen oft verwenden, haben wir verzichtet:

Aktionen im Vergleich
Aktion SysVinit upstart systemd
Dienst starten /etc/init.d/dienstname start initctl start dienstname systemctl start dienstname.service
Dienst aktivieren Symlink in rcX.d Manipulation Job oder Override File systemctl enable dienstname.service
Dienst neustarten /etc/init.d/dienstname restart initctl restart dienstname systemctl restart dienstname.service
Dienst ändern Modifikation des Init-Skripts Modifikation Job oder Override File Überschreiben des Distributorskripts in /etc
Runlevel ändern telinit runlevel telinit runlevel systemctl isolate runlevel.target

Auf den ersten Blick sind so kaum Vorteile ersichtlich, sehen wir uns dies aber mal etwas genauer an:

  1. SysVinit erfordert in jedem Skript eine bestimmte, aber unterschiedliche Logik zum Starten, Neustarten und Beenden des Dienstes

  2. Upstart erfodert zum Aktivieren/Deaktivieren eine Modifikation des Jobs

  3. Upstart erfordert zum Verändern eine Modifikation des Skriptes, welches der Distributor mitliefert. Etwas das normalerweise nur in Ausnahmefällen gemacht werden sollte! Ab Version 1.3 gibt es hierzu auch die Möglichkeit der sogenannten „Override Files“.

  4. Weder SysVinit noch Upstart bieten eine zuverlässige Möglichkeit, um unabhängig von der aktuellen Position definiert ein bestimmtes Runlevel zu erreichen.

Unit Files

Ein zentrales Konzept von systemd sind die Unit-Files. Diese ersetzen die Init-Skripte von anderen Systemen und sind wesentlich einfacher aufgebaut.

Unit Typen

Es gibt verschiedene Arten von Unit Files, nachfolgend ein paar Beispiele:

Unit Files
Dienste Typen
.service Typ für normale Dienste
.target Zieltyp, dient zum Beispiel als Ersatz für Runlevels (graphical.target), aber auch für Zwischenschritte (network.target, local-fs.target, ...)
.mount Typ für Mountpoints, meist automatisch durch systemd-fstab-generator erzeugt
.socket Typ für Socket Activation von Diensten

Vergleich

Sehen wir uns hierzu mal einen Dienst bei allen drei Systemen im Vergleich an, ausgewählt wurde hierzu cron, welcher auf den meisten Systemen zu finden sein sollte:

Den Anfang macht SysVinit:

#!/bin/sh
# Start/stop the cron daemon.
#
### BEGIN INIT INFO
# Provides:          cron
# Required-Start:    $syslog $time
# Required-Stop:     $syslog $time
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Regular background program processing daemon
# Description:       cron is a standard UNIX program that runs user-specified 
#                    programs at periodic scheduled times. vixie cron adds a 
#                    number of features to the basic UNIX cron, including better
#                    security and more powerful configuration options.
### END INIT INFO


test -f /usr/sbin/cron || exit 0

#LSBNAMES='-l'  # Uncomment for LSB name support in /etc/cron.d/

. /lib/lsb/init-functions

case "$1" in
start)  log_daemon_msg "Starting periodic command scheduler" "crond"
        start-stop-daemon --start --quiet --pidfile /var/run/crond.pid --name cron --startas /usr/sbin/cron -- $LSBNAMES
        log_end_msg $?
        ;;
stop)   log_daemon_msg "Stopping periodic command scheduler" "crond"
        start-stop-daemon --stop --quiet --pidfile /var/run/crond.pid --name cron
        log_end_msg $?
        ;;
restart) log_daemon_msg "Restarting periodic command scheduler" "crond" 
        start-stop-daemon --stop --retry 5 --quiet --pidfile /var/run/crond.pid --name cron
        start-stop-daemon --start --quiet --pidfile /var/run/crond.pid --name cron --startas /usr/sbin/cron -- $LSBNAMES
        log_end_msg $?
        ;;
reload|force-reload) log_daemon_msg "Reloading configuration files for periodic command scheduler" "crond"
        # cron reloads automatically
        log_end_msg 0
        ;;
*)      log_action_msg "Usage: /etc/init.d/cron {start|stop|restart|reload|force-reload}"
        exit 2
        ;;
esac
exit 0

Jetzt kommt der entsprechende Upstart-Job:

# cron - regular background program processing daemon
#
# cron is a standard UNIX program that runs user-specified programs at
# periodic scheduled times

description     "regular background program processing daemon"

start on runlevel [2345]
stop on runlevel [!2345]

expect fork
respawn

exec cron

Zuletzt systemd:

[Unit]
Description=Periodic Command Scheduler

[Service]
ExecStart=/usr/sbin/crond -n
ExecReload=/bin/kill -HUP $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target

Grundlegend machen alle drei Varianten das Gleiche. Jedoch ist es bei SysVinit nicht ganz so einfach zu sehen, was genau passiert. Cron ist in diesem Fall ein sehr einfaches Beispiel, Dienste wie zum Beispiel postfix haben wesentlich komplexere Init-Skripte, wohingegen die Komplexität von upstart Jobs oder systemd Units nur unwesentlich zunimmt.

Der upstart-Job wäre, wenn er in /etc/init liegt, schon direkt aktiviert und würde beim Starten des Systems abgearbeitet werden. SysVinit und systemd erfordern hierzu Links in /etc/rcX.d (Debian/Ubuntu) beziehungsweise /etc/systemd/system. Zur Verwaltung dieser Links gibt es auf einem Debian oder Ubuntu System das Tool update-rc.d. Für systemd gibt es systemctl enable dienst.service, welches sich um das Anlegen des Links kümmert.

Im systemd-Unit wurde hier übrigens definiert, dass cron.service zum Target multi-user.target gehört, das entspricht einem Mehrbenutzerrunlevel im normalen SysVinit ohne grafische Oberfläche. Wer jetzt glaubt im grafischen Modus (mit GDM, KDM, ...) keinen cron haben zu können, irrt: Targets können von anderen Targets abhängen und so definiert beispielsweise graphical.target – welches bei den meisten Distributionen der Standard ist – dass doch bitte zuerst multi-user.target gestartet werden möchte.

Die WantedBy Definition ist übrigens nur ein Vorschlag für systemctl. Es ist jederzeit möglich durch eigene Symlinks unterhalb von /etc/systemd/system/ das Verhalten und die Reihenfolge zu modifizieren. Unabhängig davon werden jedoch andere Abhängigkeiten der einzelnen Units beachtet. Dies führt zum Beispiel immer dazu, dass Avahi gestartet wird, wenn ein Dienst diesen benötigt, unabhängig davon, in welchem Target der Dienst gestartet wird.

Mythos: systemd sorgt für mehr Komplexität

Es gibt oft Befürchtungen, dass systemd ein System wesentlich komplexer macht. Begründet wird dies oft damit, dass gerade langjährige Anwender sich an das Lesen von Skripten gewöhnt haben und dies daher logisch erscheint. Tatsächlich ist es aber so, dass Init-Skripte dem DRY-Prinzip widersprechen und dadurch jedes Skript eine gewisse Komplexität mitbringt. systemd beschäftigt sich hier wesentlich wenig mit der Logik, wie etwas zu tun ist. Es beschäftigt sich damit, was getan werden muss, um einen bestimmten Status zu erreichen.

Es ist allerdings richtig, dass durch diese neuen Ansätze von systemd das Init-System als solches komplexer wird, Hintergrund ist, dass Aufgaben von vielen kleinen Skripten in einen einzigen Dienst verlagert werden. Es ist jedoch absehbar, dass auch systemd einen Grad der Stabilität wie SysVinit erreichen wird, wodurch dies zukünftig kein Problem mehr darstellt.

Genauso wie Init-Skripte arbeitet auch systemd nur das ab, was konfiguriert wurde. Es gibt keine wundersame Magie, die dafür sorgt, dass alles funktioniert.

systemd in Ubuntu?

Ubuntu hat bisher noch keinen Plan auf systemd zu wechseln. Aktuell gibt es in dieser Richtung auch keine Entwicklung. Denn die vorhandenen Pakete sind hoffnungslos veraltet und werden nicht aktiv von den Ubuntu-Entwicklern betreut. Ob systemd in Zukunft kommen wird, ist noch ungewiss, hängt aber maßgeblich von Projekten wie GNOME und KDE ab. Sollten diese systemd erfordern, wären diese Desktops nicht mehr länger unter Ubuntu lauffähig.


Ein großes Dankeschön an encbladexp für den eingereichten Artikel

Dieser Artikel steht unter der by-nc-sa 2.0-Lizenz.