Linux/Systemstart
Systemd
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.
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. Systemd 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.