QVINTVS · SCRIBET

Umrüstung auf systemd

Ich habe gerade mein Laptop auf Systemd umgerüstet und möchte kurz beschreiben, wie das vonstatten ging.

Es geht erstaunlich leicht von der Hand, eine so alteingesessene Software wie System V Init, das aus den alten Unix-Zeiten von SysV stammt, durch etwas moderneres zu ersetzen. Zumindest unter Arch Linux ist systemd sehr schnell und sehr einfach installiert.

Installation

Zuallererst installiert man die notwendigen Pakete aus dem community-Repository:

# pacman -S rsyslog initscripts-systemd systemd-arch-units

rsyslogd ist so weit ich das verstanden habe die einzige Syslog-Implementation, die alle von systemd verwendeten Features bereitstellt, der unter Arch Linux standardmäßig verwendete syslog-ng macht wohl Probleme. initscripts-systemd stellt die wichtigsten Services für Arch Linux bereit und systemd-arch-units dient zur Migrationshilfe von SysVinit auf systemd. Ich zweifle inzwischen, ob es notwendig ist, das letzte zu installieren, weil ich nahezu sämtliche davon zur Verfügung gestellten Service-Files deaktiviert habe…

Funktionsweise

Womit wir auch schon beim Thema wären. SysVinit setzte noch auf das Konzepz von Runlevels, von denen je einer einen bestimmten “Systemzustand” darstellte, etwa “single”, “multi” oder “X11”. Systemd verwirft dieses Konzept völlig (auch wenn initscripts-systemd Pseudo-Targets mitbringt, die die Runlevels nachahmen) und setzt stattdessen auf eine Kombination von sogenannten Targets und Services. Ein Service in Systemd ist ein einzelnes zu startendes Programm, meist ein Daemon (obwohl das nicht zwingend ist), das bestimmte Systemaufgaben erfüllt und wird durch eine Service-Datei spezifiziert, die angibt, wie es zu starten ist, wohin geloggt wird, und zu welchem Target es gehört. Ein Target ist demnach eine Gruppe von Services, d.h. startet man in Systemd ein Target, wird eine ganze Gruppe von Services gestartet. Besonders dabei: Systemd startet nicht wie SysVinit alles sequentiell nacheinander, sondern startet soviel parallel wir irgend möglich (ermöglicht durch entsprechende Abhängigkeits-Direktiven in den Service-Dateien), was zu einem enormen Geschwindkeitsvorteil führt.
Service-Dateien enden mit der Dateiendung .service, Targets mit .target und beide können in den Verzeichnissen /lib/systemd/system und /etc/systemd/system gefunden werden, wobei letzteres für selbstgeschriebene Services und Targets gedacht ist.

Beispiel: Das von Systemd standardmäßig gebootete Target ist graphical.target. Alle für den Betrieb eines X11-Mehrbenutzersystems erforderlichen Services werden damit gestartet, z.B. der Login-Manager, etwa GDM, der dementsprechend eine eigene Service-Datei gdm.service besitzt, die der Gruppe/dem Target graphical.target zugeordnet ist.

Natürlich startet Systemd nicht alle einem Target zugeordneten Services, denn das würde schnell zu einem Chaos führen, beispielsweise gehören sowohl GDM als auch KDM oder auch SLiM zu graphical.target, können aber nicht gleichzeitig nebeneinander betrieben werden. Um dieses Problem zu lösen, kennt Systemd das Konzept von aktiven und inaktiven Services. Ein aktiver Service ist einer, der beim Start seines Targets auch tatsächlich gestartet wird, ein inaktiver ein solcher, der es eben nicht wird. Hat man beispielsweise gdm.service aktiviert, werden (über eine Konfliktregel in der Service-Datei von GDM) automatisch kdm.service und slim.service deaktiviert. Dieser Aktivierungs- und Deaktivierungsprozess geschiet ziemlich simpel über Symlinks: Jedes Target besitzt einen Ordner, der genauso heißt wie das Target plus .wants. Dieser Wants-Ordner enthält Symlinks auf all die Service-Dateien eines Targets, die gerade aktiviert sind. So wird die Service-Datei /lib/systemd/system/gdm.service bei aktiviertem GDM in /etc/systemd/system/graphical.target.wants verlinkt werden1.

