Konfigurieren Sie den fehlerhaften systemd-Dienst so, dass er über SIGKILL beendet wird

20

Hintergrund

Ich wurde gebeten, ein systemdSkript für einen neuen Dienst zu erstellen foo_daemon, der manchmal in einen "schlechten Zustand" gerät und nicht über "stirbt" SIGTERM(wahrscheinlich aufgrund eines benutzerdefinierten Signal-Handlers). Dies ist für Entwickler problematisch, da sie angewiesen werden, den Dienst über Folgendes zu starten / stoppen / neu zu starten:

  • systemctl start foo_daemon.service
  • systemctl stop foo_daemon.service
  • systemctl restart foo_daemon.service

Problem

Manchmal müssen foo_daemonwir es aufgrund eines schlechten Zustands zwangsweise töten , indem wir:

  • systemctl kill -s KILL foo_daemon.service

Frage

Wie kann ich mein systemdSkript foo_daemonso einrichten, dass bei jedem Versuch eines Benutzers, den Dienst zu stoppen / neu zu starten, Folgendes ausgeführt systemdwird:

  • Versuchen Sie ein ordnungsgemäßes Herunterfahren von foo_daemonvia SIGTERM.
  • Warten Sie bis zu 2 Sekunden, bis das Herunterfahren / Beenden foo_daemonabgeschlossen ist.
  • Versuchen Sie ein erzwungenes Herunterfahren von foo_daemonvia, SIGKILLwenn der Prozess noch aktiv ist (sodass wir nicht das Risiko haben, dass die PID recycelt wird und systemdProbleme SIGKILLmit der falschen PID auftreten). Das Gerät, auf dem wir Spawns / Forks testen, führt zu zahlreichen schnellen Prozessen. Daher besteht eine seltene, aber sehr reale Besorgnis darüber, dass das PID-Recycling ein Problem verursacht.
  • Wenn ich in der Praxis nur paranoid bin, was das PID-Recycling SIGKILLangeht , kann ich das Skript nur gegen die PID des Prozesses ausgeben , ohne mir Gedanken über das Töten einer recycelten PID zu machen.

Wolke
quelle
2
Selbst wenn Sie Prozesse schnell genug erzeugen, um in zwei Sekunden mehr als 4 Millionen PIDs zu rollen, sitzt systemd nicht in einer Schleife und überprüft, ob diese PID noch lebt. Lebt diese PID noch? weil es nicht muss ; es ist bereits darüber informiert, ob seine unmittelbaren untergeordneten Prozesse noch aktiv sind oder nicht (mittels gewöhnlicher SIGCHLD und waitpid ()). Wenn also festgestellt wird, dass der Prozess nach SIGTERM beendet wurde, wird der Service zu diesem Zeitpunkt einfach als "inaktiv" markiert - es wird überhaupt nicht darum gehen, den SIGKILL zu überprüfen, zu warten und zu senden.
Grawity

Antworten:

26

systemd unterstützt dies bereits ab Werk und ist standardmäßig aktiviert .

Das einzige, was Sie anpassen möchten, ist das Timeout, mit dem Sie arbeiten können TimeoutStopSec=. Beispielsweise:

[Service]
TimeoutStopSec=2

Jetzt sendet systemd ein SIGTERM, wartet zwei Sekunden, bis der Dienst beendet ist, und wenn dies nicht der Fall ist, wird ein SIGKILL gesendet.

Wenn Ihr Dienst nicht systemabhängig ist, müssen Sie möglicherweise den Pfad zu seiner PID-Datei angeben PIDFile=.

Schließlich haben Sie erwähnt, dass Ihr Daemon viele Prozesse erzeugt. In diesem Fall möchten Sie möglicherweise festlegen, dass KillMode=control-groupsystemd Signale an alle Prozesse in der cgroup sendet.

Michael Hampton
quelle
Vielen Dank. Eine letzte Frage: Nehmen wir an, der Dienst ist nicht systemabhängig. Was könnte ich zum systemd-Skript für diesen Dienst hinzufügen, damit systemd die PID-Datei erstellt / verwaltet? Darüber hinaus kann der Dienst mehrere Instanzen über Vorlageneinheiten umfassen. Wir starten ihn daher normalerweise über "systemctl start [email protected]". Würde sich dies auf die PID-Dateilogik im Skript auswirken?
Cloud
4
@DevNull systemd erstellt oder verwaltet keine PID-Dateien. Es gibt keinen Grund dafür. Wenn Ihr Dienst keine eigene PID-Datei erstellt, konfigurieren Sie ihn nach Möglichkeit so, dass er im Vordergrund ausgeführt wird (anstatt zu dämonisieren) und Type=simplein der Einheit systemd festgelegt wird.
Michael Hampton
1
Wenn der Dienst abhängige Personen hat, Type=forkinghat dies den Vorteil, dass (wenn der Dienst ordnungsgemäß geschrieben wurde) systemd informiert wird, wenn er vollständig "bereit" ist, was Type = simple nicht kann. Daemonisierung ist auch ohne PID-Datei kein Problem - systemd spürt den Hauptprozess trotzdem auf.
Grawity
1
@grawity Richtig ... obwohl ich die Erfahrung gemacht habe, dass Dienste dämonisiert werden, bevor sie tatsächlich für die Bereitstellung bereit sind. Ein systemd-fähiger Dienst Type=notifyist am besten für systemd geeignet, und viele gängige Dienste tun dies bereits. Aber wahrscheinlich nicht dieses Vermächtnis. Im Falle des OP hat er einen Dienst, der viele Prozesse hervorbringt. Die systemd-Dokumente warnen vor diesem Fall .
Michael Hampton
1

Da niemand die Notwendigkeit erwähnt hat, Type=oneshotist hier ein vollständiges Beispiel, das aufgrund eines Timeout-Fehlers beendet wird.

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
Evidlo
quelle