Systemd-Units verstehen und selbst schreiben

Aus LinuxUser 07/2018

Systemd-Units verstehen und selbst schreiben

© Alexei Logvinovich, 123RF

Handarbeit

Es ist keine Hexerei, Systemd-Units selbst zu erstellen. Neben einem Grundverständnis der Dateistruktur benötigen Sie lediglich einen Texteditor.

Ob man das mag oder nicht: Systemd ist mittlerweile allgegenwärtig. Distributionen, die noch auf andere Init-Systeme setzen, wie SysVinit, Upstart oder Runit, lassen sich an zwei Händen abzählen. Kommt auf Ihren Rechnern also eine der Mainstream-Distributionen zum Einsatz, müssen Sie sich wohl oder übel mit den Konzepten und Arbeitsweisen von Systemd vertraut machen.

Einen genaueren Blick verdienen dabei die Systemd-Units und die zugehörigen Konfigurationsdateien. Das umfasst das Wissen, wie man sie erstellt, konfiguriert und aktiviert. Dabei bezeichnet “Unit” jede Art von Ressource, mit der Systemd zusammenspielt – was neben Diensten unter anderem Timer, Mountpoints, Netzwerkressourcen, Sockets, Partitionen und Geräte umfasst.

Über die dazugehörigen Konfigurationseinheiten, die Unit-Dateien, legen Sie etwa fest, wie und wann ein Dienst startet, auf welche Ressourcen er zugreifen darf und welche Abhängigkeiten erfüllt sein müssen. Unit-Files ähneln in der Funktion den Init-Skripten von SysVinit oder Upstart (Abbildung 1), lassen sich in der Regel aber einfacher erstellen und sind übersichtlicher, flexibler und leichter zu pflegen. Sie folgen den Konventionen einfacher INI-Dateien (Abbildung 2).

Abbildung 1: Init-Skripte von SysVinit sind monolithisch, lang und schwer zu lesen. Das Exemplar zu Autofs umfasst über 100 Zeilen.

Abbildung 1: Init-Skripte von SysVinit sind monolithisch, lang und schwer zu lesen. Das Exemplar zu Autofs umfasst über 100 Zeilen.

Abbildung 2: Die Unit-Datei von Autofs fällt übersichtlich aus, fasst sich kurz und lässt sich relativ einfach lesen.

Abbildung 2: Die Unit-Datei von Autofs fällt übersichtlich aus, fasst sich kurz und lässt sich relativ einfach lesen.

Die Namenskonvention für Unit-Dateien folgt dem Schema Name.Typ. Die Tabelle “Unit-Typen” zeigt eine Auswahl der am häufigsten anzutreffenden Typen. Wie Sie sehen, gibt es viele verschiedene Unit-Typen, die Systemd verwaltet.

Typ

Funktion

.service

Dienste starten, überwachen und stoppen

.device

Gerätedateien anlegen

.mount

Ein- und Aushängen von Mountpoints

.automount

automatisches Ein- und Aushängen von Mountpoints

.target

Gruppe von Units definieren

.timer

wiederkehrende Aufgaben definieren (ähnlich Cron)

.socket

Verbindungen zwischen Prozessen herstellen

.network

Netzwerke konfigurieren

.path

Service-Units abhängig von Änderungen ausführen

Viele der Unit-Typen arbeiten zusammen, um die Funktionalität zu erweitern. So dienen einige Units dazu, andere Units anzustoßen sowie Services und Targets zu aktivieren. Jeder Typ verfügt über eine eigene Manpage nach dem Schema systemd.Typ.

Verteilt

Units finden Sie an mehreren Stellen im System. Unter /lib/systemd/system/ liegen durch das System vorinstallierte Dateien. Von Ihnen selbst angelegte Units oder solche, die Sie editiert haben, gehören nach /etc/systemd/system/. Wollen Sie eine bestehende Einheit ändern, kopieren Sie sie am besten zunächst dorthin und bearbeiten sie dort. Bestimmte für die Laufzeit relevante Einheiten liegen schließlich unter /run/systemd/system/. Die Reihenfolge des Auslesens folgt dabei dem Schema /etc/, /run/ und /lib/.