Diese ganze Verwaltung manuell zu erledigen, ist zwar möglich, aber fehleranfällig (was, wenn man einen Konflikt übersieht?). Daher stellt Systemd ein Kommandozeilentool zur Verfügung, was diese Aufgabe übernimmt: systemctl. systemctl kennt vier Befehle:

start
Einen Service/ein Target sofort starten
stop
Einen Service/ein Target sofort stoppen
enable
Einen Service für sein Target aktivieren (Konflikte deaktivieren)
disable
Einen Service für sein Target deaktivieren (aber Konflikte werden nicht automatisch aktiviert!) oder alle Services eines Targets deaktivieren

Konfiguration

Mit diesem Wissen können wir nun daran gehen, Systemd zu konfigurieren. Ich werde in diesem Blogpost die komplette native Konfiguration von Systemd durchführen, von einer Übergangslösung mit teilweisem Einlesen der /etc/rc.conf halte ich nichts. Ich empfehle außerdem die Lektüre des ArchWiki-Ariktels zu Systemd , anhand dessen ich bei diesem Blogpost auch gearbeitet habe.

Zunächst deaktiviert man dazu all die Übergangspakete und den holprigen syslog-ng:

# systemctl disable arch-daemons.target arch-persistent-settings.service syslog-ng.service

Anschließend öffnet man seine /etc/rc.conf und schaut sich an, welche Programme man über den DAEMONS-Array starten lässt und notiert sich diese, denn: Die Datei /etc/rc.conf wird von Systemd nicht mehr beachtet. Ebensowenig wie /etc/inittab.
Dann geht es daran, herauszufinden, wie die Service-Dateien für die Programme heißen. Hat man etwa den CUPS-Daemon im DAEMONS-Array, so empfiehlt sich ein

$ ls /lib/systemd/system | grep cups
cups.service

und man sieht, die Service-Datei für CUPS ist cups.service. So verfährt man mit allen Programmen im DAEMONS-Array, bis man die Service-Dateien für alle Daemons zusammenhat2. Freilich gibt es auch Daemons, für die noch keine Service-Dateien geschrieben wurden, aber der größte Teil allgemein gebräuchlicher Programme ist abgedeckt. Das Schreiben von Service-Dateien wird recht gut in diesem Blogpost beschrieben, den man sich zusammen mit den Manpages zu systemd.service (5) und systemd.unit (5) durchlesen sollte.

Bei mir konnte ich schließlich folgende Servies aktivieren:

# systemctl enable rsyslog.service alsa.service NetworkManager.service \
avahi-daemon.service cups.service ntpd.service gdm.service

Danach geht es zur eigentlichen Konfiguration. Wie man dem oben verlinkten ArchWiki-Artikel entnehmen kann, müssen folgende Dateien bearbeitet werden:

/etc/hostname
Hier den Hostname eintragen, sonst nichts. Nur dieses eine Wort.
/etc/vconsole.conf
Konfiguration für die virtuellen Konsolen.
/etc/os-release
Braucht nicht bearbeitet zu werden — das erledigen die Arch-Packer schon für uns. Bei mir jedenfalls enthielt die Datei schon alles nötige.
/etc/locale.conf
Sprach- und Lokalisierungseinstellungen.
/etc/modules-load.d
Dies ist ein Verzeichnis. Hier wird für jedes zu startende/zu blacklistende Kernel-Modul eine Datei nach dem Format “MODULNAME.conf” eine Datei angelegt und einfach nur mit dem Namen des Moduls befüllt. Soll ein Modul auf die Blacklist, so schreibt man “blacklist MODULENAME” in die Datei. Siehe ArchWiki .

Bei mir haben diese Dateien folgenden Inhalt:

√ root@ikarus => ~
# cat /etc/hostname
ikarus
√ root@ikarus => ~
# cat /etc/vconsole.conf 
# Systemd Virtual Console configuration

KEYMAP="de-latin1"
FONT=""
FONT_MAP=""
√ root@ikarus => ~
# cat /etc/os-release 
NAME="Arch Linux"
ID=arch
PRETTY_NAME="Arch Linux"
ANSI_COLOR="1;36"

√ root@ikarus => ~
# cat /etc/locale.conf 
# Systemd Locals configuration file
LANG=de_DE.utf8
LC_COLLATE=C

Extra-Kernel-Module lade ich auf meinem Laptop nicht und blackliste auch nicht, aber auf meinem Desktop-Rechner arbeite ich mit KVM. Wen es interessiert:

√ root@hades => ~
# ls /etc/modules-load.d/
kvm.conf
√ root@hades => ~
# cat /etc/modules-load.d/kvm.conf 
# Kernel module to load at boot, used by systemd
kvm
kvm-amd

Zusätzlich dazu möchte ich eine kurze Warnung vor rsyslog abgeben: rsyslog loggt standardmäßig nämlich nicht (wie es noch syslog-ng tat) nach /var/log/messages.log, d.h. wer dort nach Log-Nachrichten sucht, wird zu seinem Schrecken feststellen, dass nichts mehr geloggt wird. Aber keine Panik: rsyslog loggt nach /var/log/messages (ohne die Endung .log). Wer das ändern möchte, kann das in der Datei /etc/rsyslog.conf tun und dort den Eintrag

*.info;mail.none;authpriv.none;cron.none                -/var/log/messages

nach

*.info;mail.none;authpriv.none;cron.none                -/var/log/messages.log

ändern.

Zu guter letzt muss die Kernel-Zeile für Arch Linux im Bootloader angepasst werden. Ich verwende GRUB2 mit handgeschriebener grub.cfg, und da schaut das so aus:

menuentry "Arch Linux" {
  set root=(hd0,2)
  echo "Loading Arch Linux Kernel..."
  linux /boot/vmlinuz26 root=/dev/disk/by-uuid/2973e19e-017c-4118-abd3-9e152611200e ro init=/bin/systemd quiet
  echo "Loading Initial Ramdisk..."
  initrd /boot/kernel26.img
}

Hier ist die mit linux beginnende Zeile die interessante, der Rest ist normal. Und in dieser Zeile interessieren auch nur die letzten beiden Optionen: init=/bin/systemd bewirkt, dass statt dem normalen init systemd gestartet wird. Möchte man wieder nach SysVinit zurück (warum auch immer), kann man diese Option einfach wieder entfernen und alles ist wie gehabt. quiet sorgt dafür, dass kaum Output entsteht — das ist wichtig, weil das TTY der virtuellen Konsole einfach nicht schnell genug ist, die von Systemd ausgespuckten Meldungen anzuzeigen, was dazu führt, dass der Bootvorgang u.U. länger dauert als mit SysVinit. Und überhaupt, wer will schon die Nachrichten von X parallel gestarteten Programmen sehen?

Fazit

Mit systemd bootet mein Laptop wesentlich schneller und die steinalte Technologie SysVinit wird endlich in den wohlverdienten Ruhestand geschickt, ich jedenfalls werde sobald nicht dahin zurückkehren.
Ähnliches wird sich womöglich noch mit X11 und Wayland ereignen, aber das hat noch Zeit. Wir werden sehen.

Valete.


1 Genaugenommen kann es (muss es aber nicht) zwei Wants-Ordner geben: Einen in /lib/systemd/system und einen in /etc/systemd/system. Gearbeitet wird in der Regel mit /etc/systemd/system, es ist aber prinzipiell egal, weil die Ordner von Systemd gewissermaßen “zusammengeführt” werden, d.h. beide beachtet werden.

2 Besonders fies hat sich in dieser Hinsicht der Network-Manager gebärdet, denn dessen Service-Datei heißt NetworkManager.service, und mit Großschreibung hatte ich einfach nicht gerechnet. Ich war drauf und dran, selbst eine Service-Datei für den NM zu schreiben, als ich sie doch noch gefunden habe.