Systemd und Prozesslaichen

14

Poste normalerweise nicht hier, aber ich reiße mir die Haare darüber aus. Ich besitze ein Python-Skript, das beim Start abgefragt wird und für das Starten einer Reihe anderer Prozesse verantwortlich ist. Dieses Skript wurde früher beim Start über sysvinit gestartet, aber kürzlich habe ich ein Upgrade auf Debian Jessie durchgeführt und es so angepasst, dass es über systemd gestartet werden kann.

Leider stoße ich auf ein Problem, das ich nicht lösen kann. Wenn Sie das Skript direkt in einer Benutzershell starten, werden die untergeordneten Prozesse ordnungsgemäß gestartet, und wenn das Skript beendet wird, werden die untergeordneten Prozesse verwaist und weiterhin ausgeführt.

Wenn der übergeordnete Prozess über systemd gestartet wird, werden auch alle untergeordneten Prozesse beendet. (Nun, der Bildschirm, den sie starten, wird als tot angezeigt. ???)

Idealerweise muss ich in der Lage sein, das übergeordnete Skript neu zu starten, ohne alle untergeordneten Prozesse zu beenden. Fehlt mir etwas?

Vielen Dank!

[Unit]
Description=Server commander
After=network.target

[Service]
User=serveruser
Type=forking
PIDFile=/var/Server/Server.pid

ExecStart=/var/Server/Server.py
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

Bearbeiten: Es ist wahrscheinlich relevant für mich, darauf hinzuweisen, dass das Python-Skript im Wesentlichen ein "Controller" für seine untergeordneten Prozesse ist. Es startet und stoppt Server in Gnu-Bildschirmen, wie von einem zentralen Server angefordert. Es läuft normalerweise immer, es spawnt keine Dienste und beendet sich nicht. Es gibt jedoch Fälle, in denen ich das Skript neu laden möchte, ohne untergeordnete Prozesse zu beenden, auch wenn dies bedeutet, dass die Prozesse auf PID 1 verwaist sind. Tatsächlich spielt es keine Rolle, ob das Python-Skript Prozesse als gestartet hat ein übergeordneter Prozess, wenn das überhaupt möglich ist.

Eine bessere Erklärung, wie es funktioniert:

  • Systemd erzeugt /Server.py
  • Server.py gibt die PID-Datei für Systemd aus und schreibt sie
  • Server.py erzeugt dann Serverprozesse auf dem Gnu-Bildschirm basierend auf seinen Anweisungen
  • Server.py wird weiterhin ausgeführt, um alle vom Server angeforderten Neustarts durchzuführen

Wenn Server.py ohne Systemd gestartet wird, kann es neu gestartet werden, und die von ihm gestarteten Gnu-Bildschirme sind nicht betroffen. Beim Starten mit Systemd werden beim Herunterfahren von Server.py diese Bildschirmprozesse nicht auf PID 1 verwaist, sondern beendet.

Bottswana
quelle
1
Es ist schwierig, eine Lösung bereitzustellen, ohne den Server.pyCode und eine Beschreibung darüber zu haben, wie die gestarteten Dienste gegabelt werden (wenn sie gegabelt werden). Im Allgemeinen handelt es sich jedoch um ein Problem mit der Nichtübereinstimmung des Bereitschaftsprotokolls .
intelfx
Übrigens wird das ExecStop=nicht benötigt. Die Standardaktion von systemd beim Stoppen ist das Abbrechen von Prozessen. Vielleicht möchten Sie einen Blick in die Dokumentation zur KillMode=Direktive werfen .
intelfx
1
Und schließlich ... Wenn es keine geeignete Bereitschaft Protokoll ist (eine simpleoder forkingtatsächlich), wäre der letzte Ausweg sein Type=oneshot, RemainAfterExit=yesund KillMode=control-group.
intelfx
@intelfx Im Wesentlichen startet das Python-Skript einen Server in einem Bildschirm mit Subprocess.call. Es ist komplizierter, weil das Skript Befehle von anderen erhält, die angeben, welche Bildschirme gestartet werden sollen und welche nicht. Welche Bildschirme verfügbar sind, ist ebenfalls dynamisch. Daher können sie keine eigenen Systemdienste sein. Idealerweise möchte ich nicht, dass systemd diese Bildschirme überhaupt als Teil des Dienstes behandelt, aber derzeit werden sie in derselben Prozessgruppe abgelegt und sterben mit dem Master, wenn dieser neu gestartet wird.
Bottswana
Meine Vermutung ist, dass systemd einen solchen Steuerprozess nicht "handhabt" (es sucht nur die PIDs zum Startzeitpunkt, erkennt die späteren nicht ...): |
Rogerdpack

Antworten:

9

Ich habe es geschafft, dies einfach zu beheben, indem ich KillMode so eingestellt habe, dass es anstelle der Kontrollgruppe verarbeitet wird (Standardeinstellung). Vielen Dank an alle

Bottswana
quelle
Das scheint eine Art Workaround zu sein, aber es ist mehr als ein Fix. Sehen Sie sich die anderen Antworten an. Wenn Sie dies tun und ein "systemctl stop" ausführen, werden die untergeordneten Prozesse, die noch ausgeführt werden, nicht beendet. [?] außerhalb der Aufsicht von systemctl?
Rogerdpack
5