Wenn Sie einen Blick auf die in /lib/systemd/system/ versammelten Unit-Dateien werfen, sehen Sie solche mit verschiedenen Endungen, die für die verschiedenen Typen stehen. Endungen wie .network, .timer, .mount oder .device erschließen sich quasi von selbst. Am häufigsten sind jedoch die Service-Units vertreten, die das Verhalten der Dienste auf dem Rechner festlegen (Abbildung 3).

Abbildung 3: Unit-Dateien f&uuml;r Dienste mit der Endung <code>.service</code> sind am h&auml;ufigsten vertreten.

Abbildung 3: Unit-Dateien für Dienste mit der Endung .service sind am häufigsten vertreten.

Dreigeteilt

Ein Beispiel hilft dabei, den Aufbau der Dateien zu verstehen. Es orientiert sich an dem in Abbildung 2 gezeigten autofs.service, einem Dienst zum Starten von externen Laufwerken oder Netzwerk-Shares, der eine halbwegs übersichtliche Unit-Datei nutzt.

Eine Unit gliedert sich in die drei Sektionen [Unit], [Typ] und [Install], wobei der Unit-Typ variiert. In vorliegendem Fall steht dort [Service], da es um eine Unit zum Steuern eines Diensts geht. Oft gehören mehrere Unit-Typen zusammen, wie etwa Service und Timer.

Bei Letzteren handelt es sich etwa um Dienste, die nicht ständig laufen (Abbildung 4). Die Service-Datei definiert wie üblich den Dienst selbst, während der Timer dessen sich wiederholende Ausführung regelt. Mehr über Systemd-Timer erfahren Sie in einem entsprechenden Artikel ab Seite 24 in diesem Heft.

Abbildung 4: Selbst erstellte Timer wie <code>etckeeper</code> und <code>fstrim</code> erg&auml;nzen die von Systemd erstellten Timer.

Abbildung 4: Selbst erstellte Timer wie etckeeper und fstrim ergänzen die von Systemd erstellten Timer.

Sehen Sie im Beispiel aus Listing 1 zunächst die Sektion Unit und die darin verwendeten Direktiven in Form von Schlüssel-Wert-Paaren an. Diese Sektion kommt in der Regel zum Einsatz, um Metadaten für die Einheit zu definieren und die Beziehung der Unit zu anderen Einheiten zu konfigurieren.

Listing 1

[Unit]
Description=Automounts filesystems on demand
After=network.target ypbind.service sssd.service network-online.target remote-fs.target
Wants=network-online.target

Der Schlüssel Description beschreibt den Dienst. Den Wert dazu dürfen Sie frei wählen; er sollte aber den Zweck des Dienstes deutlich offenbaren. Der Schlüssel After enthält die Services und Targets, die dieser Dienst erwartet. Dabei sind Targets in Gruppen zusammengefasste Dienste (Abbildung 5). Dass die in unserem Fall allesamt Funktionen des Netzwerks betreffen, erklärt sich von selbst – schließlich kommen Sie ohne Netzwerk nirgendwo hin, um entfernte Laufwerke einzuhängen.

Abbildung 5: Targets gruppieren mehrere Units und d&uuml;rfen selbst auf anderen Targets basieren oder mit solchen kollidieren. Die Direktive <code>AllowIsolate=yes</code> erm&ouml;glicht diesem Target, als Boot-Ziel zu dienen.

Abbildung 5: Targets gruppieren mehrere Units und dürfen selbst auf anderen Targets basieren oder mit solchen kollidieren. Die Direktive AllowIsolate=yes ermöglicht diesem Target, als Boot-Ziel zu dienen.

Als letzten Schlüssel sehen Sie Wants, mit dem Sie optionale Abhängigkeiten bezeichnen. Eine harte Abhängigkeit dagegen kennzeichnen Sie mit Require. Startet der dort eingetragene Dienst nicht, versagt der Dienst, zu dem diese Unit gehört, seine Tätigkeit. Bei Wants startet er trotzdem. Wenn Sie sich nun fragen, wozu das zusätzliche After gut ist: Dessen Fehlen würde bedeuten, dass beide Units parallel starten, was in unserem Fall nicht sinnvoll wäre.

In der Sektion Unit dürfen Sie weitere Schlüsselworte verwenden, wie Description, Documentation, BindsTo, Conflicts, Condition, Assert und andere. Erläuterungen dazu finden Sie in der Manpage zu systemd.units.

