Alles über .service-Dateien für systemd
Inzwischen hat in vielen Linux-Distributionen systemd das alte sysvinit abgelöst, und damit ändert sich auch die Art und Weise wie man Dienste definiert, die im Hintergrund laufen sollen.
Das ist nämlich meiner Meinung nach deutlich einfacher und flexibler geworden: es gibt nun statt den Skripten in /etc/init.d
die neuen .service
-Dateien, die in verschiedenen Orten vorkommen können:
/etc/systemd/system
: Systemdienste, sozusagen das neue/etc/init.d
/etc/systemd/user
: Nutzerdienste für alle Nutzer~/.config/systemd/user
: Nutzerdienste für einen speziellen Nutzer
Zusätzlich existieren unter Umständen noch weitere Verzeichnisse ({/usr,}/lib/systemd/{system,user}
), um die kümmern sich aber schon apt
, yum
oder andere Paketverwalter.
Was ebenfalls neu ist, sind Nutzerdienste. Mit systemctl --user start <service>
kann jeder Benutzer einen solchen Dienst ausführen - beispielsweise eine Backup-Software für die persönlichen Dateien.
Wie sieht so eine .service-Datei aus?
Es gibt ziemlich viel was geht mit .service
-Dateien, aber bleiben wir mal bei den Dingen, die man für einen normalen Dienst so braucht:
[Unit]
Description=Beispieldienst
After=syslog.target network.target
Wants=wasanderes.service
[Service]
Type=simple
ExecStart=/PFAD/ZUM/BEFEHL/befehl
Restart=on-failure
RemainAfterExit=false
User=moritz
Group=moritz
WorkingDirectory=/WO/AUCH/IMMER
EnvironmentFile=/PFAD/ZUM/BEFEHL/beispiel.env
Environment=HOME=/home/moritz
Environment=ENVIRONMENT=production
[Install]
WantedBy=multi-user.target
Also, was tun wir hier? In der [Unit]
-Sektion stehen allgemeine Informationen, die systemd dabei helfen unser Dienst in die Startreihenfolge einzuordnen - Abhängigkeiten, Beschreibung und Dokumentation, und so weiter.
- Mit
Description
geben wir unserem Dienst einen Namen, in diesem Fall "Beispieldienst". So wird das Programm später in den Logs genannt. - Systemd kann mehrere Dienste gleichzeitig starten. Mit
After
wird angegeben, dass beim Systemstart erst Logging und Netzwerk initialisiert werden sollen, bevor unser Programm gestartet wird. - Mit
Wants
können wir Abhängigkeiten hinzufügen. Wenn die hier angegebenen Dienste nicht laufen, werden sie gestartet bevor unser Programm gestartet wird.
In [Section]
geben wir nun an, wie genau das Programm gestartet werden soll.
- Der
Type
beschreibt, um was für eine Art Programm es sich handelt:simple
sind Programme, die gestartet werden, dann laufen und ihre Daten auf die Standardausgabe schreiben, und mit einemSIGTERM
wieder beendet werden können. Systemd kümmert sich hierbei um alles.forking
sind Programme, die gestartet werden und sich dann in den Hintergrund verdrücken (forken). Es sind also Dienste gemeint, die sich selbst verwalten (also starten, stoppen und neu laden) können. MitExecStop
,ExecReload
und gegebenenfallsExecRestart
können die Befehle für die jeweiligen Optionen eingestellt werden.oneshot
sind z.B. Skripte, die komplett durchlaufen müssen, bevor systemd davon abhängige Dienste starten kann, ansonsten aber wiesimple
.
ExecStart
beschreibt jetzt den Befehl zum starten, im Fall vonsimple
oderoneshot
also die eigentliche Programmdatei mit Argumenten. Wichtig ist, dass dieser Befehl mit absolutem Pfad angegeben wird. Weiß man diesen nicht, kann man ihn ganz einfach mitwhere <programmname>
herausfinden.Restart
gibt an, wann der Dienst neugestartet werden soll wenn er sich selbst beendet. In der Dokumentation gibt es dazu eine schöne Tabelle, die die möglichen Werte beschreibt (no
,always
,on-failure
,on-abnormal
,on-abort
undon-watchdog
).RemainAfterExit
ist besonders sinnvoll füroneshot
-Dienste und lässt nach Beenden des Programms den Dienst weiterlaufen (bzw. tut so, als würde er weiterlaufen), wodurch man hier auch mitExecStop
arbeiten kann. Normalerweise kann diese Einstellung aber weggelassen werden (oder wie hier auf `false).User
undGroup
bestimmen den ausführenden Benutzer bzw. die Gruppe. Da Programme am besten nie alsroot
laufen sollten, ist es meistens sinnvoll, diese Optionen zu setzen.WorkingDirectory
macht genau was es sagt: es setzt das Arbeitsverzeichnis, funktioniert also wiecd /WO/AUCH/IMMER && befehl
.Environment
kann Umbgebungsvariablen setzen. Gibt es viele davon, lohnt es sich eventuell, sie in eineEnvironmentFile
auszulagern, von wo aus sie dann geladen werden.
Zu guter letzt gibt es noch [Install]
. Hiermit können wir beeinflussen, wann der Dienst automatisch gestartet wird.
WantedBy
tut genau das: es gibt ein Ziel an, das zum Start des Programms führt. Für systemweite Dienste ist dies meistensmulti-user.target
, Benutzerdienste brauchen hier eindefault.target
.
Viele weitere Optionen sind in der Dokumentation aufgelistet, wobei auch das Kapitel systemd.exec sehr hilfreich ist.
Wie aktiviere und steuere ich einen Dienst?
Die Dateiendung (.service
) in den folgenden Befehlen ist komplett optional (außer es gibt andere Unit-Typen mit dem gleichen Namen), ein Dateipfad muss ebenfalls nicht angegeben werden, da systemd seine Verzeichnisse automatisch durchsucht. Praktisch, nicht?
Ist die .service
-Datei erstellt, kann man sie mit folgendem Befehl aktivieren, und damit zu den unter [Install]
angegebenen Bedingungen automatisch starten lassen:
$ systemctl enable beispieldienst.service
Oder für Nutzerdienste:
$ systemctl --user enable beispieldienst.service
Verändert man die Service-Datei, muss man das systemd wiefolgt mitteilen:
$ systemctl [--user] daemon-reload
Um den Dienst zu starten und zu stoppen, kann man folgende Befehle verwenden:
$ systemctl [--user] start|stop|restart|reload beispieldienst.service
Möchte man sehen, was ein Dienst gerade tut (Status und die letzten paar Zeilen aus dem Log), gibt es diesen Befehl:
$ systemctl [--user] status beispieldienst.service
Für ausführlichere Protokolle gibt es journalctl
:
$ journalctl [--user] -exfu beispieldienst.service
Wichtig dabei ist übrigens, dass der Nutzer dafür in der Gruppe systemd-journal
sein muss um Logs von Systemdiensten einzusehen.
Nutzerdienste auf Servern automatisch starten
Da Nutzerdienste mit WantedBy=default.target
normalerweise erst gestartet werden, wenn der entsprechende Nutzer sich tatsächlich anmeldet, ist das auf Servern erst einmal nicht allzu sinnvoll. Man kann Nutzerservices eines Nutzers jedoch auch mit dem System starten, und zwar mit dem folgenden Befehl (siehe Dokumentation):
$ loginctl enable-linger moritz