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 NutzerZusä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.
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 einem SIGTERM
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. Mit ExecStop
, ExecReload
und gegebenenfalls ExecRestart
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 wie simple
.
- ExecStart
beschreibt jetzt den Befehl zum starten, im Fall von simple
oder oneshot
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 mit where <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
und on-watchdog
).
- RemainAfterExit
ist besonders sinnvoll für oneshot
-Dienste und lässt nach Beenden des Programms den Dienst weiterlaufen (bzw. tut so, als würde er weiterlaufen), wodurch man hier auch mit ExecStop
arbeiten kann. Normalerweise kann diese Einstellung aber weggelassen werden (oder wie hier auf false).
-
Userund
Groupbestimmen den ausführenden Benutzer bzw. die Gruppe. Da Programme am besten nie als
rootlaufen sollten, ist es meistens sinnvoll, diese Optionen zu setzen.
-
WorkingDirectorymacht genau was es sagt: es setzt das Arbeitsverzeichnis, funktioniert also wie
cd /WO/AUCH/IMMER && befehl.
-
Environmentkann Umbgebungsvariablen setzen. Gibt es viele davon, lohnt es sich eventuell, sie in eine
EnvironmentFile` 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 meistens multi-user.target
, Benutzerdienste brauchen hier ein default.target
.
Viele weitere Optionen sind in der Dokumentation aufgelistet, wobei auch das Kapitel systemd.exec sehr hilfreich ist.
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.
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