Tux
Nachdem ich feststellen musst, dass immer noch der ein oder andere mit Systemd und den Unitfiles auf Kriegsfuß steht und mit tieferem Wissen manches Problem zu vermeiden wäre, will ich mit ein paar kurzen Erklärungen Abhilfe schaffen.

Systemd hat als Ersatz für init bereits 2010 angefangen in die verschiedenen Distributionen Einzug zu halten und ist mittlerweile Standard. Somit haben auch die alten init-Skripte ausgedient und wurde durch Unitfiles ersetzt. Auf den ersten Blick lassen diese weniger Optionen zu, aber sobald man sich etwas weiter mit den Einstellmöglichkeiten auseinandersetzt, wird man wohl nichts an Funktionalität vermissen.

Für die Erläuterungen möchte ich ein Beispiel nehmen, dass vielleicht der ein oder andere schon kennt, und habe mich darum für Icinga 2 entschieden. Dieses findet sich in /usr/lib/systemd/system als icinga2.service und sieht folgendermaßen aus:

[Unit]
Description=Icinga host/service/network monitoring system
After=syslog.target network-online.target postgresql.service mariadb.service carbon-cache.service carbon-relay.service

[Service]
Type=forking
EnvironmentFile=/etc/sysconfig/icinga2
ExecStartPre=/usr/lib/icinga2/prepare-dirs /etc/sysconfig/icinga2
ExecStart=/usr/sbin/icinga2 daemon -d -e ${ICINGA2_ERROR_LOG}
PIDFile=/run/icinga2/icinga2.pid
ExecReload=/usr/lib/icinga2/safe-reload /etc/sysconfig/icinga2
TimeoutStartSec=30m

[Install]
WantedBy=multi-user.target

Als erstes möchte ich auf den Pfad selbst eingehen. Diese muss per Konvention heißen wie der Service, der über sie gesteuert wird, und auf .service enden, damit sie von anderen Units unterscheidbar ist. Andere Units wären beispielsweise Sockets für die socketbasierende Aktivierung oder Targets als Gruppierung von Services und Ersatz für die Runlevel. Der Pfad /usr/lib/systemd/system ist hierbei der Ablageort für Package-Maintainer und kann mit Dateien in /run/systemd/system oder /etc/systemd/system überschrieben werden, wobei letzteres für den Administrator gedacht ist.

Die Datei selbst ist dann im Ini-Format, heißt es gibt verschiedene Sektion wie [Unit] und Key-Value-Paare, die in der entsprechenden Sektion sein müssen. In der Sektion [Unit] finden sich somit allgemeine Einstellungen die bei jedem Unit-Typen vorkommen können, in diesem Fall die Beschreibung und mit After eine Liste von Units, die wenn vorhanden vor Icinga 2 gestartet sein sollen. Die Manpage systemd.unit gibt hierüber detailliert Auskunft.

In der für den Unit-Typ spezifischen Sektion in unserem Fall [Service] werden dann weitere Einstellungen vorgenommen. Hier wird Systemd gesagt wie das Startverhalten des Dienstes ist denn standardmäßig möchte Systemd Dienste im Vordergrund starten im Gegensatz zum Standardverhalten von init bei dem sich der Dienst in den Hintergrund forkt. Über EnvironmentFile, zusätzliche Skripte in ExecStartPre oder ExecStartPost und den eigentlich Aufruf des zu startenden Dienst mittels ExecStart wird das frühere init-Skript abgelöst. In Fall von Icinga2 wird im Pre-Skript sichergestellt, dass benötigte Verzeichnisse existieren und entsprechend berechtigt sind. Zusätzlich wird der Reload-Mechanismus durch ein Skript ersetzt, damit die Konfiguration validiert wird bevor gegebenenfalls der Dienst neugestartet wird. TimeoutStartSec ist prinzipiell selbsterklärend denk ich, nimmt im Gegensatz zu den Sekunden im Namen aber auch andere Einheiten an wie hier 30m für 30 Minuten. Hierbei bitte aufpassen, dass nur der Start-Timeout und nicht der allgemeine Timeout hochgesetzt wird, da letzterer auch für den Shutdown des Systems gilt. Mehr Details liefert die Manpage systemd.service.

Die letzte Sektion gibt an in welches Target der Dienst “installiert” werden soll, wenn systemctl enable ausgeführt wird.

Die Datei unter /usr/lib/systemd/system sollte nicht angepasst werden, da diese beim nächsten Update überschrieben wird. Kopiert man es aber nach /etc/systemd/system muss man die komplette Pflege übernehmen, da es das aus dem Paket gelieferte komplett ersetzt. Hierfür gibt es den Mechanismus der Drop-Ins. Diese müssen in ein Verzeichnis mit dem Namen der Unit abgelegt werden, in unserem Fall /etc/systemd/system/icinga2.service.d und auf .conf enden. Der Name ist hierbei prinzipiell egal, sollte aber sprechend gewählt werden und da sich Eigenschaften überschreiben bietet sich eine Priorität als Präfix an. Beim Inhalt nicht die Sektionsheader vergessen! Auch hierfür ein Beispiel aus Icinga 2:

# Icinga 2 sets some default values to extend OS defaults
#
# Please refer to our troubleshooting documentations for details
# and reasons on these values.
[Service]
TasksMax=infinity

# May also cause problems, uncomment if you have any
#LimitNPROC=62883

Mit dem Kommando systemctl property kann man genau diesen Mechanismus nutzen ohne sich um die Dateistruktur kümmern zu müssen, aber leider funktioniert dies nicht für alle Optionen. Kernel-Parameter, Posix-Limits und vieles mehr lassen sich hier einstellen, welche sich in systemd.exec finden, und Einstellungen für die Kontrolle über Ressourcen, welche Systemd mittels Cgroups umsetzt, finden sich in systemd.resource-control. Die Defaults hierfür finden sich übrigens in /etc/systemd/system.conf und müssen nicht immer gleich heißen, beispielsweise DefaultTasksMax und TasksMax. Die eingebundenen Drop-Ins zeigt systemctl status sehr schön an und die aktuellen Werte für alle Einstellungen eines Services inklusive Defaults liefert systemctl show.

Und abschließend nicht vergessen Systemd die vorgenommenen Änderungen mit systemctl daemon-reload auch mitzuteilen.

Ich hoffe diese kleine Erläuterung hilft dem ein oder anderen Unitfiles besser zu verstehen und er weiß nun wo er hin langen muss wenn Stellschrauben anzupassen sind.

Dirk Götz

Autor: Dirk Götz

Dirk ist Red Hat Spezialist und arbeitet bei NETWAYS im Bereich Consulting für Icinga, Nagios, Puppet und andere Systems Management Lösungen. Früher war er bei einem Träger der gesetzlichen Rentenversicherung als Senior Administrator beschäftigt und auch für die Ausbildung der Azubis verantwortlich.