mini|systemd-Komponenten des Tizen-Betriebssystems für mobile Geräte

systemd ist eine Sammlung von Programmen, Hintergrundprogrammen (Daemons) und Bibliotheken für Linux-Betriebssysteme. Ihr zentraler Bestandteil ist der systemd init-Prozess, der als erster Prozess (Prozess-ID 1) zum Starten, Überwachen und Beenden weiterer Prozesse dient. Es bietet aber auch andere Systemkomponenten an, deren Bandbreite vom Booten („systemd-boot“) bis zum Logging („journald“) reichen. Systemd wurde von Lennart Poettering, Kay Sievers (Red Hat Inc.) und anderen in C programmiert und wird als freie Software unter der GNU Lesser General Public License (LGPL) veröffentlicht.

Der Name entspricht mit dem abschließenden „d“ dem für Daemons üblichen Namensschema: systemd ist der Daemon, der das System startet und betreut.

Geschichte Die Ideen und Konzepte zu systemd entstanden aus der Betrachtung von bereits bestehenden modernisierten init-Systemen wie launchd von macOS und SMF (Service Management Facility) von Solaris. Es wurde am 10. April 2010 veröffentlicht. Von 2011 bis 2015 sind die größten Distributionen auf systemd umgestiegen:

2011: Fedora ab Version 15 2011: Mandriva 2012: openSUSE ab Version 12.1 2012: Mageia ab Version 2 2012: Arch Linux seit Oktober 2014: Red Hat Enterprise Linux (und damit auch CentOS) ab Version 7, 2014: SUSE Linux Enterprise Server ab Version 12, 2014: Oracle Linux ab Version 7, 2015: Ubuntu ab Version 15.04 2015: Debian ab Version 8. 2016: Linux Mint ab Version 18 2021: AlmaLinux ab der ersten Version (8.3) 2021: Rocky Linux ab der ersten Version (8.4)

Die wichtigsten Distributionen, die systemd bewusst gar nicht oder nicht standardmäßig nutzen, sind:

Alpine Linux (v. a. für Docker (Software)) Devuan (Debian-Abspaltung, um systemd zu vermeiden) Gentoo Linux (systemd alternativ möglich)

Ab Version 221 enthält systemd sd-bus, eine unabhängige D-Bus-Programmierschnittstelle, die bei der Komplexität zwischen libdbus und GDBus angesiedelt ist. sd-bus unterstützt sowohl das klassische dbus1 im Userspace als auch kdbus als Backend und soll so den reibungslosen Übergang zur Interprozesskommunikation im Kernel ermöglichen.

In Version 260 wurde die Abwärtskompatibilität zu SysVinit-Skripten entfernt.

Technik

Da systemd bewusst Features benutzt, die nur unter Linux zur Verfügung stehen, nicht aber auf anderen unixoiden Betriebssystemen, kann es nur auf Systemen mit Linux-Kernel laufen.

Ziele

systemd soll in seiner Kernfunktion die gegenseitigen Abhängigkeiten von Prozessen und anderen Aspekten des Systemzustands organisieren. Dazu gehört insbesondere die verlässliche sowohl Steuerung der Systemkomponenten als auch Erkennung von deren Statusänderungen und das Auslösen von Reaktionen darauf. Ebenfalls von großer Bedeutung ist die leichte Nutzbarkeit auch komplizierter Konfigurationsmöglichkeiten (systemd hat inklusive der optionalen Systemdienste etwa 1.500 Konfigurationsdirektiven). Das flexiblere Abhängigkeitssystem kann zu stärkerer Parallelisierung beim Systemstart und somit einer kürzeren Bootzeit führen als das klassische SysVinit oder das überwiegend nur noch bei ChromeOS zum Einsatz kommende Upstart. Über die Steuerung der Systemkomponenten hinaus hat systemd einige Systemdienste neu implementiert, deren Nutzung mal mehr, mal weniger optional ist.

Units

systemd verwaltet nicht nur Dienste, sondern auch weitere wichtige Komponenten eines Linux-Systems. Diese Verwaltung erfolgt über so genannte Units, von denen es unterschiedliche Typen gibt und die als Textdateien konfiguriert werden, die an Windows-INI-Dateien angelehnt sind. Die Typen sind: .mount: Einhängepunkt .service: Daemonen, sowohl für das System als auch für die Benutzer .device: Hardware (Sysfs-Einträge, udev) .socket: Sockets (v. a. IP oder UNIX Domain Sockets) .swap: Auslagerungsspeicher .automount: Automounter (Einhängen von Dateisystemen erst bei Bedarf) .path: Überwachung von Dateisystempfaden, überwiegend mittels inotify: Starten einer Unit, wenn die konfigurierte Veränderung eintritt. .slice: hierarchische Zusammenfassung von Units zur Ressourcensteuerung (cgroups) .scope: Zusammenfassung von Prozessen, die nicht von systemd erzeugt wurden, etwa der Prozessbaum eines SSH-Logins .nspawn: systemd-Container (systemd-nspawn); Alternative zu LXC (Linux Containers)

