Linux/Systemstart
Init-Systeme
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.
Entwicklung
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.
Anwendung
Gängige 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: # SysVinit erfordert in jedem Skript eine bestimmte, aber unterschiedliche Logik zum Starten, Neustarten und Beenden des Dienstes
- Upstart erfodert zum Aktivieren/Deaktivieren eine Modifikation des Jobs
- 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“.
- Weder SysVinit noch Upstart bieten eine zuverlässige Möglichkeit, um unabhängig von der aktuellen Position definiert ein bestimmtes Runlevel zu erreichen.
Vergleich
Hierzu einen Dienst bei allen drei Systemen im Vergleich. Ausgewählt wurde hierzu cron, der auf den meisten Systemen zu finden ist.
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
Upstart
# 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
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.
Systemd - Schaltzentrale
Bei einer Reihe von Distributionen kümmert sich mittlerweile nicht mehr Sysvinit, sondern Systemd um den Systemstart.
Das erst zwei Jahre alte Init-System verspricht den Bootprozess zu beschleunigen und erfordert keine explizite Konfiguration der Abhängigkeiten zwischen Systemdiensten; nebenbei schafft es einige distributionsspezifische Eigenarten aus der Welt.
Bei Linux-Distributionen übergibt der Kernel traditionell Sysvinit die Verantwortung zur Einrichtung des Systems. Einige Jahre sah alles danach aus, als würde Upstart das angestaubte, aber noch weitverbreitete Init-System beerben, doch mittlerweile immer mehr Distributionen auf Systemd um – abgesehen von Ubuntu , das laut Mark Suttleworth auf absehbare Zeit bei Upstart bleiben wird.
Fedora nutzt Systemd seit Version 15, auch in OpenSuse 12.1 und Mandriva 2011 kommt das neue Init-System zum Einsatz; Mageia steigt mit Version 2 um. Bei Arch Linux und Gentoo sowie Debian Testing liegt Systemd bei; bei einigen weitere Distributionen wird der optionale Einsatz oder der Umstieg diskutiert.
Eine der Besonderheiten von Systemd ist der parallele Start von Hintergrunddiensten, ohne dass Abhängigkeiten zwischen diesen explizit festgelegt werden müssen; das nutzt Hardware-Ressourcen effizienter und lässt das System flott starten.
Systemd erledigt zudem einige Aufgaben, um die sich bislang meist distributionsspezifische Skripte kümmern; ganz nebenbei beseitigt es damit einige Unterschiede bei der Bedienung und Konfiguration von Distributionen.
systemd
Maintainer | Lennart Poettering, Kay Sievers (Red Hat Inc.) |
Erscheinungsjahr | 30. März 2010 |
Aktuelle Version | 224 (31. Juli 2015) |
Betriebssystem | Linux |
Programmiersprache | C |
Kategorie | init-Dienst |
Lizenz | GNU LGPL 2.1+ (Freie Software) |
freedesktop.org/wiki/Software/systemd |
systemd ist ein Hintergrundprogramm (Daemon) für Linux-Systeme, das als init-Prozess als erster Prozess (Prozess-ID 1) zum Starten, Überwachen und Beenden weiterer Prozesse dient.
Es wurde von Lennart Poettering, Kay Sievers (Red Hat Inc.) und Anderen in C geschrieben 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
Ideen und Konzepte
Die Ideen und Konzepte zu systemd entstanden aus der Betrachtung von bereits bestehenden modernisierten init-Systemen wie launchd von Mac OS X und SMF (Service Management Facility) von Solaris. Es wurde am 10. April 2010 veröffentlicht.
Distributionen
Distributionen, die systemd als vorgegebenen init-Dienst verwenden, sind Fedora seit Version 15, openSUSE seit Version 12.1, Mandriva 2011, Mageia seit Version 2, Arch Linux seit Oktober 2012, Red Hat Enterprise Linux seit Version 7, Tizen sowie siduction seit Version 2013.2, SUSE Linux Enterprise Server seit Version 12, Ubuntu seit Version 15.04 und Debian ab Version 8.
D-Bus
Ab Version 221 beinhaltet 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.
Technik
systemd ist abwärtskompatibel zu SysVinit-Skripten. Allerdings werden bewusst Features benutzt, die nur unter Linux zur Verfügung stehen, nicht aber auf anderen unixoiden Betriebssystemen. Es kann daher nur auf Systemen mit Linux-Kernel laufen.
Es soll den gegenseitigen Abhängigkeiten von Prozessen besser gerecht werden, durch mehr Parallelisierung zu einer besseren Auslastung beim Systemstart führen und somit weniger Verzögerungen verursachen als das ältere, klassische SysVinit oder das inzwischen auch von Ubuntu aufgegebene Upstart.
Grundlegendes Konzept dafür ist es, weitgehend alle Prozesse gleichzeitig zu starten.
Um nicht, wie bei anderen zwar grundsätzlich auf Parallelisierung setzenden Systemen, anhand der in einem Modell erfassten wechselseitigen Abhängigkeiten der Prozesse teilweise noch mit Serialisierung zu arbeiten, werden die D-Bus-Verbindungen und Sockets zur Interprozesskommunikation schon vor dem Start des zugehörigen Dienstes bereitgestellt und vom Kernel eventuell auflaufende Nachrichten bis zur Bereitschaft des Dienstes gepuffert.
Ähnliches wird für Anfragen an Dateisysteme mittels autofs bewerkstelligt.
Daneben kann es nur gelegentlich benötigte Dienste ereignisbasiert erst bei Bedarf starten und so beim Systemstart weniger Dienste starten. Damit nimmt es Aufgaben wahr, die bei klassischen Unix-Systemen von inetd übernommen werden.
Weiterhin sollen alle Shell-Boot-Skripte durch deklarative Konfigurationsdateien ersetzt werden, in denen definiert wird, wie die jeweiligen Dienste gestartet werden. Diese Dateien sind in der Regel deutlich einfacher zu schreiben als init-Skripte und vermeiden den erheblichen Overhead von Shell-Skripten.
Kritik
Der Hauptkritikpunkt am systemd liegt in seinem Anspruch, deutlich mehr verschiedene Aufgaben als das alte SysV-Init erledigen zu wollen, was ihn recht kompliziert und fehleranfällig mache und überdies die Unix-Philosophie verletze, dass ein Programm ein Problem gut lösen sollte, anstatt viele Aufgaben schlecht zu lösen.
Aufgaben
Der Init-Prozess ist der erste Prozess, den der Kernel erzeugt. Alle weiteren Prozesse sind Kinder des Init-Prozesses, der daher die Verantwortung für die komplette Einrichtung des Userlands trägt.
Dazu gehört nicht nur das Einhängen von Dateisystemen und die Netzwerkeinrichtung, sondern auch das Starten von Hintergrund-Diensten und Programmen – darunter auch jene, über die sich Benutzer am System anmelden.
Nach dem Abschluss der Systemeinrichtung läuft der Init-Prozess weitgehend untätig im Hintergrund weiter. Er kommuniziert mit dem Kernel und wird beispielsweise informiert, wenn der Benutzer Strg+Alt+Entf drückt.
Genau wie beim Aufruf von Befehlen wie shutdown -r now oder reboot erledigt der Prozess mit der PID 1 dann alles Nötige, um das System sauber zum Stillstand zu bringen.
Mit diesen Aufgaben wurde in den 80er Jahren in Unix System V das einfache, aber flexible "System V Init System" betraut. In den 90er Jahren entstand eine Sysvinit genannte Neuimplementierung dieses Init-Systems.
Sie arbeitet mit einer ganz ähnlichen Logik und kommt bis heute bei vielen Linux-Distributionen zum Einsatz. Sysvinit erledigt die Aufgaben des Systemstarts im Wesentlichen mit Shell-Skripten, die einfach der Reihe nach abgearbeitet werden.
Mit der Verbreitung von Linux in Mobilgeräten, Desktop-PCs, Fernsehern und zahlreichen anderen Gebieten wandelten sich allerdings die Anforderungen an den Init-Prozess: Der Systemstart sollte flexibler werden und dank Parallelisierung deutlich schneller ablaufen.
Herangehensweisen
Lange schien es, als wäre das 2006 von einem Canonical-Entwickler gestartete Upstart der designierte Nachfolger für Sysvinit (siehe den Artikel Schneller booten mit Upstart auf heise open).
Anfangs kam es nur bei Ubuntu zum Einsatz, später auch bei Fedora (Versionen 9 bis 14) und Red Hat Enterprise Linux (RHEL6-Familie). OpenSuse experimentierte während der Arbeit an der Version 11.3 mit Upstart, blieb letztlich jedoch bei Sysvinit.
Upstart ist ein ereignisorientiertes Init-System – es kann Dienste starten, wenn Ereignisse wie "Netzwerk ist konfiguriert" oder "Netzlaufwerk ist eingebunden" eintreten.
Der Ansatz unterscheidet sich stark von dem statischen Sysvinit, daher lassen sich bestehende Konfigurationen nur schwer oder gar nicht in das Ereignis-Modell von Upstart übertragen.
Im April 2010 erschien Systemd; es bedient sich einiger Ideen aus früheren Unit-Systemen und kombiniert diese mit einer einheitlichen Konfigurations- und Administrationsschnittstelle. Systemd arbeitet als Hintergrunddienst (Daemon) und steuert wichtige Aspekte der Systemkonfiguration von der Initialisierung der Hardware bis zu den gestarteten Server-Prozessen.
Der Name erschien den Entwicklern als eine passende Verbindung zum französischen Begriff "Système D" (etwa: "Trick 17"), der kreative technische Lösungsansätze à la MacGyver beschreibt.
Hintenrum
Zentrales Merkmal von Systemd ist die Socket-Aktivierung, durch die der Daemon Hintergrunddienste ohne explizite Konfiguration der Abhängigkeiten parallel starten kann, sobald die Grundeinrichtung des Systems abgeschlossen und die lokalen Dateisysteme eingebunden sind.
Der Trick besteht darin, dass Systemd die Sockets zur Kommunikation mit den zu startenden Diensten selbst anlegt und dorthin geschriebene Daten zwischenspeichert, bis sie der gestartete Dienst entgegennehmen kann.
Illustrieren lässt sich das Konzept am Beispiel der Dienste Syslog und D-Bus. Letzterer verbindet sich beim Start mit dem Socket /dev/log, um darüber bei Bedarf Status- und Fehlermeldungen über den Log-Daemon ins Systemlog zu schreiben. Sysvinit kann daher D-Bus erst starten, wenn der Syslog-Dienst voll einsatzbereit ist.
Systemd hingegen legt /dev/log selbst an und startet Syslog und D-Bus gleichzeitig; dabei werden die Daten, die D-Bus an /dev/log schickt, gepuffert, bis sie Syslog entgegennimmt. Anfangs überließ Systemd dem Kernel das Puffern; bei aktuellen Versionen vom Systemd kümmert sich die dort enthaltene Log-Funktion "Journal" um diese Aufgabe.
Systemd kann so auch Bluetooth, Avahi und weitere Dienste, die mit dem Log-Daemon oder D-Bus kommunizieren, parallel mit Syslog und D-Bus starten.
Wenn Avahi beim Start eine Antwort von D-Bus erwartet, stoppt der Prozess an dieser Stelle automatisch und setzt den Start ohne weiteres Zutun fort, sobald die Antwort über den Socket eintrifft. Sollte D-Bus aus irgendeinem Grund nicht anlaufen, bricht Systemd den Start von Bluetooth und Avahi nach einiger Zeit ab.
Apple verwendet dasselbe Prinzip in seinem mit Mac OS X 10.4 eingeführten Launchd , der auch bei iOS zum Einsatz kommt und als Hauptgrund für den deutlich verkürzten Startprozess neuerer Mac-OS-Versionen gilt, da der Parallelstart der Dienste die verfügbaren CPU- und I/O-Ressourcen effizienter nutzt.
Bei Sysvinit starten die Dienste hingegen in einer festgelegten Reihenfolge – Bluetooth und Avahi erst, wenn der D-Bus-Daemon läuft, der wieder erst startet, wenn das Syslog bereit ist. Selbst Bluetooth und Avahi, die voneinander unabhängig sind, starten nicht bei allen Sysvinit-Distributionen parallel.
Bedarfsanforderung
Da Systemd den Socket erstellt und hält, kann der Daemon einen abgestürzten Dienst neu starten, ohne dass mit dem Socket verbundene Programme die Verbindung verlieren.
Dadurch lassen sich System-Komponenten einfacher aktualisieren, da der Kernel die über den Socket eingehenden Client-Anfragen während des Neustarts puffert und der neue Dienst einfach dort fortfahren kann, wo der alte aufgehört hat.
Sockets lassen sich zudem an verschiedene Programme übergeben. Systemd nutzt das zum Loggen von früher Statusmeldungen:
Solange das Root-Dateisystem noch nicht beschreibbar eingebunden ist, nimmt ein minimaler Log-Dienst Daten entgegen, die nach /dev/log geschrieben werden, und schreibt sie in den Kernel-Log-Puffer. Sobald der eigentliche Syslog-Server bereits ist, wird der Minidienst beendet; der Syslog-Daemon übernimmt den Socket und schreibt dabei alle zuvor aufgelaufenen Nachrichten aus dem Kernel-Log-Buffer auf die Festplatte.
So gehen keine Nachrichten verloren, was eine Protokollierung vom ersten Moment des Bootens an ermöglicht.
Einheiten
Die verschiedenen Tätigkeiten beim Systemstart – Sockets anlegen, Hardware einrichten, Datenträger einbinden, Hintergrunddienste starten und so weiter – sind in sogenannten Units organisiert.
Für jede Aufgabe, die Systemd ausführen soll, benötigt man eine Unit-spezifische Konfigurationsdatei – bei einer Mount-Unit beispielsweise muss die Konfiguration lediglich die Device-Datei des Datenträgers und das Zielverzeichnis enthalten.
Diese Unit-Dateien sind erheblich kürzer als traditionelle Init-Skripte. Syntaktisch ähneln sie den Ini-Dateien von Windows.
Den Typ einer Unit erkennt Systemd am Dateinamen. Dateien, die auf .service enden, legen Service-Units an; sie kümmern sich um Hintergrunddienste.
Units zum Ein- und Aushängen von Dateisystemen enden auf .mount; das Suffix lautet .automount, wenn dabei der Automounter involviert ist, der Dateisysteme beim Zugriff automatisch einhängt. Units mit dem Suffix .path weisen Systemd an, die spezifizierten Dateien und Verzeichnisse via Inotify überwachen; erfolgt dort ein Zugriff, startet Systemd diese Unit.
Auf .socket endende Unit-Dateien legen einen oder mehrere Sockets für die Socket-Aktivierung an. Der zugehörige Dienst wird erst dann über eine zu der Socket-Unit gehörende Service-Unit gestartet, wenn ein anderer Prozess Daten auf den Socket schreibt.
Der geöffnete Socket wird dabei an den Dienst übergeben – ähnlich wie es alte Unix-/Linux-Hasen von Inetd kennen.
Die Unit-Dateien von Systemd und den Systemdiensten liegen im Verzeichnis /lib/systemd/system/; liegt eine gleichnamige Datei in /etc/systemd/system/, ignoriert Systemd die im Lib-Verzeichnis.
Der Administrator kann so eine Unit-Datei von Systemd kopieren und an seine Belange anpassen, ohne fürchten zu müssen, dass sie beim nächsten Update überschrieben wird – das konnte bei Sysvinit-Distributionen passieren, wenn man eines der in /etc/rc.d/init.d/ gespeicherten Init-Skripte von Hand veränderte.
Systemd erzeugt einige Units dynamisch selbst; sie tauchen daher nicht im Dateisystem, sondern nur in der mit systemctl abrufbaren Liste der Units auf.
So wird für einige Geräte wie Datenträger, PCI-Geräte und TTYs im Zusammenspiel mit Udev automatisch eine Device-Unit generiert, wenn sie in den Udev-Regeln mit TAG+="systemd" gekennzeichnet sind.
Ähnlich wie beim Zweigespann aus Socket- und Service-Unit können andere Units von diesen Device-Units abhängen und so automatisch starten, wenn Geräte auftauchen, auf die sie angewiesen sind.
Dieses System kommt auch bei den .swap-Units zum Einsatz, die automatisch mit Hilfe der Angaben in /etc/fstab angelegt werden und die den Auslagerungsspeicher einbinden, sobald das spezifizierte Swap-Volume auftaucht.
Systemd erzeugt auch für einige andere in /etc/fstab spezifizierte Datenträger automatisch Mount-Units, daher tauchen in der Systemctl-Liste mehr Mount-Units auf, als man Konfigurationsdateien findet.
Ziele
Unit-Dateien, die auf .target enden, definieren Gruppen aus Units. Sie leisten selbst wenig, rufen vielmehr andere Units auf, die für Dienste, Dateisysteme und andere Dinge zuständig sind.
So lassen sich Boot-Ziele definieren, die den klassischen Sys-V-Runlevels entsprechen. Die Unit multi-user.target etwa sorgt für den Start all jener Dienste, die ältere Fedora- und OpenSuse-Versionen im Runlevel 3 aufrufen würden – voller Multiuser-Netzwerkbetrieb ohne grafischen Anmeldemanager.
Letzterer erscheint bei der Unit graphical.target, die damit das Äquivalent zum Runlevel 5 darstellt und typischerweise das Standard-Ziel ist.
Beim Hochfahren des Systems aktiviert Systemd die spezielle Target-Unit default.target, typischerweise ein Alias eines anderen Targets wie graphical.target oder multi-user.target.
Die Targets können zudem aufeinander aufbauen oder voneinander abhängen; graphical.target etwa wartet den Start von multi-user.target ab, bevor es die grafische Oberfläche startet.
Wo nötig lassen sich über die Angabe von "Wants" in den Unit-Dateien manuell Abhängigkeiten zwischen den Units definieren – wichtig beispielsweise für Dienste wie den Apache-Webserver, der beim Start eine voll konfigurierte Netzwerkumgebung erwartet.
Solche Dienste sollten von network.target abhängen. Bei Diensten wie Avahi oder Bind ist eine solche Abhängigkeit nicht nötig, da diese auch mit Netzwerk-Interfaces zurechtkommen, die zur Laufzeit erscheinen oder verschwinden.
Althergebrachtes
Aus Kompatibilitätsgründen versteht sich Systemd auch mit System-V- und LSB-Init-Skripten, die nicht nur von Sysvinit-Distributionen verwendet werden, sondern auch mit Upstart funktionieren.
Diese Init-Skripte werden durch eine Shell interpretiert und erfordern einen Parameter wie "start", "stop" oder "restart".
Auch die Hersteller kommerzieller Software legen ihren Hintergrunddiensten typischerweise Sys-V- und LSB-Init-Skripte bei. Um sie intern wie eine richtige Service-Unit zu behandeln, generiert Systemd daraus automatisch eine Service-Unit; das Init-Tool ignoriert allerdings Sys-V- und LSB-Init-Skripte, wenn es eine Unit-Datei mit gleichem Namen findet.
Gruppen
Systemd packt jeden Dienst beim Start in eine eigene, nach dem Dienst benannte Control Group. Diese Technik isoliert die Prozesse und bietet mit Hilfe optionaler Controller Stellschrauben, um die Verteilung der Ressourcen zu beeinflussen. Kindprozesse erben die Gruppenzugehörigkeit.
Systemd kann so Prozessgruppen als zusammengehörige Einheiten verwalten, um etwa beim Beenden eines Dienstes alle zugehörigen Prozesse zuverlässig zu stoppen. Administratoren können über die normalen Cgroup-Schnittstellen den Ressourcenverbrauch von Diensten kontrollieren; die manuelle Zuordnung der Prozesse entfällt.
Breiterer Ansatz
Systemd liegen eine Reihe von Units bei, die einige grundsätzliche Dinge bei der Initialisierung des Systems erledigen. Teilweise sind diese wie ein Hintergrunddienst angelegt.
Die Service-Unit fsck-root.service etwa veranlasst bei Bedarf eine Prüfung des Root-Dateisystems, bevor es durch remount-rootfs.service beschreibbar eingebunden wird.
Die Service-Units hwclock-load und hwclock-save sorgen für einen Abgleich der Zeit mit der Systemuhr.
Bei Sysvinit- und Upstart-Distributionen kümmern sich Shell-Skripte um derartige Aufgaben, etwa /etc/rc.sysinit oder eine Sammlung kleiner Skripte in /etc/rcS.d/.
Diese Skripte sind stark auf die jeweilige Distributionsfamilie zugeschnitten und verhalten sich daher bei Debian ganz anders als bei Fedora oder OpenSuse; das ist der Grund, warum man bei Fedora und RHEL in /etc/sysconfig/keyboard die Tastatur festlegen kann, dieses Verzeichnis bei Debian aber vergeblich sucht.
Viele Systemd-Units starten C-Programme, die schneller und robuster sein sollen als die Shell-Skipte, die diese Aufgaben bisher erledigten.
Mit der Integration dieser Dienste versucht Systemd viele Unterschiede zwischen den Distributionen aus der Welt zu schaffen.
Das erleichtert Entwicklern die Arbeit, denn sie können Unit-Dateien für ihre Dienste mitliefern und dabei die Dinge erwarten, die Systemd beiliegen.
Sys-V-Init-Skripte beizulegen ist erheblich schwieriger, weil diese auf distributionsspezifische Eigenarten Rücksicht nehmen müssen.
Details
Weitere Hintergründe zu Ideen, Arbeitsweisen und Einsatz von Systemd liefern die Man-Pages zu Systemd – etwa systemd und systemd.conf .
Auch für jeden der Unit-Typen gibt es Man-Pages – beispielsweise systemd.unit oder systemd.service . Über die Homepage von Lennart Poettering findet man zahlreiche Artikel , die Hintergründe zum Init-System erläutern, darunter die bislang zwei Teile umfassende Serie "systemd for Developers":* Part I: Socket Activation
- Part II: Socket Activation (Part II)
Im dritten "Systemd Status Update" hat Poettering zudem vor Kurzem einige der Neuerungen aufgelistet, die in den letzten eineinhalb Jahren in Systemd eingeflossen sind.
Im zweiten Teil des Artikels geht es um Systemd aus Adminsicht: Aufbau von Unit-Dateien, Befehle zum Auflisten, Starten und Stoppen von Units, Statusausgaben und Beheben von Problemen.
Systemd - Anschmeißer
Aktuelle Versionen von Fedora, OpenSuse, Mandriva und einigen anderen Distributionen starten das System bereits mit Systemd.
Das neue Init-System bringt eigene Werkzeuge zur Konfiguration und Diagnose mit und erfordert andere Kniffe als Sysvinit, wenn es Probleme gibt.
Das neue Init-Tool Systemd liegt schon mehreren Distributionen als Alternative zu Upstart oder dem angestaubten Sysvinit bei.
Einige von Sysvinit- und Upstart-Distributionen gewohnte Kommandos und Tricks arbeiten durch Kompatibilitätsmaßnahmen auch unter Systemd. Um die Fähigkeiten von Systemd richtig zu nutzen, sollte der Administrator allerdings auch Werkzeuge und Parameter von Systemd kennen.
Wichtigstes Tool zur Interaktion mit Systemd ist das Kommandozeilenprogramm systemctl. Für Änderungen an der Konfiguration oder den Neustart von Hintergrunddiensten erfordert es Root-Rechte; einige Diagnose-Aufrufe dürfen auch einfache Anwender ausführen.
Wer das Programm ohne jegliche Parameter aufruft, erhält eine Liste der "Units", die beim Systemstart anfallende Aufgaben erledigen. Dazu gehört neben dem Einbinden und Prüfen von Datenträgern auch das Starten von Hintergrunddiensten oder das Einrichten von Hardware.
Bei einer Standardinstallation von Fedora 16 listet Systemctl rund hundertsechzig aktive Units in zehn verschiedenen Spielarten. Zu den wichtigsten zählen Service-Units. Sie kümmern sich um Hintergrunddienste, die eine Sysvinit-Distribution typischerweise über Init-Skripte startet. Mount- und Automount-Units binden Dateisysteme ein.
Socket-Units legen Sockets an; sie starten indirekt über Abhängigkeiten einen andere Unit, sobald auf den Socket zugegriffen wird. (Eine detaillierte Erläuterung des Unit-Konzepts finden Sie im ersten Teil des Artikels.)
Über einen Parameter kann man Systemctl anweisen, nur Units eines bestimmten Typs aufzulisten, etwa alle Service-Units:
systemctl --type=service
Systemctl leitet seine Ausgabe automatisch an less weiter; über die Pfeiltasten lässt sich nicht nur hoch- und runterscrollen, sondern auch nach rechts, denn dort verbergen sich manchmal weitere Informationen.
In der ersten Spalte der Ausgabe findet sich der Unit-Name. Die zweite Spalte gibt an, ob Systemd die Unit-Definition laden konnte, die dritte, ob die Unit aktiv ist. Inaktive – installierte, aber nicht zum Start vorgesehene – Units gibt das Programm nur mit dem Schalter -a aus; dasselbe gilt für Units, die das Init-System etwa aufgrund eines Fehlers in der Unit-Datei nicht laden konnte.
Spalte vier liefert den aktuellen Status. "exited" zeigt an, dass sich der Prozess ohne Fehler beendet hat. Das ist zum Beispiel bei Diensten der Fall, die im Hintergrund weiterlaufen – etwa bei der Service-Unit, die aus Kompatibilitätsgründen die von Sysvinit bekannte Datei /etc/rc.local beim Systemstart ausführt. "running" steht bei Diensten, die im Hintergrund laufen: cron, dbus, sshd, udev und andere.
In der fünften Spalte folgt eine Beschreibung der Unit. Wenn sie mit "LSB" oder "SYSV" beginnt, hat Systemd die Unit automatisch erzeugt, um ein traditionelles Init-Skript abzuarbeiten.
Bei Diensten, die nicht gestartet werden konnten oder später abgestürzt sind, steht in der vierten Spalte "failed" – rot hervorgehoben, sofern die Konsole farbige Ausgabe beherrscht.
Das status-Kommando von sytemctl gibt den Zeitpunkt des Abbruchs und den zurückgelieferten Fehlercode des Programms aus, beispielsweise
Bei einem frisch installierten Fedora 16 listet Systemctl um die 60 Service-Units auf. Darunter sind auch die Login-Prozesse für die Textkonsolen (agetty), denn anders als Sysvinit handhabt Systemd diese über Service-Units wie einen normalen Hintergrunddienst.
Units ...
Die Konfigurationsdateien zum Erzeugen der Units, die Systemd mitbringt, liegen in /lib/systemd/system/; eine gleichnamige Datei in /etc/systemd/system/ hat jedoch Vorrang.
Unit-Definition sind meist deutlich kürzer als die klassischen Sys-V-Init-Skripte. Eine Unit-Datei für den Dienst zur Netzwerkzeit-Synchronisierung via NTP ist nur wenige Zeilen lang:
[Unit] Description=Network Time Service [Service] ExecStart=/usr/bin/ntpd -n -u ntp:ntp -g [Install] WantedBy=multi-user.target
Alle Unit-Dateien enthalten einen durch [Unit] eingeleiteten Abschnitt mit allgemeinen Einstellungen, darunter eine kurze Beschreibung. Im Abschnitt [Service] folgen dienstspezifische Angaben; bei NTP ist das lediglich das Kommando, um den Dienst zu starten. Falls ein spezieller Befehl zum Beenden nötig ist, kann man diesen über eine ExecStop-Anweisung festlegen.
Beim NTP-Daemon ist das unnötig, weil er sich in guter Unix-Tradition durch ein SIGTERM-Signal beenden lässt; das sendet Systemd zum Beenden, wenn kein anderer Befehl spezifiziert ist.
Der Abschnitt [Install] enthält Anweisungen, die Systemd bei der (De-)Installation interpretiert; der Eintrag im NTP-Beispiel bedeutet, dass die Zeitsynchronisation beim Ansteuern des Targets "Multi-User" aufgerufen werden soll.
... und Targets
Die Targets-Units bieten ein Konzept, das den Runlevels von Sysvinit ähnelt; aus Kompatibilitätsgründen versteht Systemd sogar die Runlevel-Namen zur Ansteuerung äquivalenter Targets.
Wie gewohnt kann man daher bei Fedora 16 dem Kernel im Boot-Loader den Parameter single mitgeben; Systemd steuert daraufhin rescue.target an, das eine minimale, dem Single-User-Modus entsprechende Umgebung bietet.
Auch 3 funktioniert, um den Multi-User-Modus ohne grafischen Anmeldemanager anzusteuern. Repräsentiert wird dieser Modus in Systemd durch die Target-Unit multi-user. Um multi-user.target zum Standard zu machen, reicht ein Links:
ln -sf /lib/systemd/system/multi-user.target /etc/systemd/system/default.target
Soll der grafische Anmeldemanager später doch wieder standardmäßig starten, kann man auf die gleiche Weise graphical.target zum Standardziel erheben; es ist das Äquivalent zum Runlevel 5 von Fedora und OpenSuse.
Alternativ zu den alten Runlevel-Bezeichnungen kann man dem Kernel auch die Namen der zu startenden Target-Unit mitgeben:
systemd.unit=multi-user.target
Um im Betrieb eine andere Target-Unit anzusteuern, dient das isolate-Kommando von Systemctl:
systemctl isolate rescue.target
Der Wechsel in das Rescue-Target ist für Administrationsaufgaben interessant, denn dabei beendet Systemd alle User-Logins und Hintergrunddienste, sodass nur noch Systemdienste laufen – etwa jene zur Überwachung von Logical Volumes (lvm2-monitor).
Manchmal müssen auch diese für Umbauten heruntergefahren werden, was mit dem Notfall-Modus emergency.target gelingt; hier laufen nur noch die Kernel-Threads.
Verlangen
Das show-Kommando von Systemctl liefert einige Interna zu den laufenden Units und den über sie ausgeführten Arbeiten. Mit ihm lässt sich auch ausgeben, welche Units Systemd beim Ansteuern des Multi-User-Targets aufruft:
systemctl show -p Wants multi-user.target
In der Ausgabe können sich andere Targets finden – beim multi-user.target etwa basic.target. Das wiederum hängt vom sysinit.target ab, das local-fs.target voraussetzt.
Diese drei Targets kümmern sich um die Grundeinrichtung des Systems; dazu zählen das Einbinden der Dateisysteme und der Start von Udev. Zum Spezifizieren der Abhängigkeit vom Basic-Target enthält die Unit-Konfigurationsdatei multi-user.target folgende Angaben:
Requires=basic.target After=basic.target
Durch die After-Angabe erfährt Systemd, dass es das Target nicht nur aufrufen, sondern auch den seinen vollständigen Start abwarten muss. Neben Requires gibt es auch noch das schwächere Wants.
Darüber angegebene Units ruft Systemd ebenfalls auf, setzt den Start aber auch fort, wenn eine von ihnen nicht startet.
Diese Art der Abhängigkeit lässt sich auch über Links zu Unit-Dateien spezifizieren, die in einem Verzeichnis angelegt werden, dessen Name sich aus dem Namen der target-Unit und angehängtem .wants zusammensetzen, etwa
Ausknipsen
Wer die NTPD-Service-Unit deaktivieren will, damit die Systemzeit beim Booten nicht via NTP synchronisiert wird, kann das folgenden Befehl tun:
systemctl disable ntpd.service
Dabei macht Systemctl nichts anderes, als den Link auf die Service-Unit-Datei in den Wants-Verzeichnissen zu entfernen; beim Aktivieren eines Dienstes mit enable erstellt das Tool einen Link. Beides kann man auch manuell tun, um Units zu (de)aktiviern.
Wird ein Dienst nicht von einer Unit, sondern über ein traditionelles Init-Skript gestartet, leitet Systemctl die Aufforderung zum Aktivieren an das Programm chkconfig weiter. Bei Fedora ist das etwa der Fall, wenn man Apache installiert und via Systemctl aktiviert.
Das (De)Aktivieren eines Dienstes wirkt sich erst beim nächsten Start oder Beenden des Systems aus. Folgendes Kommando startet einen Dienst einmalig sofort:
systemctl start ntpd.service
Der Parameter stop beendet den Dienst. Mit dem Kommando status liefert Systemctl Information über die Unit, darunter ihren derzeitigen Zustand und den Namen der sie spezifizierenden Datei. Zudem gibt das Programm aus, ob und wie lange der Dienst bereits läuft und welche Prozesse zu ihm gehören; den Hauptprozess weist Systemctl dabei explizit aus.
Über die Zugehörigkeit zu den von Systemd angelegten Control Groups lässt sich recht einfach herausfinden, welche Prozesse von welchem Dienst gestartet wurden. Die von Systemd angelegte Cgroup-Hierarchie gibt der Befehl systemd-cgls aus; alternativ zeigt ps die Gruppenzugehörigkeit an:
ps xaw -eo pid,args,cgroup
Abgesoffen
Falls beim Systemstart Probleme auftreten, an denen Systemd direkt oder indirekt beteiligt scheint, sollten Sie dem Kernel die folgenden Parameter im Boot-Loader mitgeben:
systemd.log_target=kmsg systemd.log_level=debug
Systemd schreibt dann ausführliche Informationen zur Fehlersuche auf die Konsole und in den Puffer der Kernel-Meldungen, den man später mit dmesg auslesen kann.
Zu Systemd gehören die Kommandozeilenprogramme poweroff, halt und reboot; alternativ kann man das System über die gleichlautenden Systemctl-Kommandos herunterfahren oder neu starten. Einen Neustart erreicht man auch mit dem Kommando
systemctl kexec
Nach dem Stoppen aller Dienste weist Systemd den laufenden Kernel an, einen zuvor konfigurierten Linux-Kernel direkt zu starten – ohne BIOS-Selbsttest und Boot-Loader. Ist kein Kexec-Kernel konfiguriert, erfolgt ein normaler Neustart.
Ranholen
Bei gängigen Administrationsaufgaben kommt man nur mit den Service- und Target-Units direkt in Kontakt; die anderen Units sind vor allem für spezielle Funktionen von Systemd wichtig oder erledigen beim Systemstart all jene Dinge, um die sich bei Sysvinit- und Upstart-Distributionen distributionsspezifische Skripte gekümmert haben.
Dazu gehört etwa das Einbinden der in /etc/fstab spezifizierten Dateisysteme, das Aktivieren von Auslagerungsspeicher oder das gelegentliche Aufräumen des /tmp-Verzeichnisses.
Für einige dieser Arbeiten bringt Systemd eine Automount-Funktion mit, die Pseudo-Einhängepunkte für in /etc/fstab konfigurierte Dateisysteme anlegen kann; tatsächlich eingebunden werden sie allerdings erst beim ersten Zugriff.
Das Hinzufügen von "comment=systemd.automount" in /etc/fstab verwandelt einen beliebigen Mount-Punkt in einen Automount-Punkt. Das kann den Startvorgang beschleunigen und ist beispielsweise für Netzwerkfreigaben nützlich, wenn die Netzverbindung über den NetworkManager erst beim Einloggen eines Users aufgebaut wird.
Ursachenforschung
Über Systemctl kann man Systemd zum Senden eines Signals auffordern, ohne die Prozess-ID des Dienstes zu kennen. Der folgende Befehl versetzt Rsyslogd in den Debug-Modus; dieser wird beendet, wenn man den Befehl ein zweites Mal aufruft:
systemctl kill --signal=USR1 rsyslogd.service
Wenn man die Angabe des zu sendenden Signals weglässt, schickt Systemctl ein normales Term-Signal, woraufhin sich alle Prozesse beenden sollten, die zu einem Dienst gehören.
Der Befehl systemd-analyze gibt aus, wie lange der Systemstart gedauert hat und wie viel Zeit davon auf Kosten von Kernel, Initramfs und die Einrichtung des Userlands durch Systemd entfallen. Der Befehl systemd-analyze blame gibt die Startzeiten der einzelnen Units aus. Zur genaueren Betrachtung des Boot-Prozesses kann das Programm eine SVG-Datei erzeugen, die den Start der Units visualisert:
systemd-analyze plot > plot.svg
Manchmal kommt man so Units auf die Spur, die den Systemstart stark in die Länge ziehen. Einige Hinweise zur korrekten Interpretation dieser Ergebnisse liefert der siebte Teil der Blog-Reihe "Systemd for Administrators".
Die bislang zwölf Teile umfassende Serie enthält auch noch viele andere Tipps und Hinweise für den Praxiseinsatz vom Systemd: # Verifying Bootup
- Which Service Owns Which Processes?
- How Do I Convert A SysV Init Script Into A systemd Service File?
- Killing Services
- The Three Levels of "Off"
- Changing Roots
- The Blame Game
- The New Configuration Files
- On /etc/sysconfig and /etc/default
- Instantiated Services
- Converting inetd Services
- Securing Your Services
Über die Homepage von Lennart Poettering finden sich zudem zahlreiche weitere Artikel mit Hintergründen zum Init-System. Im dritten "Systemd Status Update" hat Poettering zudem vor Kurzem einige der Neuerungen aufgelistet, die in den letzten eineinhalb Jahren in Systemd eingeflossen sind.
Dienste gezielt konfigurieren
Systemd startet im Bootprozess unter anderem einen SSH-Daemon, hängt eine Partition ein und konfiguriert eine Netzwerkschnittstelle.
Alle diese einzelnen kleinen Aufgaben bezeichnet Systemd als Units. Die wiederum lassen sich noch einmal nach ihrem jeweiligen Einsatzzweck klassifizieren.
So kümmern sich Service-Units um das Starten und Stoppen von Diensten, Mount- und Automount-Units helfen beim Ein- und Aushängen von Dateisystemen, während wiederum Socket-Units die benötigten Sockets öffnen.
Für jede dieser Units muss der Administrator eine eigene kleine Konfigurationsdatei erstellen. Ihr Dateiname setzt sich aus dem Namen der Unit und dem entsprechenden Unit-Typ zusammen.
Beim SSH-Daemon handelt es sich zweifelsohne um einen Dienst, weshalb die Konfigurationsdatei »sshd.service« heißt.
Systemd bringt bereits Unit-Dateien für die wichtigsten Systemdienste mit. Diese lagern normalerweise im Unterverzeichnis "/usr/lib/systemd/system/" (in früheren Systemd-Versionen "/lib/systemd/system").
Zusätzlich existiert noch das Verzeichnis "/etc/systemd/system/". In ihm sollen Administratoren ihre eigenen Unit-Dateien speichern. Alle dort gelagerten Unit-Dateien haben Vorrang vor den Einstellungen ihrer gleichnamigen Kolleginnen unter "/usr/lib/systemd/system/".
Diese Trennung hat den Vorteil, dass ein Update der Distribution keine geänderte Unit-Datei überschreibt.
Listing sshd.service
[Unit] Description=OpenSSH server daemon After=syslog.target network.target auditd.service [Service] EnvironmentFile=/etc/sysconfig/sshd ExecStartPre=/usr/sbin/sshd-keygen ExecStart=/usr/sbin/sshd -D $OPTIONS ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s [Install] WantedBy=multi-user.target
Target-Auswahl
Systemd startet immer automatisch das "default.target". Ein anderes Target können Sie am Bootprompt über den Parameter "systemd.unit" vorgeben.
Mit "systemd.unit=rescue.target" würde Systemd beispielsweise ein Rettungssystem starten. "default.target" ist zudem für gewöhnlich nur ein symbolischer Link auf ein anderes Target, bei einem Desktop-System etwa auf "graphical.target".
Wer ein anderes Target zum Standard küren möchte, muss somit lediglich den Link umbiegen. In folgendem Fall würde Systemd zukünftig immer in das "multi-user.target" starten:
ln -s /usr/lib/systemd/system/multi-user.target
/etc/systemd/system/default.target
Um den Prozess eines Dienstes abzuschießen, müssen Sie lediglich den Namen der Service-Unit kennen, um den Rest kümmert sich "systemctl".
Im folgenden Beispiel sendet Systemd ein SIGTERM-Signal an den SSH-Daemon:
systemctl kill --signal=SIGTERM sshd.service
Das Kommando "systemctl reboot" startet das System neu, "systemctl poweroff" fährt das System kontrolliert herunter und schaltet es aus. Ergänzend zu "poweroff" gibt es noch "suspend", "hibernate" und "hybrid-sleep", die in die entsprechenden Schlafzustände wechseln.
Zu diesen Befehlen gibt es noch handliche Kurzformen, anstelle von "systemctl reboot" funktioniert beispielsweise auch einfach "reboot".
Bild 3: Dieses System mit CentOS 7 hat knapp 50 Sekunden für den kompletten Start benötigt. Gebremst haben vor allem Plymouth und die Firewall (in Form von "firewalld").
Changing the Default Boot Target
$ ln -sf /usr/lib/systemd/system/multi-user.target /etc/systemd/system/default.target
This line makes the multi user target (i.e. full system, but no graphical UI) the default target to boot into. This is kinda equivalent to setting runlevel 3 as the default runlevel on Fedora/sysvinit systems.
$ ln -sf /usr/lib/systemd/system/graphical.target /etc/systemd/system/default.target
This line makes the graphical target (i.e. full system, including graphical UI) the default target to boot into. Kinda equivalent to runlevel 5 on fedora/sysvinit systems. This is how things are shipped by default.
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 |
Units gleichzeitig starten
Ein neu gestarteter Server sollte ein funktionierendes Netzwerk bieten, den Multiuser-Betrieb unterstützen und schließlich auch noch den SSH-Daemon zünden. Systemd muss folglich automatisch ein paar fest vorgegebene Units starten.
Um das zu erleichtern, lassen sich mehrere Units zu einer Gruppe zusammenfassen, dem sogenannten Target. Systemd kann dann alle Units aus einem Target auf einen Schlag starten beziehungsweise aktivieren.
Einige praxisrelevante Targets liegen Systemd bereits bei. So umfasst das Target "multi-user.target" alle Units, die für den Multiuser-Netzwerkbetrieb notwendig sind, während das Target "graphical.target" zu einem Desktop mit grafischer Benutzeroberfläche führt.
Die Targets ersetzen damit gleichzeitig die alten Runlevel von SysV-Init: Weist der Administrator Systemd an, das Target "graphical.target" zu aktivieren, sitzt er anschließend vor einem System mit grafischer Benutzeroberfläche, wie es üblicherweise der Runlevel 5 zur Verfügung stellt.
Targets sind selbst wieder normale Units. Das hat den Vorteil, dass ein Target ein anderes verwenden beziehungsweise starten kann.
Das nutzen die mitgelieferten Targets massiv aus: "graphical.target" aktiviert etwa erst dann die grafische Benutzeroberfläche, wenn "multi-user.target" das restliche System eingerichtet hat.
What units does a unit depend on?
For example, if you want to figure out which services a target like multi-user.target pulls in, use something like this:
$ systemctl show -p "Wants" multi-user.target
Wants=rc-local.service avahi-daemon.service rpcbind.service NetworkManager.service acpid.service dbus.service atd.service crond.service auditd.service ntpd.service udisks.service bluetooth.service cups.service wpa_supplicant.service getty.target modem-manager.service portreserve.service abrtd.service yum-updatesd.service upowerd.service test-first.service pcscd.service rsyslog.service haldaemon.service remote-fs.target plymouth-quit.service systemd-update-utmp-runlevel.service sendmail.service lvm2-monitor.service cpuspeed.service udev-post.service mdmonitor.service iscsid.service livesys.service livesys-late.service irqbalance.service iscsi.service netfs.service
Instead of "Wants" you might also try "WantedBy", "Requires", "RequiredBy", "Conflicts", "ConflictedBy", "Before", "After" for the respective types of dependencies and their inverse.
Aufbau der Unit-Dateien
Unit-Dateien sind recht einfach aufgebaut. Das Listing "sshd.service" zeigt als Beispiel die Unit-Datei des SSH-Daemons aus CentOS 7 und damit schon einen etwas umfangreicheren Vertreter. Jede Unit-Datei ist in mehrere Abschnitte unterteilt, jede Zeile enthält genau eine Einstellung.
Im Abschnitt "[Unit]" liefert "Description=" zunächst eine kurze Beschreibung der Unit. Hinter "After=" folgen, jeweils durch ein Leerzeichen getrennt, alle Units und Targets, die der Dienst zwingend für seine Arbeit benötigt.
Im Beispiel startet der SSH-Daemon erst dann (und wirklich erst dann), wenn die Logging-Dienste ("syslog.target"), das Netzwerk ("network.target") und der Audit-Dienst ("auditd.service") verfügbar sind.
Neben "After" gibt es noch die etwas weniger restriktiven "Requires" und "Wants": Alle Units hinter "Requires=" startet Systemd parallel mit der neu definierten Unit.
Deaktiviert der Administrator eine der aufgeführten Units, knipst Systemd auch automatisch der neuen Unit das Licht aus. Sämtliche hinter "Wants=" gelisteten Units startet Systemd ebenfalls parallel mit der neu definierten Unit.
Letztgenannte aktiviert Systemd aber selbst dann, wenn eine der anderen Units abstürzt oder aus einem anderen Grund nicht verfügbar ist.
Im Abschnitt "[Service]" folgen alle Informationen, die Systemd zum Aktivieren des Dienstes benötigt. Der Befehl zum Starten des SSH-Daemons findet sich hinter "ExecStart=", alle anderen Angaben sind optional. Im Listing "sshd.service" holt zunächst "EnvironmentFile=" ein paar Umgebungsvariablen aus der angegebenen Datei hinzu. Das Programm hinter "ExecStartPre=" führt Systemd immer direkt vor dem eigentlichen Dienst aus.
Wenn Systemd den Dienst beenden muss, schickt er ihm ein SIGTERM-Signal, auf das alle guten Prozesse reagieren sollten. Im Listing "sshd.service" sorgt "KillMode=process" noch dafür, dass Systemd nur den SSH-Daemon selbst, nicht aber seine Kindprozesse abwürgt. Lässt sich der Dienst anders als der SSH-Daemon nur mit einem speziellen Befehl herunterfahren, notiert man diesen hinter "ExecStop=".
Mit welchem Kommando Systemd den Dienst neu startet, verrät "ExecReload=". Wann das passiert, bestimmt der Wert hinter "Restart=". In Listing "sshd.service" passiert das automatisch, wenn sich der SSH-Daemon unerwartet beendet ("on-failure").
Mit dem Neustart wartet Systemd zudem sicherheitshalber 42 Sekunden ("RestartSec=42s"). Diese Verzögerung soll unter anderem verhindern, dass der Dienst immer wieder schnell hintereinander neu startet und so unnötig Rechenzeit frisst.
Der Abschnitt "[Install]" verrät schließlich noch, zu welchen Targets die Unit gehört. Im Listing sorgt die letzte Zeile dafür, dass der SSH-Daemon immer zusammen mit dem Target "multi-user.target" startet.
Alternativ können Sie die Zugehörigkeit auch über symbolische Links vorgeben. Dazu erstellen Sie zunächst im Verzeichnis "/etc/systemd/system/" ein neues Unterverzeichnis. Dieses erhält den Namen des Targets mit einem angehängten ".wants".
Möchten Sie beispielsweise den SSH-Daemon im Target "multi-user.target" starten lassen, erstellen Sie das Unterverzeichnis "multi-user.target.wants". In ihm setzen Sie dann wiederum einen symbolischen Link auf die Unit-Datei des Dienstes, im Beispiel also auf »/lib/systemd/system/sshd.service« .
Damit startet dann der SSH-Daemon immer dann, wenn Systemd das Target "multi-user.target" aktiviert.
Change a service file
rpm keeps overwriting it in /usr/lib/systemd/system all the time. How to handle this?
The recommended way is to copy the service file from /usr/lib/systemd/system to /etc/systemd/system and edit it there. The latter directory takes precedence over the former, and rpm will never overwrite it.
If you want to use the distributed service file again you can simply delete (or rename) the service file in /etc/systemd/system again.
My service foo.service
as distributed by my operating system vendor is only started when (a connection comes in or some hardware is plugged in). I want to have it started always on boot, too. What should I do?
Simply place a symlink from that service file in the multi-user.target.wants/ directory (which is where you should symlink everything you want to run in the old runlevel 3, i.e. the normal boot-up without graphical UI.
It is pulled in by graphical.target too, so will be started for graphical boot-ups, too):
# ln -sf /usr/lib/systemd/system/foobar.service /etc/systemd/system/multi-user.target.wants/foobar.service # systemctl daemon-reload
Services After the Network is up
My service is ordered after network.target but at boot it is still called before the network is up. What's going on?
That's a long story, and that's why we have a wiki page of its own about this: Running Services After the Network is up (http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget).
RT scheduling
Whenever my service tries to acquire RT scheduling for one of its threads this is refused with EPERM even though my service is running with full privileges. This works fine on my non-systemd system!
By default, systemd places all systemd daemons in their own cgroup in the "cpu" hierarchy.
Unfortunately, due to a kernel limitation, this has the effect of disallowing RT entirely for the service. See My Service Can't Get Realtime! for a longer discussion and what to do about this.
Steuerzentrale systemctl
Administratoren steuern Systemd über das Kommandozeilenprogramm "systemctl". Rufen Sie es ohne weitere Parameter auf, präsentiert es alle ihm bekannten Units (Bild 1).
Auf einem frisch gestarteten CentOS 7 mit grafischer Benutzeroberfläche sind das um die 130 Stück. Wer nur an bestimmten Units interessiert ist, kann die Anzeige über den Parameter "--type=" einschränken.
Alle Dienste präsentiert etwa "systemctl --type=service". Die Ausgaben von "systemctl" zeigt standardmäßig "less" an, die Navigation erfolgt mit den Pfeiltasten und der Leertaste, [q] wiederum beendet die Anzeige.
Neben dem Namen der Unit verrät "systemctl" in der zweiten und dritten Spalte, ob es die Unit laden und aktivieren konnte. Die Spalte "SUB" gibt Auskunft über den derzeitigen Status: Bei einem Dateisystem erfährt man etwa, ob dieses gemountet ist, bei einem Dienst hingegen, ob dieser läuft ("running").
In der letzten Spalte findet man schließlich noch eine kurze Beschreibung der Unit. Sofern ein Dienst beim Start nicht hochfahren wollte oder abgestürzt ist, markiert "systemctl" dies in seiner Ausgabe in hell leuchtendem Rot.
Eine Liste mit allen nicht funktionierenden Units liefert "systemctl --failed", detaillierte Informationen über eine Unit zeigt ein Aufruf von "systemctl status" an (Bild 2).
In bestimmten Situationen erzeugt Systemd selbst eine Unit. Das passiert beispielsweise nach dem Anstöpseln eines neuen Gerätes.
Die dann unter Umständen mithilfe von Udev generierten Units erscheinen zwar in der Ausgabe von "systemctl", es existieren aber keine passenden Unit-Dateien auf der Festplatte. Von diesen dynamisch generierten Units dürfen aber wiederum andere Units abhängen.
Änderungen nur mit root
Alle bisher vorgestellten Informationen darf jeder Nutzer abfragen. Um Änderungen an der Konfiguration vorzunehmen, müssen Sie "systemctl" jedoch mit Root-Rechten starten.
Dann lassen sich einzelne Units über »systemctl start« aktivieren beziehungsweise mit »systemctl stop« anhalten. Der folgende Befehl fährt den SSH-Daemon hoch:
systemctl start sshd.service
Auf Systemen mit SysV-Init würde dies dem Aufruf des Skripts "/etc/init.d/sshd start" entsprechen. Vergessen Sie im Unit-Namen den Typ, geht Systemd von ".service" aus.
Den SSH-Daemon könnten Sie folglich einfach mit »systemctl start sshd« anwerfen. "systemctl" wechselt natürlich auch Targets.
Der folgende Befehl aktiviert beispielsweise das Target "rescue.target", was wiederum zu einem Rettungssystem führt:
systemctl isolate rescue.target
Die Angabe "isolate" sorgt dafür, dass ausschließlich die von "rescue.target" vorgegebenen Units aktiv sind, alle anderen Dienste und Units beendet Systemd.
Um zu verhindern, dass ein Dienst beim Systemstart automatisch hochfährt, deaktivieren Sie ihn:
systemctl disable sshd.service
In diesem Beispiel würde Systemd den SSH-Daemon aus sämtlichen Targets nehmen. Mit "enable" knipsen Sie ihn wieder an:
systemctl enable sshd.service
Damit gehört der SSH-Daemon wieder zu allen Targets, die in seiner Unit-Datei (aus dem Listing "sshd.service") hinter "WantedBy" vermerkt sind.
Im Hintergrund setzt Systemd dabei übrigens lediglich die symbolischen Links in den ".wants"-Unterverzeichnissen.
Bild 2: In den Status-Informationen liefert "systemctl" unter anderem auch die PID (hier die 1270) und die Laufzeit des Dienstes (hier über eine Stunde).
Wichtige Systemd-Befehle im Überblick
systemctl | |
systemctl start sshd.service | |
systemctl stop sshd.service | |
systemctl disable sshd.service | |
systemctl enable sshd.service | |
systemctl --failed | |
systemctl isolate graphical.target | |
systemctl isolate multi-user.target | |
systemctl daemon-reload |
|
Listing running services
$ systemctl UNIT LOAD ACTIVE SUB JOB DESCRIPTION accounts-daemon.service loaded active running Accounts Service atd.service loaded active running Job spooling tools avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack bluetooth.service loaded active running Bluetooth Manager colord-sane.service loaded active running Daemon for monitoring attached scanners and registering them with colord colord.service loaded active running Manage, Install and Generate Color Profiles crond.service loaded active running Command Scheduler cups.service loaded active running CUPS Printing Service dbus.service loaded active running D-Bus System Message Bus ...
Showing runtime status
$ systemctl status udisks2.service udisks2.service - Storage Daemon
Loaded: loaded (/usr/lib/systemd/system/udisks2.service; static) Active: active (running) since Wed, 27 Jun 2012 20:49:25 +0200; 1 day and 1h ago Main PID: 615 (udisksd) CGroup: name=systemd:/system/udisks2.service └ 615 /usr/lib/udisks2/udisksd --no-debug
Jun 27 20:49:25 epsilon udisksd[615]: udisks daemon version 1.94.0 starting Jun 27 20:49:25 epsilon udisksd[615]: Acquired the name org.freedesktop.UDisks2 on the system message bus
Runlevel
What would get started?
… if I booted into a specific target?
If you want systemd to calculate the "initial" transaction it would execute on boot, try something like this:
$ systemd --test --system --unit=foobar.target
for a boot target foobar.target. Note that this is mostly a debugging tool that actually does a lot more than just calculate the initial transaction, so don't build scripts based on this.
Change current runlevel
In systemd runlevels are exposed via "target units". You can change them like this:
# systemctl isolate runlevel5.target
Note however, that the concept of runlevels is a bit out of date, and it is usually nicer to use modern names for this. e.g.:
# systemctl isolate graphical.target
This will only change the current runlevel, and has no effect on the next boot.
Change default runlevel
The symlink /etc/systemd/system/default.target controls where we boot into by default. Link it to the target unit of your choice. For example, like this:
or
Current runlevel
Note that there might be more than one target active at the same time. So the question regarding the runlevel might not always make sense. Here's how you would figure out all targets that are currently active:
If you are just interested in a single number, you can use the venerable runlevel command, but again, its output might be misleading.
Enable another getty
Simply instantiate a new getty service for the port of your choice (internally, this places another symlink for instantiating another serial getty in the getty.target.wants/ directory).
# systemctl enable serial-getty@ttyS2.service # systemctl start serial-getty@ttyS2.service
Note that gettys on the virtual console are started on demand. You can control how many you get via the NAutoVTs= setting in logind.conf(7). Also see this blog story.
Which service a process belongs to?
You may either use ps for that:
$ alias psc='ps xawf -eo pid,user,cgroup,args' $ psc ...
Or you can even check /proc/$PID/cgroup directly. Also see this blog story.
journalctl - display full messages
Even if less is not used?
A: Use:
# journalctl --full
/tmp and tmpfs
My systemd system always comes up with /tmp as a tiny tmpfs. How do I get rid of this?
That's also a long story, please have a look on:* API File Systems (http://www.freedesktop.org/wiki/Software/systemd/APIFileSystems)
cgroups
cgroup tree
$ systemd-cgls └ system
├ 1 /usr/lib/systemd/systemd --system --deserialize 18 ├ ntpd.service │ └ 8471 /usr/sbin/ntpd -u ntp:ntp -g ├ upower.service │ └ 798 /usr/libexec/upowerd ├ wpa_supplicant.service │ └ 751 /usr/sbin/wpa_supplicant -u -f /var/log/wpa_supplicant.log -c /etc/wpa_supplicant/wpa_supplicant.conf -u -f /var/log/wpa_supplicant.log -P /var/run/wpa_supplicant.pid ├ nfs-idmap.service │ └ 731 /usr/sbin/rpc.idmapd ├ nfs-rquotad.service │ └ 753 /usr/sbin/rpc.rquotad ├ nfs-mountd.service │ └ 732 /usr/sbin/rpc.mountd ├ nfs-lock.service │ └ 704 /sbin/rpc.statd ├ rpcbind.service │ └ 680 /sbin/rpcbind -w ├ postfix.service │ ├ 859 /usr/libexec/postfix/master │ ├ 877 qmgr -l -t fifo -u │ └ 32271 pickup -l -t fifo -u ├ colord-sane.service │ └ 647 /usr/libexec/colord-sane ├ udisks2.service │ └ 615 /usr/lib/udisks2/udisksd --no-debug ├ colord.service │ └ 607 /usr/libexec/colord ├ prefdm.service │ ├ 567 /usr/sbin/gdm-binary -nodaemon │ ├ 602 /usr/libexec/gdm-simple-slave --display-id /org/gnome/DisplayManager/Display1 │ ├ 612 /usr/bin/Xorg :0 -br -verbose -auth /var/run/gdm/auth-for-gdm-O00GPA/database -seat seat0 -nolisten tcp │ └ 905 gdm-session-worker [pam/gdm-password] ├ systemd-ask-password-wall.service │ └ 645 /usr/bin/systemd-tty-ask-password-agent --wall ├ atd.service │ └ 544 /usr/sbin/atd -f ├ ksmtuned.service │ ├ 548 /bin/bash /usr/sbin/ksmtuned │ └ 1092 sleep 60 ├ dbus.service │ ├ 586 /bin/dbus-daemon --system --address=systemd: --nofork --systemd-activation │ ├ 601 /usr/libexec/polkit-1/polkitd --no-debug │ └ 657 /usr/sbin/modem-manager ├ cups.service │ └ 508 /usr/sbin/cupsd -f ├ avahi-daemon.service │ ├ 506 avahi-daemon: running [epsilon.local] │ └ 516 avahi-daemon: chroot helper ├ system-setup-keyboard.service │ └ 504 /usr/bin/system-setup-keyboard ├ accounts-daemon.service │ └ 502 /usr/libexec/accounts-daemon ├ systemd-logind.service │ └ 498 /usr/lib/systemd/systemd-logind ├ crond.service │ └ 486 /usr/sbin/crond -n ├ NetworkManager.service │ ├ 484 /usr/sbin/NetworkManager --no-daemon │ └ 8437 /sbin/dhclient -d -4 -sf /usr/libexec/nm-dhcp-client.action -pf /var/run/dhclient-wlan0.pid -lf /var/lib/dhclient/dhclient-903b6f6aa7a1-46c8-82a9-7f637dfbb3e4-wlan0.lease -cf /var/run/nm-d... ├ libvirtd.service │ ├ 480 /usr/sbin/libvirtd │ └ 571 /sbin/dnsmasq --strict-order --bind-interfaces --pid-file=/var/run/libvirt/network/default.pid --conf-file= --except-interface lo --listenaddress 192.168.122.1 --dhcp-range 192.168.122.2,1... ├ bluetooth.service │ └ 479 /usr/sbin/bluetoothd -n ├ systemd-udev.service │ └ 287 /usr/lib/systemd/systemd-udevd └ systemd-journald.service └ 280 /usr/lib/systemd/systemd-journald
ps with cgroups
$ alias psc='ps xawf -eo pid,user,cgroup,args' $ psc
PID USER CGROUP COMMAND
...
1 root name=systemd:/systemd-1 /bin/systemd systemd.log_target=kmsg systemd.log_level=debug selinux=0 415 root name=systemd:/systemd-1/sysinit.service /sbin/udevd -d 928 root name=systemd:/systemd-1/atd.service /usr/sbin/atd -f 930 root name=systemd:/systemd-1/ntpd.service /usr/sbin/ntpd -n 932 root name=systemd:/systemd-1/crond.service /usr/sbin/crond -n 935 root name=systemd:/systemd-1/auditd.service /sbin/auditd -n 943 root name=systemd:/systemd-1/auditd.service \_ /sbin/audispd 964 root name=systemd:/systemd-1/auditd.service \_ /usr/sbin/sedispatch 937 root name=systemd:/systemd-1/acpid.service /usr/sbin/acpid -f 941 rpc name=systemd:/systemd-1/rpcbind.service /sbin/rpcbind -f 944 root name=systemd:/systemd-1/rsyslog.service /sbin/rsyslogd -n -c 4 947 root name=systemd:/systemd-1/systemd-logger.service /lib/systemd/systemd-logger 950 root name=systemd:/systemd-1/cups.service /usr/sbin/cupsd -f 955 dbus name=systemd:/systemd-1/messagebus.service /bin/dbus-daemon --system --address=systemd: --nofork --systemd-activation 969 root name=systemd:/systemd-1/getty@.service/tty6 /sbin/mingetty tty6 970 root name=systemd:/systemd-1/getty@.service/tty5 /sbin/mingetty tty5 971 root name=systemd:/systemd-1/getty@.service/tty1 /sbin/mingetty tty1 973 root name=systemd:/systemd-1/getty@.service/tty4 /sbin/mingetty tty4 974 root name=systemd:/user/lennart/2 login -- lennart 1824 lennart name=systemd:/user/lennart/2 \_ -bash 975 root name=systemd:/systemd-1/getty@.service/tty3 /sbin/mingetty tty3 988 root name=systemd:/systemd-1/polkitd.service /usr/libexec/polkit-1/polkitd 994 rtkit name=systemd:/systemd-1/rtkit-daemon.service /usr/libexec/rtkit-daemon
...
Tools
systemd-ui
Graphical front-end for systemd
Graphical front-end for systemd system and service manager.
kcmsystemd
A systemd control module for KDE
Systemd control module for KDE. Provides a graphical frontend for the systemd daemon, which allow for viewing and controlling systemd units, as well as modifying configuration files. Integrates in the System Settings dialogue in KDE.
Lahme Dienste bloßstellen
Da Systemd den Bootprozess recht früh kontrolliert, kann es ihn auch umfassend protokollieren und analysieren. So verrät ein Aufruf von "systemd-analyze", wie lange der letzte Startvorgang insgesamt gedauert hat.
"systemd-analyze blame" zeigt detailliert an, welcher Dienst wie lange für seinen Start benötigt (Bild 3).
Besonders langsame Dienste stehen dabei in der Liste weiter oben. Der folgende Befehl zeichnet die Startdauer der Dienste in eine Zeitleiste ein:
systemd-analyze plot > bootchart.svg
Die fertige Grafik landet dabei in der Datei »bootchart.svg« (Bild 4). Sofern die Software Graphviz installiert ist, erstellt der folgende Befehl einen Dependency Graph:
systemd-analyze dot | dot -Tsvg > abhaengigkeiten.svg
In ihm sind alle gestarteten Dienste und ihre jeweiligen Abhängigkeiten eingezeichnet. Mit diesen grafischen Darstellungen lassen sich bremsende Dienste recht schnell entlarven.
Sowohl der Graph als auch die Zeitskala sind allerdings bei Desktop-Systemen recht groß, Administratoren sollten daher einen Bildbetrachter mit Zoom-Funktion verwenden.
Immerhin hebt "systemd-analyze" trödelnde Dienste farblich hervor.
Wer nur am Pfad mit den zeitkritischen Diensten interessiert ist, kann ihn sich für das aktuelle Target mit "systemd-analyze critical-chain" direkt an der Konsole ausgeben lassen.
Wie lange ein Dienst zum Starten benötigt hat, steht dabei hinter dem "+". Neben dem "@" notiert das Tool, zu welchem Zeitpunkt Systemd den Dienst aktiviert beziehungsweise gestartet hat.
Bild 4: "systemd-analyze" kann auch eine solche Zeitleiste erstellen. Je länger dabei der Balken ist, desto länger hat der Start der jeweiligen Unit gedauert.
Syslog
Besser protokolliert
Log-Meldungen verwaltet in den allermeisten Fällen ein Syslog-Server. Das Fedora-Projekt will dieses jetzt ändern und in zukünftigen Releases neue Wege beschreiten. Hier soll dann Journald aus dem Systemd-Paket zum Einsatz kommen.
Wenn ich mich mit jemandem über das Thema System- und Service-Management unterhalte, stelle ich oft eine gewisse Verunsicherung fest, wenn wir auf das Thema "systemd" zu sprechen kommen. Deshalb an dieser Stelle eine kleine Einführung und ein paar Gründe, die für ein neues Init-System sprechen. Man ist es zwar irgendwie gewohnt, dass sich ein SysV-basierter Init-Prozess um den Systemstart kümmert, da dieses System aber in die Jahre gekommen ist und aktuelle Anforderungen nicht mehr wirklich gut erfüllt, wird es Zeit für einen Nachfolger. Dieser existiert eigentlich bereits seit geraumer Zeit mit Upstart.
Upstart ist zum größten Teil abwärtskompatibel mit dem alten SysV-System und löst viele der alten Probleme. Anstatt eine vordefinierte Liste abzuarbeiten, welche Dienste zu starten sind, ist Upstart Event-basiert. Auf Basis dieser Events finden dann Aktionen statt. All diese Event-/Aktionsregeln definiert der Administrator beziehungsweise Entwickler eines Dienstes in den Upstart-Konfigurationsdateien. Und hier liegt genau das Problem von Upstart. Passt man nicht genau auf, welche Events von anderen Events abhängig sind, erhält man eine Reihe von Abhängigkeiten, die dann dafür sorgen, dass Dienste wieder aufeinander warten müssen, bevor sie starten können. Und genau dies möchte man ja verhindern.
Problem gelöst
Lennart Poettering und sein Team wollen mit ihrer Implementierung eines neuen Init-Systems dieses (und andere) Probleme lösen und gehen sogar noch einen Schritt weiter. Die »systemd« genannte Software startet einfach alle Dienste parallel, ohne sich dabei um Abhängigkeiten zu kümmern. Möchte ein Dienst auf einen anderen Dienst zugreifen, so landen die Anfragen einfach so lange in einer Warteschlange, bis der gewünschte Dienst verfügbar ist. Dieser von Apples »launchd« bekannte Trick sorgt dafür, dass ein System extrem schnell hochfährt. Neben dieser Funktion bietet »systemd« natürlich noch viele weitere Neuerungen. Interessant ist auch, dass jeder durch »systemd« gestartete Prozess in einer eigenen Control-Group (Cgroup) landet und somit unter der Kontrolle des Kernels steht. Eine sehr gute und sehr ausführliche Beschreibung des neuen Init-Systems findet sich unter [1].
An dieser Stelle geht es nun um eine Funktion von Systemd, die bereits seit der Version 38 zur Verfügung steht: das Journal. Hierbei handelt es sich um ein neuartiges Logging-System, das, ähnlich wie Systemd selbst, radikale Änderungen mit sich bringt und einige grundlegende Probleme des alten Syslogd beheben möchte. Davon gibt es in der Tat genügend. So sieht das Syslog-Protokoll beispielsweise nicht vor, eine Log-Meldung zu authentifizieren. Jeder ist in der Lage, Meldungen von einem bestimmten Prozess vorzutäuschen beziehungsweise zu verändern.
Das Log-Format selbst sieht nur wenige Felder vor, die in jeder Nachricht zu verwenden sind, beispielsweise den Prozessnamen und die ID des Prozesses. Der Inhalt der Nachricht wird zumeist so aufbereitet, dass er für einen Menschen gut leserlich ist. Jedoch ist das manuelle Durchforsten von Log-Dateien nicht wirklich effektiv, sodass in den allermeisten Fällen doch wieder ein Log-Parser zum Einsatz kommt. Dieser muss dann den umgekehrten Weg beschreiten und die Nachricht so zerlegen, dass ihre Informationen lesbar werden – alles nicht sehr effektiv.
Hinzu kommt noch das Problem, dass die Syslog-Meldungen ja nicht die einzigen Logs auf einem System darstellen. Es existieren auch noch Logs von anderen Subsystemen, die nicht auf Syslog zurückgreifen. Die Audit- und Accounting-Subsysteme sind Beispiele hierfür. Dann gibt es natürlich auch jede Menge Anwendungen, die ihre eigenen Logs verwenden. Am Ende sind es also eine Vielzahl unterschiedlicher Log-Mechanismen, mit denen man sich auseinandersetzen muss. Der in Systemd integrierte Journald versucht all diese Probleme zu lösen und stellt ein einheitliches Log für sämtliche Komponenten eines Systems zur Verfügung.
Anwendungen und Services können beliebige Meta-Informationen an den Journald weiterreichen. Dies erfolgt entweder mittels »printk()« , der regulären »syslog()« -Funktion, über die native API oder für Coredumps mittels »/proc/proc/sys/kernel/core_pattern« . Die Informationen werden als Key-/Value- Paare übergeben und können einzeln abgefragt werden. Log-Meldungen werden kryptografisch gesichert und sind somit vor Veränderungen geschützt. Benutzerrelevante Meldungen können dabei von den Benutzern selbst eingesehen werden, Systemmeldungen sind »root« oder den Mitglieder der Gruppe »adm« vorbehalten.
Um eine Übersicht sämtlicher Log-Meldungen, auch von bereits rotierten Logs, zu bekommen, reicht der Aufruf von »journalctl« . Die Ausgabe und das Format sind nahezu identisch mit dem, was man von einer »/var/log/messages« -Datei gewohnt ist. Auch die von »tail« bekannten Optionen »-f« und »-n« kann man verwenden, um lediglich die letzten Zeilen des Journals zu sehen. Warnmeldungen stellt der »journald« fettgedruckt, Fehlermeldungen in Rot dar. Wer lediglich die Meldungen seit des letzten Bootvorgangs sehen möchte, der ruft journalctl einfach mit der Option »-b« auf. Nett, aber noch nicht sonderlich aufregend.
Da das Journal für jedes Log-Feld einen Index besitzt, lassen sich die Meldungen recht schön filtern. Möchte man eine Übersicht aller Meldungen eines Services innerhalb eines bestimmten Zeitfensters bekommen, so wäre dies mit folgendem Befehl möglich:
# journalctl -u vsftpd --since=yesterday --until '2013-11-05 11:00'
Keine Ahnung, welche Systemd-Units auf dem System vorhanden sind? Kein Problem: Der Befehl »systemctl list-unit-files« zeigt sie an. Interessiert man sich lediglich für Services, grenzt die Option »--type=service« die Ausgabe entsprechend ein. Insgesamt stellt Systemd aktuell zwölf verschiedene Unit-Types zur Verfügung.
Doch woher weiß man, welche Felder zu einer Log-Meldung gehören? Hier hilft es weiter, die Option »-o verbose« an den Journald zu übergeben. Alle Felder einer Meldung werden dann im Key-/Value-Format angezeigt. Mit diesen Informationen gewappnet, kann man weiter auf Entdeckungsreise gehen. Sie möchten etwa alle Meldungen eines bestimmten Nutzers sehen, die zu einem Fehler geführt haben? Kein Problem. Übergibt man das gewünschte Feld zusammen mit der Log-Priorität »err« , werden die beiden Optionen miteinander verknüpft und das passende Ergebnis angezeigt:
# journalctl -p err _UID=1000
Es wird noch besser. Ich möchte vielleicht alle relevanten Fehlermeldungen einer bestimmten SELinux-Domäne sehen? Nun, der Aufruf hierfür wäre entsprechend:
# journalct -p err _SELINUX_CONTEXT=Kontext
Was aber, wenn ich nicht mehr genau weiß, wie denn der Kontext der entsprechenden SELinux-Domäne lautet? Dann lasse ich das Feld für den Kontext einfach leer und drücke zweimal die Tab-Taste, bekomme eine Liste aller bekannten Kontextinformationen aus den Logs und kann die richtige Domäne raussuchen. Diese Auto-Completion funktioniert mit allen Feldern, die das Journal kennt.Datei:Bild7.png
Abbildung 1: Das Tool systemctl zeigt bei Status-Abfragen eines Dienstes die aktuellen Log-Meldungen für diesen Dienst an.
Suche eingebaut
Abschließend sei noch erwähnt, dass die Journal-Meldungen für einen bestimmten Service in der Status-Ausgabe des Systemd verwendet werden (Abbildung 1). Somit sind alle relevanten Log-Meldungen für einen Dienst sofort sichtbar und man muss nicht erst umständlich in der passenden Log-Datei danach suchen.
Infos# Systemd-Einführung: http://0pointer.de/blog/projects/systemd.html
systemd ist ein System- und Sitzungs-Manager (Init-System), der für die Verwaltung aller auf dem System laufenden Dienste über die gesamte Betriebszeit des Rechners, vom Startvorgang bis zum Herunterfahren, zuständig ist. Prozesse werden dabei immer (soweit möglich) parallel gestartet, um den Bootvorgang möglichst kurz zu halten.
Bei Ubuntu ist es der zweite Ansatz, das in die Jahre gekommene Init-System SysVinit abzulösen. Während Canonical bis einschließlich Ubuntu 14.04 ausschließlich und exklusiv auf die Eigenentwicklung Upstart setzte, löst es dieses ab Ubuntu 14.10 nach und nach ab. Ab Ubuntu 15.04 ist es bei Ubuntu und den offiziellen Varianten vorinstalliert. Allerdings werden im Hintergrund viele Funktionen weiterhin an Upstart weitergereicht. Wann Upstart endgültig aus Ubuntu entfernt wird, ist derzeit unbekannt.
Die Verwendung von systemd ist nicht unumstritten. Protokolldateien werden - in der Voreinstellung - im Binär-Format gespeichert und können daher nicht mit den üblichen Werkzeugen wie less oder grep angezeigt oder durchsucht werden. Darüber hinaus setzt systemd spezielle Funktionen (wie cgroups) des Linux-Kernels voraus, wodurch es nicht auf andere unixoide Systeme portiert werden kann.
Grundlagen
Units
Systemd wird über Dateien konfiguriert. Man nennt so eine Datei "Unit". Bei Ubuntu vorinstallierte Units sind im Ordner /lib/systemd/system/ gespeichert. Falls sich jedoch eine Unit mit gleichem Namen im Verzeichnis /etc/systemd/system/ befindet, so wird diese bevorzugt und jene in /lib ignoriert. Damit hat man die Möglichkeit, eine Unit an eigene Gegebenheiten anzupassen, ohne dass man befürchten muss, dass sie bei einem Update überschrieben wird. Es existieren verschiedene Typen von Units, die von systemd je nach Endung des Dateinamens unterschiedlich behandelt werden:
Typ | Beschreibung |
.device | Legt Gerätedateien an |
.mount | Ein- und Aushängen von Dateisystemen |
.path | Startet die Unit via inotify |
.service | Für Dienste |
.socket | Stellt Verbindungen zwischen Prozessen her |
.target | Definiert eine Gruppe von Units |
.timer | Für wiederkehrende Aufgaben, ähnlich cron-Jobs
|
Verwaltung
Grafische Werkzeuge
systemd bringt im Gegensatz zu Upstart ein grafisches Werkzeug mit, mit der Benutzer mit Root-Rechten [1] Einfluss auf das Verhalten nehmen können [2].* systemd-ui (universe)
mit apturl
Paketliste zum Kopieren: apt-get aptitude
sudo apt-get install systemd-ui
Um möglichst universell verwendet werden zu können, ist die Programmoberfläche allerdings komplett auf Englisch. Gestartet wird das Programm aus dem Terminal mit diesem Befehl:
systemadm
Protokolle
Mit der GNOME-Anwendung Logs können die Protokolldateien von systemd grafisch angezeigt werden. Ab Ubuntu 14.10 steht folgendes Paket zur Verfügung:* gnome-logs (universe)
mit apturl
Paketliste zum Kopieren: apt-get aptitude
sudo apt-get install gnome-logs
Kommandozeile
Das Werkzeug, um systemd auf der Kommandozeile bzw. in einem Terminal [3] zu verwalten, hört auf den Namen systemctl. Um einzelne Dienste zu betrachten, muss die Unit explizit angegeben werden. In den folgenden Beispielen wird das Wort "unit" als Platzhalter verwendet.
Die meisten Befehle greifen tief ins System ein und benötigen daher Root-Rechte. Diese werden bei Bedarf durch PolicyKit abgefragt. Mman kann sie aber auch implizit durch ein vorangestelltes sudo gewähren.
Befehl | Beschreibung |
systemctl | Listet alle units auf |
systemctl --failed | Listet alle Dienste auf, die nicht gestartet werden konnten |
systemctl status | Zeigt alle Units mit ihren Abhängigkeiten voneinander |
systemctl status unit | Zeigt den Status einer einzelnen Unit |
systemctl stop unit | Stoppt eine Unit |
systemctl start unit | Startet eine Unit |
systemctl restart unit | Stoppt eine Unit und startet sie sofort wieder |
systemctl reload unit | Erzwingt das erneute Einlesen der Konfiguration einer Unit, die Units wird nicht neu gestartet |
systemctl enable unit | Unit wird aktiviert und kann beim Booten gestartet werden |
systemctl disable unit | Unit wird deaktiviert und wird beim Booten nicht automatisch gestartet. Andere Units könnten aber Abhängigkeiten haben und diese daher trotzdem starten. |
systemctl reenable unit | Arbeitet die obigen Anweisung disable und dann enable nacheinander ab. Sollte nach jeder Veränderung einer Unit ausgeführt werden. |
systemctl mask unit | Starten einer Unit verbieten |
systemctl unmask unit | Starten einer Unit erlauben |
systemctl daemon-reload | systemd Units neu Einlesen |
Auch das Herunterfahren oder Neustarten des Rechners erfolgt mit systemctl:
Befehl | Beschreibung |
systemctl poweroff | Herunterfahren |
systemctl reboot | Neustarten
|
Logs
Logdateien sind nun über den Befehl journalctl abrufbar:
Befehl | Beschreibung |
journalctl | Listet alle Meldungen im Log auf |
journalctl -u unit | Listet nur die Meldungen einer bestimmten Unit auf |
journalctl -u unit -f | Listet nur die Meldungen einer bestimmten Unit auf, entspricht tail -f
|
Sonstiges
Befehl | Beschreibung |
hostnamectl | Rechnername anzeigen oder ändern |
timedatectl | Datum, Uhrzeit und Zeitzone anzeigen oder ändern |
localectl | Verwendeten Zeichensatz anzeigen oder ändern |
loginctl | Loginverwaltung
|
Analyse
Systemd kann zu Analysezwecken eine BootChart-ähnliche Grafik erzeugen, die den Bootvorgang detailliert darstellt. Dazu verwendet man folgenden Befehl:
systemd-analyze plot > bootchart.svg
Problembehebung
/etc/modules
Die Datei /etc/modules wird zwar noch von systemd ausgewertet, nimmt aber keine Optionen für die aufgeführten Kernelmodule mehr entgegen. Stattdessen müssen die Optionen in einer Datei unterhalb des Ordners /etc/modprobe.d/ übergeben werden.
/etc/rc.local
Das entsprechende Unit* /lib/systemd/system/rc-local.service
zum Aufruf der Datei /etc/rc.local ist vorhanden und wird auch von systemd ausgewertet.
Jedoch wird der entsprechende rc-local.service in der jetzigen Konfiguration nur von anderen Prozessen angestoßen, so dass das für eigene Zwecke nicht optimal sein kann (unkontrolliertes Timing). Dies kann durch ein "target" gelöste werden, z.B. durch "multi-user.target". Anzeigen der aktuellen Unit:
systemctl cat rc-local
Falls hier am Ende ein Install Abschnitt mit einem entsprechenden "target" fehlt, kann dieses ergänzt werden:
sudo systemctl edit --full rc-local
öffnet einen Texteditor im Terminal, am Ende ergänzt man
[Install] WantedBy=multi-user.target
Speichert und beendet den Editor. Die geänderde Unit wird nun noch aktiviert:
sudo systemctl reenable rc-local
Die angepasste rc-local Unit liegt nun unter /etc/systemd/system/rc-local.service und hat z.B. folgenden Inhalt, anzuzeigen mit systemctl cat rc-local:
vergrößern
... [Unit] Description=/etc/rc.local Compatibility ConditionFileIsExecutable=/etc/rc.local After=network.target
[Service] Type=forking ExecStart=/etc/rc.local start TimeoutSec=0 RemainAfterExit=yes
[Install] WantedBy=multi-user.target
Links
- Projektseite (http://freedesktop.org/wiki/Software/systemd)
- systemd (https://wiki.archlinux.org/index.php/systemd) - Arch Linux Wiki
- Systemd for Upstart users (https://wiki.ubuntu.com/SystemdForUpstartUsers)
Cgroups zur Ressourcenkontrolle in Linux
Vorlage:Anchor Wie viel darf's denn sein?
Mit dem neuen Cgroups-Feature lässt sich bei modernen Linux-Distributionen der Ressourcen-Verbrauch etwa von Prozessen administrativ beschränken. Besonders interessant ist die Anwendung der Technologie bei virtualisierten Systemen.
Duell der Datenbanken: In einem Shootout messen sich MySQL und PostgreSQL. Der Schwerpunkt vom ADMIN 06/2011 überprüft, wer schneller ist und gibt einen ... (mehr)
Vor einigen Jahren führte der Autor eine Linux-Schulung bei einem großen IT-Dienstleister durch. Dessen Administratoren verfügten über umfangreiche Erfahrungen mit kommerziellen Unix-Varianten, wie etwa HP-UX, und stellten die Frage, wie sie unter Linux eine Ressourcensteuerung und -kontrolle umsetzen könnten:
Wie kann ein Administrator den genutzten Arbeitsspeicher eines einzelnen Prozesses oder einer Gruppe von Prozessen beschränken?
Zum damaligen Zeitpunkt musste der Autor einräumen, dass Linux diese Funktion nicht bietet. 2006 hat jedoch Rohit Seth begonnen, diese Funktionalität zu entwickeln. Seit dem Kernel 2.6.24 kann ein Administrator diese nun auch nutzen.
Ursprünglich als "process container" bezeichnet, können die Control-Groups (kurz: cgroups) Ressourcen (Arbeitsspeicher, CPU, I/O) limitieren, priorisieren, zählen (für Abrechnungszwecke) und isolieren.
Auch wenn viele Administratoren diese Funktionalität auf einem normalen Server wahrscheinlich nicht einsetzen werden, ist sie beim Einsatz etwa von KVM-Virtualisierung sehr interessant. Mit Cgroups lassen sich die Ressourcen eines virtuellen Gastes beschränken oder gegenüber anderen Gästen priorisieren [1].
Gruppenzwang
Mit einer Cgroup kann ein Administrator mehrere Prozesse zu einer Gruppe zusammenfassen. Diese Prozesse und sämtliche Kindprozesse kann der Administrator dann mit Parametern für bestimmte Subsysteme versehen.
Ein Subsystem ist dann zum Beispiel ein Ressource-Controller, der den verfügbaren Arbeitsspeicher verwaltet. Am einfachsten illustriert dies ein Beispiel.
Um die Cgroups zu verwenden, muss der Administrator zunächst Hierarchien anlegen, in der die Gruppen verwaltet werden.
Hierzu editiert er die Datei »/etc/cgconfig.conf« , die in Listing 1 zu sehen ist. Existiert die Datei noch nicht, so muss er das entsprechende Paket noch installieren.
Diese Datei legt für jedes Subsystem eine eigene Hierarchie an, unterhalb derer die Cgroups angelegt werden können. Die Hierarchie »/cgroup/cpu« erlaubt die Verwaltung der CPU-Shares, während »/cgroup/net_cls« die Verwaltung der Netz-I/O-Leistung unterstützt.
Listing 1
/etc/cgconfig.conf
01 mount { 02 cpuset = /cgroup/cpuset; 03 cpu = /cgroup/cpu; 04 cpuacct = /cgroup/cpuacct; 05 memory = /cgroup/memory; 06 devices = /cgroup/devices; 07 freezer = /cgroup/freezer; 08 net_cls = /cgroup/net_cls; 09 ns = /cgroup/ns; 10 blkio = /cgroup/blkio; 11 }
Ein Start des Cgconfig-Daemons erzeugt dann die Verzeichnisse und mountet das Cgroups-Dateisystem. Mit dem Befehl »lssubsys« kontrolliert der Admin die korrekte Erzeugung der Hierarchien (Listing 2).
Listing 2
lssubsys
01 # lssubsys -am 02 cpuset /cgroup/cpuset 03 cpu /cgroup/cpu 04 cpuacct /cgroup/cpuacct 05 memory /cgroup/memory 06 devices /cgroup/devices 07 freezer /cgroup/freezer 08 net_cls /cgroup/net_cls 09 ns /cgroup/ns 10 blkio /cgroup/blkio
Die Control Groups legt der Administrator mit dem Befehl »cgcreate« an:
cgcreate -g blkio:/dd
Welche Parameter für das Subsystem Block-I/O zur Verfügung stehen, lässt sich mit dem Befehl in Listing 3 in Erfahrung bringen.
Listing 3
Block-I/O-Subsystem
01 # cgget -g blkio /dd 02 /dd: 03 blkio.reset_stats= 04 blkio.io_queued=Total 0 05 blkio.io_merged=Total 0 06 blkio.io_wait_time=Total 0 07 blkio.io_service_time=Total 0 08 blkio.io_serviced=Total 0 09 blkio.io_service_bytes=Total 0 10 ...
Ab Kernel 2.6.37 unterstützt der Kernel hier auch die Optionen »blkio.throttle.*« . Damit kann der Administrator die maximale I/O-Bandbreite beim Lesen und Schreiben einer Prozessgruppe einschränken.
Um dies zu testen, benötigt der Admin zunächst die Major- und Minor-Nummern des Gerätes, auf dem die Bandbreite eingeschränkt werden soll. Handelt es sich um »/dev/sda1« , kann er diese mit einem einfachen »ls« ermitteln:
# ls -l /dev/sda1 brw-rw----. 1 root disk 8, 1 10. Okt 08:32 /dev/sda1
Hier handelt es sich um die Major/Minor-Nummern 8 respektive 1. Um die Bandbreite für die Control-Group nun auf 1 Mbyte/s zu beschränken, verwendet er den Befehl »cgset« oder einfach ein »echo« :
echo "8:1 1048576" > /cgroup/blkio/dd/blkio.throttle.write_bps_device
Für den Test startet er nun dd.
dd if=/dev/zero of=/tmp/test & pid=$!
Zunächst arbeitet der Prozess »dd« in der Root-Cgroup, die nicht eingeschränkt ist. Dies testet der Administrator, indem er dem Prozess ein SIGUSR1 sendet:
# kill -USR1 $pid 578804+0 Datensätze ein 578804+0 Datensätze aus 296347648 Bytes (296 MB) kopiert, 7,00803 s,42,3 MB/s
Um den Prozess in die Cgroup »dd« zu verschieben, verwendet er den Befehl »echo« :
# echo $pid > /cgroups/blkio/dd/tasks
Sendet der Administrator nun erneut ein USR1-Signal an den »dd« -Prozess, erkennt er, dass die durchschnittliche Bandbreite stark sinkt, da der Prozess nun nur noch mit einer Bandbreite von 1 MByte/s schreiben darf.
Statt die maximale Bandbreite zu beschränken, kann der Admin auch die Bandbreiten zwischen den Gruppen priorisieren.
Hierzu dient der Parameter »blkio.weight=« . Der Default-Wert beträgt 500. Erhält eine Gruppe den Wert 1000, so kann sie doppelt so häufig auf die Block-Geräte zugreifen wie die anderen Gruppen.
Statt des Echo-Kommandos lassen sich Prozesse auch mit dem Kommando »cgclassify« einzelnen Gruppen zuweisen.
Möchte der Admin einen Prozess direkt in einer bestimmten Gruppe starten, so verwendet er den Befehl »cgexec« :
cgexec -g blkio:dd "dd if=/dev/zero of=/tmp/test"
Automatik
Die manuelle Zuweisung von Prozessen zu verschiedenen Gruppen ist aufwendig und fehlerträchtig. Besser ist es deshalb, wenn der Daemon »cgrulesengd« diese Zuweisung auch automatisch übernimmt. Hierzu benötigt dieser Dienst die Regeldatei »/etc/cgrules.conf« , die ihm mitteilt, welcher Prozess von welchem Benutzer in welcher Control-Group landen soll. Die Datei besitzt eine recht einfache Syntax:
<user>[:<process] <controllers> <destination>
Für das Beispiel mit dem »dd« -Kommando sieht die Regel folgendermaßen aus:
*:dd blkio /dd
Dies fügt die »dd« -Prozesse sämtlicher Benutzer der Controlgroup »/dd« des Blkio-Resource-Controllers hinzu.
Hierarchien
Bisher betrachtet der Artikel nur einzelne isolierte Control-Groups. Zur besseren Strukturierung lassen sich aus Gruppen aber auch
Hierarchien bilden. So kann der Administrator innerhalb einer Control-Group weitere Control-Groups anlegen, etwa mit »cgreate -g blkio:/dd/user1« .
Diese erscheinen dann als Unterverzeichnisse und erben die Eigenschaften der übergeordneten Control-Group.
Sämtliche Kind-Cgroups konkurrieren dann um die der übergeordneten Cgroup zugeteilten Ressourcen. Darf diese nur 1 MByte/s schreiben, dürfen sämtliche Kind-Cgroups zusammen dieses Maximum nicht überschreiten.
Die Ressourcen werden hierarchisch zugewiesen. Leider funktionieren diese Hierarchien für den Blkio-Controller noch nicht. Die anderen Controller wie CPU, Memory und so weiter unterstützen aber bereits Hierarchien.
Wo können die Cgroups nun sinnvoll eingesetzt werden? Sicher gibt es spezielle Anwendungen, die im Alltag davon profitieren können.
Jedoch ist es in vielen Fällen sinnvoller, dass der Linux-Kernel die Ressourcen selbstständig zuweist und hierbei keine Schranken setzt.
Setzt man jedoch eine Virtualisierungslösung wie KVM ein und virtualisiert mehrere Gäste auf einem Host, gibt es durchaus Bedarf, die Ressourcennutzung der einzelnen Gäste untereinander zu beschränken, priorisieren und zu messen. Hierfür lassen sich die Cgroups ideal einsetzen.
Virtualisiert
Allerdings muss man beim Einsatz von Cgroups die Virtualisierung über die Libvirt-Bibliotheken steuern und LXC-Container oder Qemu/KVM verwenden.
Der Libvirtd-Daemon erzeugt dann beim Start für jeden Gast eine eigene Cgroup mit dem Namen des Gastes.
Diese befindet sich in der Hierarchie »libvirtd/qemu|lxc/Gast« unter jedem Controller. Hier kann der Admin nun für jeden Gast einzeln die Ressourcen verwalten und priorisieren.
Damit ein Gast doppelt so viel CPU-Zeit wie ein zweiter Gast erhalten kann, muss man im CPU-Controller die »cpu.shares« ändern.
Das angestrebte Ziel lässt sich erreichen, indem man den Default-Wert von 1024 auf 2048 ändert.
Genauso kann der Administrator auch den Verbrauch des Arbeitsspeichers oder die Bandbreitennutzung im Netzwerk konfigurieren.
Hierzu nutzt er den Memory-Controller oder den Net_Cls-Controller in Kombination mit dem »tc« -Befehl. Allerdings unterstützen erst die aktuellsten Libvirt-Varianten den Net_Cls-Controller.
Er unterscheidet sich von den anderen Controllern, da er lediglich eine Class-ID setzt und man dann mit dem Kommando »tc« die Bandbreite kontrolliert (siehe Kasten "Bandbreitenkontrolle").
Der Blkio-Controller lässt sich noch nicht mit Libvirt nutzen, da er noch nicht die Hierarchien unterstützt, die der Libvirtd erzeugen möchte. Daran arbeiten die Kernel-Entwickler aber schon [2].
Will der Admin für die verbrauchte Zeit der einzelnen virtuellen Gäste Abrechnungen erstellen, so kann er das mit dem CPUAcct-Controller erreichen.
Dieser zählt für jeden Gast in »/cgroup/cpuacct/libvirt/qemu/Gast/cpuacct.usage« die tatsächlich verbrauchte CPU-Zeit in Nano-Sekunden.
Bandbreitenkontrolle
Wird ein Prozess vom Net_cls-Controller überwacht, kann der Admin für sämtliche Prozesse der Cgroup eine Class-ID vergeben. Diese kann dann mit dem »tc« Kommando genutzt werden. Hierzu setzt der Admin zunächst für die Cgroup die Class-ID:
echo 0x00100001 > /cgroup/net_cls/libvirt/qemu/Gast/net_cls.classid
Diese hexadezimale Zahl besteht aus zwei Teilen: 0xAAAABBBB. Hierbei definieren die Ziffern AAAA die Major-Nummer der Class-ID, während die Ziffern BBBB die Minor-Nummer angeben. Führende Nullen müssen nicht angegeben werden. Der obige Ausdruck hätte also auch 0x100001 lauten können.
Um nun die Class-ID zu nutzen, muss der Admin eine Classbased-Queueing-Discipline (QDisc) auf der ausgehenden Netzwerkkarte (etwas »eth0« ) installieren.
Die QDisc entscheidet, wann ein Paket zu versenden ist. Eine klassenbasierte QDisc erlaubt die Einsortierung der Pakete in unterschiedliche Klassen sowie die Priorisierung und Beschränkung dieser Klassen.
Eine klassische QDisc für die Beschränkung des Netzwerkverkehrs ist der Hierarchical Token Bucket Filter (HTB). Der Admin muss zunächst diesen auf der Netzwerkkarte installieren. Hierzu löscht er eine möglicherweise vorhandene QDisc und lädt dann den HTB:
tc qdisc del dev eth0 root 2>/dev/null tc qdisc add dev etho root handle 10: htbU
Nun muss der Admin die Klassen erzeugen.
tc class add dev eth0 parent 10: classid 10:1 htb rate 10mbit tc class add dev eth0 parent 10: classid 10:2 htb rate 20mbit ceil 100mbit
Diese zwei Zeilen erzeugen zwei verschiedene Klassen. Die erste Klasse verfügt über eine maximale Bandbreite von 10 Megabit/s. Die zwei Klasse verfügt über 20 Megabit/s, darf jedoch bis zu einer maximalen Bandbreite von 100 Mbit/s beanspruchen, wenn keine andere Klasse Ansprüche erhebt. Die Option »default 2« bei der Erzeugung des HTB weist unklassifizierten Verkehr der zweiten Klasse zu.
Um die Class-ID der Cgroup Net_Cls nun auszuwerten, muss der Admin noch einen Filter definieren:
tc filter add dev eth0 parent 10: \
protocol ip prio 10 \ handle 1: cgroup
Nun wird die Net_Cls-Class-ID automatisch von dem Kernel für die Einsortierung der Pakete in den HTB-Klassen genutzt. Der Libvirt-Gast erhält nun eine maximale Sendeleistung von 10 Mbit/s.
Jeder Thread eines Prozesses kann in einer eigenen Cgroup kontrolliert werden.
Daran muss der Administrator denken, wenn er, wie zu Beginn gezeigt, die Prozesse nach ihrem Start mit dem echo-Kommando einer Cgroup zuweisen möchte.
Auch sämtliche gestarteten Threads (»/proc/pid/task/« ) muss er entsprechenden Cgroups zuweisen.
Einfacher ist da das Kommando »cgexec« . Dieser Befehl startet den Prozess bereits in der Cgroup. Alle Kindprozesse und -threads erben dann diese Gruppe.
Fazit
Leider unterstützen nur die aktuellen Linux-Distributionen Cgroups.
Einzelne Funktionen stehen sogar nur in den aktuellsten Linux-Kerneln zur Verfügung.
Der Administrator muss daher im Einzelfall testen, welche Eigenschaften er nutzen kann.
Dann bieten die Cgroups aber, insbesondere auch beim Einsatz von Virtualisierung, umfangreiche Funktionen für die Ressourcen-Steuerung der Prozesse und Gäste.
Quellen und Literatur
Quellen
- Ralf Spenneberg (ADMIN 06/2011)http://www.admin-magazin.de/Das-Heft/2011/06/Cgroups-zur-Ressourcenkontrolle-in-Linux
Infos
- Cgroups: http://www.kernel.org/doc/Documentation/cgroups/
- Blkio-Hierarchien: http://lwn.net/Articles/413015/
Kommandos zu systemd
Welche Dienste laufen
# systemctl
Alle Meldungen vom letzten Bootvorgang anzeigen
# journalctl -b -1
Welche Dienste haben einen Fehler gemeldet
# systemctl --failed
Aktualisierende Anzeige
Ähnlich einen tail -f aktualisiert sich die Anzeige am Bildschirm laufend.
# journalctl -f
Ausgabe filtern
Alle Meldungen von gestern und heute des cron Service anzeigen
# journalctl -u cron.service --since=yesterday
Alle Meldungen des cron Service zwischen 7:00 und 8:00 Uhr
# journalctl -u cron.service --since='2014-05-12 07:00' --until='2014-05-12 08:00'
Alle wichtigen Meldungen (Priority 2 entspricht emerg, alert und crit) von heute anzeigen. Dies entpricht den Klassen des syslog-Daemon. emerg (0), alert (1), crit (2), err (3), warning (4), notice (5), info (6), debug (7).
# journalctl -p 2 --since=today
Logmeldungen eines nicht laufenden Systems ansehen
z.B. die Logmeldungen eines Backup (/var) ansehen. Dazu müssen die Daten in geeigneter Weise für das system.journal zur Verfügung stehen, im Beispiel via Mount-Kommando einer gesichertern /var-Partition.
# mount ./LVvar-20140514_1155.dd /media/loop
# cd /media/loop/log/journal/9dd891f2123ca26f8f3558d752e6cf59
# ll insgesamt 10752 -rw-r-----+ 1 root utempter 9875456 Mai 14 11:59 system.journal -rw-r-----+ 1 root utempter 1114112 Mai 11 21:54 user-1000.journal
# journalctl -D /media/loop/log/journal/9dd891f2123ca26f8f3558d752e6cf59
Welche Programme vom Type 'service' laufen
Typen sind zB. mount, service, mount, device, socket, target
# systemctl --type=service
Service stoppen, starten, restarten oder den Status ermitteln
# systemctl sshd.service [stop|start|restart|reload|status] # systemctl network.service [stop|start|restart|reload|status]
Service dauerhaft aktivieren
# systemctl enable nfs-server.service
Service dauerhaft deaktivieren
# systemctl disable nfs-server.service
Ist ein Service aktiviert schon ab dem Systemstart
# systemctl is-enabled nfs-server.service; echo $?
Wechsel in den Runlevel 3
# systemctl isolate multi-user.target # systemctl isolate runlevel3.target
Wechsel in den Runlevel 5
# systemctl isolate graphical.target # systemctl isolate runlevel5.target
Welche Runlevel gibt es
# systemctl list-units --type=target UNIT LOAD ACTIVE SUB DESCRIPTION basic.target loaded active active Basic System cryptsetup.target loaded active active Encrypted Volumes getty.target loaded active active Login Prompts graphical.target loaded active active Graphical Interface local-fs-pre.target loaded active active Local File Systems (Pre) local-fs.target loaded active active Local File Systems mail-transport-agent.target loaded active active Mail Transport Agent multi-user.target loaded active active Multi-User System network-online.target loaded active active Network is Online network.target loaded active active Network paths.target loaded active active Paths remote-fs-pre.target loaded active active Remote File Systems (Pre) remote-fs.target loaded active active Remote File Systems rpcbind.target loaded active active RPC Port Mapper slices.target loaded active active Slices sockets.target loaded active active Sockets swap.target loaded active active Swap sysinit.target loaded active active System Initialization timers.target loaded active active Timers
LOAD = Reflects whether the unit definition was properly loaded. ACTIVE = The high-level unit activation state, i.e. generalization of SUB. SUB = The low-level unit activation state, values depend on unit type.
19 loaded units listed. Pass --all to see loaded but inactive units, too. To show all installed unit files use 'systemctl list-unit-files'.
Alle Units anzeigen vom Type Service die inaktiv sind
# systemctl list-units --all --type=service --state=inactive --no-pager
UNIT LOAD ACTIVE SUB DESCRIPTION acpi-fakekey.service loaded inactive dead ACPI fakekey daemon alsa-restore.service loaded inactive dead Restore Sound Card State alsa-state.service loaded inactive dead Manage Sound Card State (restore and store) alsa-store.service loaded inactive dead Store Sound Card State
[...]
systemd-sysusers.service not-found inactive dead systemd-sysusers.service systemd-tmpfiles-clean.service loaded inactive dead Cleanup of Temporary Directories systemd-udev-hwdb-update.service not-found inactive dead systemd-udev-hwdb-update.service systemd-update-utmp-runlevel.service loaded inactive dead Update UTMP about System Runlevel Changes systemd-vconsole-setup.service not-found inactive dead systemd-vconsole-setup.service
LOAD = Reflects whether the unit definition was properly loaded. ACTIVE = The high-level unit activation state, i.e. generalization of SUB. SUB = The low-level unit activation state, values depend on unit type.
51 loaded units listed. To show all installed unit files use 'systemctl list-unit-files'.
Eine Unit-Datei anzeigen
# systemctl cat cron.service --no-pager # /lib/systemd/system/cron.service [Unit] Description=Regular background program processing daemon Documentation=man:cron(8)
[Service] EnvironmentFile=-/etc/default/cron ExecStart=/usr/sbin/cron -f $EXTRA_OPTS IgnoreSIGPIPE=false KillMode=process
[Install] WantedBy=multi-user.target
Die Eigenschaften (Properties) einer Unit anzeigen
Alle Eigenschaften auflisten.
# systemctl show cron.service --no-pager Type=simple Restart=no NotifyAccess=none RestartUSec=100ms TimeoutStartUSec=1min 30s TimeoutStopUSec=1min 30s WatchdogUSec=0 [...]
Spezielle Eigenschaften (Property) einer Unit anzeigen
In welchen Runlevel (Target) läuft der Cron-Service.
# systemctl show cron.service --property=WantedBy --no-pager WantedBy=multi-user.target
System anhalten
# systemctl halt
Suspendmode
# systemctl suspend
Ausschalten
# systemctl poweroff
Reboot
# systemctl reboot
Journalgröße limitieren
Um die Logmeldungen nicht ins unermessliche wachsen zu lassen kann die Größe des Verzeichnisses /var/log/journal beschränkt werden. Dazu muss man in der Konfigurationsdatei /etc/systemd/journald.conf den Wert SystemMaxUse zB. auf 512 MByte beschränken.
SystemMaxUse=512M
Ab dem nächsten Reboot ist diese Beschränkung aktiv.
Detailliertere Logmeldung
Um mehr Informationen vom systemd zu bekommen muss man den Debuglevel einschalten mit der Variable SYSTEMD_LOG_LEVEL. Dazu stoppt man den betreffenden Dienst (hier systemd-networkd) und editiert die entsprechende Servicedatei unter /lib/systemd und setzt die nachfolgende Zeile in dieser Datei.
Dienst stoppen:
# systemctl stop systemd-networkd
Zeile in /lib/systemd/system/systemd-networkd.service ergänzen unter Abschnitt '[Service].
SYSTEMD_LOG_LEVEL=debug /lib/systemd/systemd-networkd
Danach den Dienst wieder starten und die Meldungen in einer zweiten Konsole verfolgen.
# systemctl start systemd-networkd # journal -f -u systemd-networkd
Verzeichnisse des systemd
/lib/systemd/system
/etc/systemd/system/
Bootvorgang chronologisch auflisten
Dies listet die Startzeiten der jeweiligen Dienste während des Bootvorgangs auf. Hiermit kann man Services aufspüren die ungewöhnliche lange zum Starten brauchen.
# systemd-analyze blame
2.738s networking.service 2.439s lvm2-activation-early.service 1.078s uml-utilities.service 847ms systemd-fsck@dev-disk-by\x2dlabel-VIDEO.service 620ms systemd-fsck@dev-disk-by\x2dlabel-MUSIC.service 559ms systemd-udev-settle.service 519ms systemd-fsck@dev-disk-by\x2dlabel-VM\x2dNORMAL.service 514ms systemd-fsck@dev-disk-by\x2dlabel-USERDATA.service 483ms lvm2-activation.service 420ms systemd-fsck@dev-disk-by\x2dlabel-MISC.service 387ms mnt-import-dataexchange.mount 319ms vboxdrv.service 310ms mediatomb.service 308ms systemd-fsck@dev-disk-by\x2dlabel-PHOTO.service 305ms postfix.service 295ms mnt-import-archive.mount 172ms mnt-vm-normal.mount 150ms gpm.service 148ms binfmt-support.service 122ms systemd-logind.service 122ms loadcpufreq.service 106ms lm-sensors.service 102ms alsa-restore.service 102ms console-kit-log-system-start.service 101ms pppd-dns.service 97ms rsyslog.service 96ms rc-local.service 96ms systemd-user-sessions.service 96ms motion.service 95ms mnt-share-music.mount 95ms saned.service 95ms nfs-kernel-server.service 94ms ifplugd.service 93ms kexec.service 93ms ntp.service 93ms sysstat.service 90ms irqbalance.service 88ms acpi-support.service 86ms nfs-common.service 83ms keyboard-setup.service 72ms console-setup.service 71ms mnt-share-photo.mount 69ms mnt-import-vm.mount 64ms systemd-fsck-root.service 57ms mnt-share-userdata.mount 54ms systemd-update-utmp.service 53ms systemd-modules-load.service 51ms console-kit-daemon.service 47ms systemd-tmpfiles-setup-dev.service 46ms lvm2-monitor.service 40ms dirmngr.service 39ms udisks2.service 39ms mnt-import-rsnapshot.mount 38ms mnt-share-misc.mount 37ms rpcbind.service 35ms kbd.service 32ms systemd-tmpfiles-clean.service 28ms systemd-fsck@dev-disk-by\x2dlabel-HOME.service 27ms systemd-update-utmp-runlevel.service 26ms sys-kernel-debug.mount 25ms systemd-fsck@dev-disk-by\x2dlabel-VM\x2dFAST.service 25ms dev-mqueue.mount 24ms systemd-fsck@dev-disk-by\x2dlabel-VAR.service 24ms dev-hugepages.mount 24ms kdm.service 23ms polkitd.service 22ms systemd-udev-trigger.service 22ms systemd-tmpfiles-setup.service 18ms mnt-share-videostream.mount 18ms user@1000.service 18ms lvm2-pvscan@8:17.service 16ms lvm2-pvscan@8:1.service 15ms hdparm.service 13ms upower.service 10ms systemd-backlight@backlight:acpi_video0.service 9ms home.mount 9ms keymap.service 8ms dns-clean.service 8ms dev-disk-by\x2duuid-5d5979de\x2d85ac\x2d440a\x2db647\x2dcac2026b301e.swap 8ms hddtemp.service 7ms systemd-random-seed.service 7ms var.mount 7ms systemd-journal-flush.service 7ms mnt-vm-fast.mount 6ms kmod-static-nodes.service 5ms resolvconf.service 4ms systemd-sysctl.service 4ms systemd-remount-fs.service 3ms proc-sys-fs-binfmt_misc.mount 3ms cpufrequtils.service 3ms systemd-udevd.service 2ms vboxballoonctrl-service.service 2ms udev-finish.service 2ms vboxweb-service.service 2ms kexec-load.service 2ms vboxautostart-service.service 1ms sys-fs-fuse-connections.mount 1ms qemu-system-x86.service
Graphische Auswertung des Bootvorgangs
Erzeugt eine SVG-Graphik die z.B. mit gwenview betrachtet werden kann.
# systemd-analyze plot > bootplot.svg
Literatur
- Thorsten Leemhuis: Sammelstelle – Log-Informationen beim Journal von Systemd abrufen. c’t 13/2014, Seite 168
Quellen
- Lennart Poettering, Kay Sievers, Thorsten Leemhuis: Das Init-System Systemd Teil 1, Teil 2 bei heise.de
Weitere Informationen
- man systemd
- man systemctl
- man journalctl
- How To Use Systemctl to Manage Systemd Services and Units
- Useful SystemD commands
- Debian Wiki:systemd
- Ubuntu-Wiki:Systemd
- Fedora-Wiki:Systemd
- Arch-Wiki:Systemd
- Slow boot? Blame systemd!
- ADMIN-Magazin: Syslog oder kein Syslog, das ist hier die Frage
- Artikelreihe aus Archiv auf 0pointer.net "systemd for Administrators" oder alle Artikel über Startpage-Suche
Weblinks
- Offizielle Webpräsenz (http://freedesktop.org/wiki/Software/systemd) (englisch)
- Ursprüngliche Ankündigung (http://0pointer.de/blog/projects/systemd.html) (englisch)
- Projektseite beim Fedora-Projekt (http://fedoraproject.org/wiki/Features/systemd) (englisch)
- The road forward for systemd (http://lwn.net/Articles/389149/) (englisch)
- Video-Interview mit Lennart Poettering von 2011
Kritik
- Systemd: Harbinger of the Linux apocalypse (englisch)
- Systemd: The Biggest Fallacies (englisch)
- Linus Torvalds and others on Linux's systemd. Artikel von Steven Vaughan-Nichols auf ZDNet vom 19. September 2014 (englisch).
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.
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.
Turbobooster
In fast allen großen Linux-Distributionen kümmert sich mittlerweile Systemd um den Systemstart.
Der SysV-Init-Ersatz geht nicht nur besonders flott zu Werke, er schmeißt auch die alten kryptischen Startskripte über Bord. Linux-Administratoren müssen deshalb früher oder später umlernen.
Den Bootvorgang der meisten Linux-Distributionen steuerte lange Zeit das bewährte, aber etwas unflexible SysV-Init.
Wie sein Name andeutet, orientiert es sich am Bootsystem des kommerziellen Unix System V aus den 1980er Jahren.
Zunächst startet es ein paar Shell-Skripte, die dann wiederum die benötigten Dienste wecken, das Netzwerk einrichten, Dateisysteme einhängen und weitere vorbereitende Maßnahmen ausführen.
Dieses Vorgehen ist zwar einfach, aber auch recht langsam: Zum einen muss die Shell jedes Skript interpretieren, zum anderen müssen die Skripte in einer bestimmten Reihenfolge ablaufen.
So kann beispielsweise der Webserver erst starten, wenn das Netzwerk steht.
Beschleuniger Systemd
Einen ordentlichen Geschwindigkeitsschub soll das maßgeblich von Lennart Poettering und Kay Sievers entwickelte Systemd bringen. Obwohl erst 2010 veröffentlicht, hat es bereits das alte SysV-Init in nahezu allen großen Distributionen abgelöst.
OpenSUSE bietet Systemd seit Version 12.1 an, in Fedora steht es ab Version 15 zur Verfügung. Zuletzt stellte Red Hat sein neues RHEL 7 auf Systemd um, die nächste größere Debian-Version dürfte ebenfalls standardmäßig Systemd verwenden. Selbst Ubuntu wird sich bald von seiner Eigenentwicklung Upstart verabschieden.
Systemd nutzt einige pfiffige Konzepte, um den Systemstart massiv zu beschleunigen. Pate standen dabei vor allem "launchd" aus Mac OS X und die von Sun Solaris verwendete Service Management Facility (SMF).
Parallele Starts
Systemd startet keine Skripte mehr, sondern aktiviert stattdessen selbst die entsprechenden Dienste und Anwendungen.
Damit muss Systemd nicht immer wieder den Shell-Interpreter anwerfen, was Zeit und Ressourcen spart. Um abwärtskompatibel zu bleiben, verdaut Systemd aber auch weiterhin die alten SysV-Init-Skripte.
Des Weiteren startet Systemd sämtliche Dienste parallel. Dummerweise reagieren einige Dienste auf dieses Verfahren etwas allergisch.
So lässt sich ein Webserver erst dann starten, wenn das Netzwerk eingerichtet und vorhanden ist. Systemd richtet deshalb die zur Kommunikation benötigten Sockets kurzerhand selbst ein und gaukelt dem Webserver so ein funktionierendes Netzwerk vor.
Alle über die Sockets verschickten Nachrichten fängt Systemd ab und puffert sie so lange, bis das eigentliche Netzwerk steht beziehungsweise ein benötigter Dienst endlich läuft.
Sobald dies der Fall ist, arbeiten die Dienste die in der Warteschlange ausstehenden Anfragen ab. Damit blockiert der Start eines Dienstes nicht den kompletten Bootprozess.
Im schlimmsten Fall müssen die Prozesse einen kurzen Moment auf eine Antwort warten.
Da Systemd die von ihm eingerichteten Sockets kontrolliert, kann es auch feststellen, ob der darüber kommunizierende Dienst abgestürzt ist, und diesen dann automatisch neu starten.
Im Idealfall bleiben dabei sogar die Verbindungen mit den Clients bestehen. Systemd kümmert sich nicht nur um die Kommunikation über Sockets, sondern unter anderem auch um das Einbinden von Dateisystemen und D-Bus-Verbindungen.
Mittlerweile ist sogar das Werkzeug Udev, das sich um das Hotplugging von Geräten kümmert, in Systemd aufgegangen.
Auf Wunsch startet Systemd die einzelnen Dienste erst dann, wenn sie tatsächlich benötigt werden oder ein vom Administrator vorgegebenes Systemereignis eintritt.
Dieses Vorgehen beschleunigt nicht nur den Startvorgang, es spart gleichzeitig auch den alten "inetd"-Dienst ein.
Abschließend sperrt Systemd jeden Prozess samt der von ihm gestarteten Kind-Prozesse in eine eigene Control Group. Diese kurz als Cgroups bezeichnete Funktion des Linux-Kernels erlaubt es, den Diensten gezielt den Zugriff auf Ressourcen zu entziehen.
Systemd nutzt diese kleinen Gefängnisse vor allem, um die Prozesse kontrolliert zu stoppen: Bei einem Absturz kann Systemd nicht nur den Dienst, sondern auch alle seine Kind-Prozesse bequem aus dem Speicher entfernen.
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 da. 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.
Fazit
Systemd beschleunigt mit seinen Tricks den Bootprozess massiv.
Die Unit-Dateien erfordern zwar von Administratoren eine Umstellung, sind aber einfacher und klarer aufgebaut, als die alten SysV-Init-Skripte.
Dennoch ist Systemd nicht ganz unumstritten. So übernimmt es viele Aufgaben, die vorher spezialisierte Skripte oder Tools ausführten – etwa die Netzwerkeinrichtung, das (automatische) Einbinden von Dateisystemen oder das Logging. Im Gegenzug vereinheitlicht sich der Startprozess, die vielen distributionseigenen Skripte fallen weg.
Systemd nutzt Linux-spezifische Funktionen wie etwa die zur Ressourcenkontrolle gedachten Cgroups.
Damit lässt es sich auf andere Unix-Systeme wie BSD nur schwer oder gar nicht übertragen. Unter Linux hat es Systemd jedoch bereits zum neuen Standard-Startsystem gebracht, Administratoren kommen auch zukünftig nicht mehr an Systemd vorbei.
Weiterführende Informationen liefern vor allem die vielen Manpages, die Lennart Poettering auf seiner Homepage zum Durchstöbern anbietet.
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.
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.
Umgang mit Altlasten
Viele Entwickler legen ihren Diensten und Systemprogrammen nur ein SysV-Init Start-Skript bei. Das betrifft vor allem kommerzielle Software. Systemd kann diese Skripte weiterhin auswerten und aufrufen.
Intern erstellt Systemd für jedes der Skripte eine entsprechende Service-Unit. In der Ausgabe von "systemctl" tragen solche Units das Kürzel "LSB" oder "SYSV" vor ihrer Beschreibung. Systemd ignoriert allerdings das SysV-Init-Skript, wenn eine Unit-Datei mit dem gleichen Namen existiert.
Systemd versteht zudem weiterhin die alten Runlevel. Wer etwa unter CentOS 7 am Bootprompt noch den Parameter "single" anhängt, landet in einem minimalen Rettungssystem. Systemd wertet die Angabe aus und startet dann automatisch das Target "rescue.target".
Analog interpretiert Systemd auch die übrigen Runlevel: Der Aufruf von "telinit 3" aktiviert das Target "multi-user.target" und somit ein System ohne grafische Benutzeroberfläche.
Zusätzlich definiert Systemd noch die Targets "runlevel0.target" bis "runlevel6.target", die den jeweiligen alten Runlevels entsprechen.
In zukünftigen Systemd-Versionen könnten diese Krücken jedoch verschwinden, Administratoren sollten sie folglich nur im Notfall nutzen.
systemd and SysV scripte
Which share the same basename, e.g. /usr/lib/systemd/system/foobar.service vs. /etc/init.d/foobar -- which one wins?
If both files are available the native unit file always takes precedence and the SysV init script is ignored, regardless whether either is enabled or disabled.
Note that a SysV service that is enabled but overridden by a native service does not have the effect that the native service would be enabled, too. Enabling of native and SysV services is completely independent.
Or in other words: you cannot enable a native service by enabling a SysV service by the same name, and if a SysV service is enabled but the respective native service is not, this will not have the effect that the SysV script is executed.