Ich besitze ein Python-Skript, das beim Start abgefragt wird und für das Starten einer Reihe anderer Prozesse verantwortlich ist.

Was darauf hinweist, dass Sie es falsch machen. Mehr dazu gleich.

Wenn das Skript beendet wird, werden die untergeordneten Prozesse verwaist und weiterhin ausgeführt.

Dies ist kein korrektes Verhalten. Wenn der "Haupt" -Prozess - in diesem Fall das von Ihnen angegebene Type=forkinguntergeordnete Element - beendet wird, betrachtet systemd den Dienst als deaktiviert und beendet alle anderen noch laufenden Prozesse (in der Kontrollgruppe), um aufzuräumen .

Manchmal ist die Konvertierung von System 5- rcSkripten nach systemd nicht einfach, da die richtige Vorgehensweise unter systemd ganz anders ist. Der richtige Weg, OpenVPN, OpenStack oder OSSEC HIDS in systemd auszuführen, ist nicht derselbe wie mit einem rcSkript. Die Tatsache, dass Sie ein Skript haben, das gegabelt wird, dann eine ganze Menge von Enkelprozessen erzeugt und dann damit fertig wird, dass diese Enkelkinder weiterlaufen, zeigt an, dass Sie die gleiche Art von Horror begehen wie ossec-control, wenn auch mit zwei Stufen weniger gegabelt wird. Wenn Sie feststellen, dass Sie ein "Master" -Skript schreiben, das "enable" -Flags überprüft und untergeordnete Prozesse für die "enabled" -Teile Ihres Systems ausführt, machen Sie den gleichen Fehler wie die horrenden ossec-control.

Bei systemd sind keine solchen hausgemachten Mechanismen erforderlich. Es ist bereits ein Service Manager. Laut /unix//a/200365/5132 besteht der richtige Weg, dies in systemd zu tun, nicht darin, einen Dienst zu haben, der einen verrückten und verwirrten Versuch hervorruft, "Unterdienste" zu haben. Es ist wichtig, dass jedes untergeordnete Element als eigenständiger systemd-Dienst fungiert. Dann aktiviert und deaktiviert und startet und stoppt man die verschiedenen Teile des Systems unter Verwendung der normalen systemd-Steuerelemente. Wie Sie im OSSEC HIDS-Fall sehen können, deckt eine einfache Vorlagenserviceeinheit fast alle Dienste ab (eine Ausnahme ist /ubuntu//a/624871/43344 ), sodass Sie beispielsweise systemctl enable [email protected]eine optionale Serviceeinheit aktivieren könnenagentlessdService, ohne den fürchterlichen "Master-Script" -Mechanismus zu benötigen, der mit System 5 benötigt wurde rc.

Es gibt viele Fälle, die vielleicht nicht so extrem sind wie OSSEC HIDS, in denen ein solches Umdenken erforderlich ist. MTSes wie exim und sendmail sind zwei davon. Möglicherweise gab es ein einzelnes rcSkript, das einen Warteschlangenläufer, ein SMTP-Submission-Dæmon und ein SMTP-Relay-Dæmon erzeugte, mit einer Reihe von Ad-hoc-Shell-Variablen in einer Konfigurationsdatei, um genau zu steuern, welche ausgeführt werden. Der richtige Weg, dies mit systemd zu tun, besteht darin, drei richtige Service-Einheiten (von denen zwei zugeordnete Socket-Einheiten haben ) und überhaupt keine Ad-hoc-Dinge zu haben, sondern nur die regulären Mechanismen des Service-Managers.

JdeBP
quelle
Ich freue mich über das Feedback dazu. Ich bin damit einverstanden, dass Subset-Services sinnvoll sind, aber dies wurde in Python aus einem Grund getan, auf den ich nicht näher eingehen kann. Meine einzige Lösung besteht darin, einen Weg zu finden, wie diese Methode funktioniert. Trotzdem danke. Ich würde es gerne richtig machen.
Bottswana
Die Subservices, die das Skript startet, sind nur Server, die als bestimmter Benutzer in gnu screen ausgeführt werden. Diese Server ändern sich häufig, einige werden hinzugefügt, einige werden entfernt und dies wird an anderer Stelle gesteuert, sodass es sich nicht wirklich um tatsächliche Dienste in systemd handelt, da dies zu viel Komplexität führt und nicht zentral verwaltet werden kann. Das gleiche Skript wird auch auf Nicht-Systemd-Servern verwendet.
Bottswana
systemd verfügt über explizite Funktionen, mit denen Dienste hinzugefügt und entfernt werden können, ohne dass Root-Zugriff erforderlich ist. Das Argument "auch für Nicht-System-Dienste verwendet" ist das einzige der obigen Argumente, das nicht durch Hinzufügen von Systemd behoben werden kann. :)
Charles Duffy
0

Sie könnten einfach die Eltern schlafen und warten, bis systemd sie zum Stoppzeitpunkt beendet hat.

Craig Hicks
quelle