Eine Sonderstellung haben die .timer- und .target-Units, die außerhalb von systemd nicht sichtbar sind: .timer: Die systemd-Variante von Cronjobs. Wenn eine .timer-Unit ausgelöst wird, startet sie eine Unit. .target: Gruppierung von Units für das gemeinsame Starten und Stoppen (systemctl isolate, nicht systemctl stop; analog zu Runleveln) und die (vereinfachte) Prüfung, ob alle benötigten Units aktiv sind.

Die Konfiguration fast aller Parameter über die Unit-Dateien ist nicht nur deutlich einfacher, weil komplexe Sachverhalte und Kommandoaufrufe zu häufig einer einzigen Zuweisung eingedampft werden, sondern spart auch Ressourcen, weil der Aufruf externer Kommandos aus einem Script durch wenige Systemaufrufe ersetzt werden.

Units müssen nicht zwingend in Unit-Dateien erstellt werden. Für etablierte Arten, Dinge zu konfigurieren, die in systemd als Unit abgebildet werden, gibt es systemd-Unit-Generatoren (die bei jedem Laden der systemd-Konfiguration laufen, also nur transiente Units erzeugen). Die wichtigsten sind: systemd-fstab-generator: Erzeugt aus den /etc/fstab-Einträgen .mount-Units systemd-cryptsetup-generator: Erzeugt instanziierte .service-Units zum Entschlüsseln von Blockgeräten, die in /etc/crypttab konfiguriert sind Vor systemd 260 gab es einen Generator, der aus SysVinit-Scripten .service-Units erzeugte.

Drop-in-Dateien

Wenn man die von der Distribution oder dem Softwareanbieter bereitgestellte Unit ändern möchte, kann man diese ersetzen, was zu Konflikten bei Updates führen kann (wenn entweder die eigene Änderung überschrieben wird oder man wichtige Änderungen verpasst). Man kann stattdessen einzelne oder mehrere Direktiven in gesonderten Dateien setzen oder ändern. systemd fügt diese Dateien mit der Unit-Datei zusammen. Die Drop-In-Dateien für die Unit ssh.service befinden sich ggf. in ssh.service.d/*.conf. Dies kann man auch nutzen, um gemeinsame Konfigurationen aus einer Quelldatei in mehrere Units einzubinden (per Symlink).

Abhängigkeiten

Start-Stopp-Abhängigkeiten und Reihenfolge

Es gibt in systemd zwei Arten von Abhängigkeiten, die auf nicht offensichtliche Weise unabhängig voneinander sind und deshalb typischerweise (um eine Startvoraussetzung zu erreichen) kombiniert werden müssen: Start-Stopp-Abhängigkeiten (v. a. Wants=, Requires=, BindsTo=, Conflicts=) Reihenfolge-Abhängigkeiten (After=, Before=)

Der Start einer Unit kann das Starten oder Stoppen anderer Units auslösen. Das Booten (das eine .target-Unit hat) ist diesbezüglich nicht grundsätzlich verschieden vom späteren manuellen Starten einer einzelnen Unit: Es werden rekursiv die Abhängigkeiten zwischen allen involvierten Units erfasst. Für alle zu startenden Units werden Transaktionen mit Start-Jobs erstellt. Alle wartenden Start-Jobs, für die alle Startvoraussetzungen erfüllt sind, werden gleichzeitig gestartet. Wenn der Start einer Unit fehlschlägt, werden alle Start-Jobs, für die diese Unit eine Startvoraussetzung ist, abgebrochen.

Die Abhängigkeiten einer einzelnen Unit kann man sich mit systemctl list-dependencies anzeigen lassen. Eine grafische Gesamtansicht aller Abhängigkeiten im System kann man mit systemd-analyze dot erstellen.

Um den erfolgreichen Start der Unit srv.mount zu einer Startvoraussetzung für die Unit apache2.service zu machen, benötigt apache2.service zweierlei: eine zwingende Start-Stopp-Abhängigkeit (Requires=, BindsTo=), also eine, deren Fehlschlagen nicht akzeptiert wird (anders als bei Wants=) eine Reihenfolge-Abhängigkeit (After=, Before=)

Ohne die Reihenfolge-Abhängigkeit würden beide Units gleichzeitig gestartet und hätte das Fehlschlagen von srv.mount (innerhalb von systemd) keine Auswirkungen auf apache2.service (außer bei BindsTo=). Wenn nur die Reihenfolge-Abhängigkeit konfiguriert ist, wird srv.mount womöglich gar nicht gestartet (es sei denn, eine andere Unit löst dies aus). Wenn die Unit zufällig doch gestartet wird, wartet systemd mit dem Start von apache2.service, bis der Start von srv.mount geglückt oder fehlgeschlagen ist, und startet dann in jedem Fall apache2.service.

+ Startvoraussetzung und Reihenfolge von apache2.service - - keine Start-Stopp-Abhängigkeit Wants= Requires= BindsTo= Conflicts= keine Reihenfolge-Abhängigkeit srv.mount läuft startet(1) startet startet startet startet(2) srv.mount scheitert startet(1) startet startet startet, aber wird nach dem Fehlschlagen von srv.mount beendet startet(2) After= srv.mount läuft startet(1) nach srv.mount startet nach srv.mount startet nach srv.mount startet nach srv.mount startet(2) nach dem Beenden von srv.mount srv.mount scheitert startet(1) nach srv.mount startet nach srv.mount startet nicht startet nicht startet(2) nach dem Beenden von srv.mount (1) aber srv.mount wird möglicherweise gar nicht gestartet (2) und löst (ggf. vor dem eigenen Start) die Beendigung der anderen Unit aus

Bei einer Conflicts=-Beziehung ist egal, ob eine After=- oder Before=-Reihenfolge konfiguriert ist, weil Stopp-Jobs immer vor Start-Jobs ausgeführt werden. Nur wenn gar keine Reihenfolge konfiguriert ist, wartet systemd mit dem Start nicht, bis die andere Unit beendet wurde.

systemd erfasst und steuert also die Übergänge von einem Systemzustand (Gesamtheit der Zustände aller Units) zum nächsten, wogegen SysVinit nur die Start- und Stoppreihenfolge von Scripten organisiert und diese dann unabhängig von dabei auftretenden Fehlern ausführt.

Ziel-Unit beim Booten

systemd aktiviert beim normalen Booten die Unit default.target. Dies ist üblicherweise ein Symlink auf die echte .target-Unit. Abfragen und setzen kann man das Ziel von default.target mit systemctl get-default bzw. systemctl set-default.

Man kann default.target beim Booten über Parameter der Kernel-Kommandozeile überschreiben: systemd.unit=. Vorgesehene .target-Units für diesen Fall sind etwa emergency.target und rescue.target. Allerdings startet keine von beiden SSH. Wenn man eine .target-Unit mit virtuellen Konsolen und SSH, aber ohne die Dienste aus multi-user.target haben will, kann man diese leicht erstellen: [Unit] Description=%n: To be called from the kernel command line: systemd.unit=minimal-network.target Wants=basic.target getty.target network-online.target ssh.service Wenn man keine solche Unit vorbereitet hat, kann man auch alle explizit zu startenden Units auf der Kernel-Kommandozeile angeben: systemd.unit=ssh.service systemd.wants=basic.target systemd.wants=network-online.target systemd.wants=getty.target Das Ergebnis ist dasselbe, egal, welche der Units für systemd.unit= angegeben wird.

Erkennung eines erfolgreichen Unit-Starts

Der erfolgreiche Start von .service-Units, dessen Zeitpunkt wichtig ist, weil ab dann die Startvoraussetzung für andere Units erfüllt sein kann (die man so früh wie möglich starten möchte), wird für die einzelnen Untertypen dieser Unit unterschiedlich erkannt. Die Varianten sind: Type=oneshot: Die Unit ist erst aktiv, wenn sich der darin konfigurierte Prozess aktiv beendet hat; hier kontrolliert der Prozess also den Start abhängiger systemd-Units Type=dbus: Die Unit ist aktiv, sobald der D-Bus-Name registriert ist. Type=notify: Dies ist nur möglich, wenn die Anwendung an systemd angepasst ist. Sie meldet direkt an systemd, wann sie einsatzbereit ist. alle anderen: Die Unit ist aktiv, sobald der konfigurierte Prozess gestartet wurde. Das hat die Nachteile, dass der Prozess bei der Initialisierung abstürzen kann dass bei Prozessen, die lange für ihre Initialisierung brauchen, später gestartete Units versuchen, auf diesen Dienst zuzugreifen, bevor er erreichbar ist

Beschleunigung durch Socket-Abhängigkeit