Nun zur Sektion [Service], die eine zentrale Rolle spielt (Listing 2). Als Erstes definieren Sie dort den Service-Typ. Als Standard gilt hier Type=simple, den Systemd bei Fehlen einer expliziten Angabe annimmt. Er bedeutet, dass der fragliche Dienst nach dem Start nicht verzweigt.

Listing 2

[Service]
Type=forking
PIDFile=/var/run/autofs.pid
EnvironmentFile=-/etc/default/autofs
ExecStart=/usr/sbin/automount
ExecReload=/bin/kill -HUP $MAINPID
TimeoutSec=180

In unserem Beispiel handelt es sich um einen Service des Typs forking. Hier betrachtet Systemd den Dienst als gestartet, sobald der Prozess sich in den Hintergrund verzweigt und das übergeordnete System sich beendet. Dieser Typ findet oft bei klassischen Daemons Anwendung. Hier sollten Sie unbedingt das Schlüssel-Wert-Paar PIDFile=Datei angeben, damit das System den Hauptprozess weiter verfolgen kann.

Darüber hinaus gibt es noch einige weitere Service-Typen, denen Sie möglicherweise begegnen, wenn Sie sich die Unit-Dateien auf Ihrem Rechner genauer ansehen. Type=oneshot kommt bei Skripten zum Einsatz, die einen einzelnen Job erledigen und sich dann beenden. Der Type=notify entspricht weitestgehend dem Type=simple, mit dem Unterschied, dass der Daemon ein Signal an Systemd sendet, wenn er bereitsteht. Beim Type=dbus gilt der Dienst als bereit, wenn der angegebene BusName auf dem System-Bus von D-Bus erscheint. Beim Type=idle verzögert Systemd das Ausführen des Diensts, bis es alle anderen anstehenden Jobs erledigt hat. Ansonsten entspricht auch hier das Verhalten jenem des Type=simple.

Als weiterer Schlüssel taucht in der Sektion [Service] aus unserem Beispiel EnvironmentFile= auf. Der Wert dazu verweist auf eine Datei, aus der der Dienst bei Bedarf Umgebungsvariablen lädt. ExecStart= enthält den Befehl, den Systemd beim Start der Einheit ausführt, während ExecReload= die Konfiguration des Diensts im Bedarfsfall neu lädt.

Abschließend legt TimeoutSec= fest, wie lange der Service maximal läuft. Alle Service-Typen und Schlüssel für die Sektion [Service] finden Sie in der Manpage systemd.service eingehend erläutert.

In der Sektion [Install] findet sich in unserem Beispiel nur ein einzelner Eintrag (Listing 3). Das hier verwendete Schlüssel-Wert-Paar findet sich so fast in jeder Service-Datei an dieser Stelle. Der Schlüssel WantedBy legt dabei fest, wann die Einheit startet. Der Wert multi-user.target dient als Standard für ein System mit mehreren Benutzern. Diese Targets entsprechen den Run-Levels bei SysVinit, wobei multi-user.target für das Run-Level 3 steht.

Listing 3

[Install]
WantedBy=multi-user.target

Das jeweilige Run-Level bei Systemd ermitteln Sie mittels systemctl get-default im Terminal. In einer grafischen Umgebung heißt es graphical.target (SysVinit: Run-Level 5). Alle verfügbaren Run-Level (oder richtiger: Targets) zeigt der Befehl ls -al /lib/systemd/system/runlevel* (Abbildung 6).

Abbildung 6: Die vor Systemd verwendeten Runlevel finden allesamt eine Entsprechung in Systemd-Targets.

Abbildung 6: Die vor Systemd verwendeten Runlevel finden allesamt eine Entsprechung in Systemd-Targets.

Selbst erstellen?

Sie haben sich unter Umständen vielleicht gefragt, welcher praktische Anlass (neben reiner Neugier) Sie dazu veranlassen sollte, eine Systemd-Unit zu erstellen. Dafür gibt unter Umständen gute Gründe.

Angenommen, Sie installieren eine Software, die einen Dienst ausführt, der lediglich eine Init-Datei mitbringt, aber noch keine Unit-Datei: Hier bietet es sich an, eine Einheit dafür selbst zu erstellen. Einen guten Ausgangspunkt dafür bietet die simple Vorlage aus Listing 4.

Listing 4

[Unit]
Description=Meine_Unit
Documentation=man:optionaler Verweis auf Man-Dateien
After=wird nach XY gestartet
Wants=optionale Abhängigkeiten
[Service]
Schlüssel-Wert-Paare für den fraglichen Unit-Typ
[Install]
WantedBy=multi-user.target

Ein sinnvolles Vorgehen beim Befüllen der Sektion [Service] ist, sich bestehende ähnliche Unit-Dateien anzusehen. Eine Liste aller im System vorhandener Unit-Dateien und deren derzeitigen Status listet der Befehl systemctl list-unit-files auf. Im vorliegenden Fall schränken Sie das mit systemctl list-unit-files --type service auf Dienste ein.

Der erste Befehl liefert allerdings möglicherweise interessante andere Unit-Typen gleichen Namens. Das könnten etwa Target-Units sein: Sie dienen dazu, andere Einheiten zu verknüpfen und zu gruppieren, um einen gewünschten Zustand des Systems zu beschreiben. Einige dieser Units wären dann etwa Dienste, andere vielleicht zusätzliche Targets mit eigenen Gruppen von Units.

Mehr Komfort haben hierbei Anwender, die auf KDE Plasma setzen: Dieser Desktop führt in den Systemeinstellungen unter dem Punkt Systemd alle Units und deren Status übersichtlich auf. Zusätzlich können Sie über eine Ausklappliste nach Unit-Typen filtern oder eine Suchfunktion nutzen (Abbildung 7).

Abbildung 7: Der Men&uuml;punkt <span class="ui-element">Systemd</span> in den Einstellungen von KDE&nbsp;Plasma erleichtert den &Uuml;berblick &uuml;ber im System laufende Einheiten und deren aktuellen Status. Per Kontextmen&uuml; steuern Sie hier Units wie mit Systemctl.

Abbildung 7: Der Menüpunkt Systemd in den Einstellungen von KDE Plasma erleichtert den Überblick über im System laufende Einheiten und deren aktuellen Status. Per Kontextmenü steuern Sie hier Units wie mit Systemctl.

Um mehr über eine ähnliche wie die zu erstellende Einheit zu erfahren, hilft neben dem Blick in die Unit-Datei der Befehl systemctl status Dienst. Er liefert Informationen über Laufzeit, Speicherverbrauch, die Prozess-ID (PID) und eventuelle Fehlermeldungen seit dem letzten Start des Diensts (Abbildung 8).

Abbildung 8: Die Abfrage des Status einer Einheit erleichtert die Fehleranalyse.

Abbildung 8: Die Abfrage des Status einer Einheit erleichtert die Fehleranalyse.

TIPP

Beim Bestimmen des optimalen Startzeitpunkts für einen Dienst hilft ein Blick auf die Ausgabe von systemd-analyze blame, die den Ablauf beim Booten aufschlüsselt.

Haben Sie die Unit-Datei fertiggestellt und an der richtigen Stelle platziert, fragen Sie zunächst mit systemctl status Dienst den Status ab. Zusätzliche Informationen liefert hier unter Umständen der Befehl journalctl --unit=Dienst.

Um den Dienst nun zu aktivieren und zu starten, verwenden Sie das Kommando systemctl start Dienst. Die Manpage zu Systemctl liefert hier weitere Befehle und Optionen.

Fazit

Es ist keine Hexerei, Systemd-Units selbst zu erstellen. Was zunächst etwas wirr erscheint, erweist sich bei näherem Hinsehen als gut organisierte und strukturierte Zusammenstellung ineinandergreifender Komponenten. Im Vergleich zu den Init-Dateien von SysVinit lassen sich Systemd-Units jedenfalls einfacher erstellen und warten. Vor allem brauchen Sie im Unterschied zu einigen anderen Init-Systemen zum Erstellen von Unit-Dateien keine Skriptsprache zu beherrschen, da es sich um einfache INI-Dateien handelt, die Systemd in Unit-Dateien umwandelt.

Die Dokumentation von Systemd im Allgemeinen und Systemd-Units im Besonderen liegt meist nur in englischer Sprache vor. Deutschsprachige Dokumentationen gehen meist nicht weit genug in die Tiefe. Einen guten Überblick über die Zusammenhänge in Sachen Units bietet die Webseite von DigitalOcean [1]. Eine verlässliche Anlaufstelle für Systemd und dessen Komponenten mit vielen weiterführenden Links finden Sie bei Freedesktop [2] und in Lennart Poetterings Blog “Pid Eins” [3].

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDF
LinuxUser 07/2018 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben