Starten Sie N Prozesse mit einer systemd-Servicedatei


36

Ich fand diese Systemd-Service-Datei, um autossh zu starten und einen SSH-Tunnel aufrechtzuerhalten: https://gist.github.com/thomasfr/9707568

[Unit]
Description=Keeps a tunnel to 'remote.example.com' open
After=network.target

[Service]
User=autossh
# -p [PORT]
# -l [user]
# -M 0 --> no monitoring
# -N Just open the connection and do nothing (not interactive)
# LOCALPORT:IP_ON_EXAMPLE_COM:PORT_ON_EXAMPLE_COM
ExecStart=/usr/bin/autossh -M 0 -N -q -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -p 22 -l autossh remote.example.com -L 7474:127.0.0.1:7474 -i /home/autossh/.ssh/id_rsa

[Install]
WantedBy=multi-user.target

Gibt es eine Möglichkeit, systemd so zu konfigurieren, dass mehrere Tunnel in einem Dienst gestartet werden?

Ich möchte keine N Systemdienstdateien erstellen, da ich das Kopieren und Einfügen vermeiden möchte.

Alle Servicedateien wären identisch, außer dass "remote.example.com" durch andere Hostnamen ersetzt würde.

1,5 Jahre später ...

Ich habe diese Frage vor ungefähr 1,5 Jahren gestellt.

Meine Meinung hat sich ein bisschen geändert. Ja, es ist schön, dass Sie dies mit systemd tun können (ich benutze es immer noch), aber ich werde in Zukunft das Konfigurationsmanagement verwenden.

Warum sollte systemd eine Vorlagensprache implementieren und% h ersetzen?

Einige Monate später denke ich, dass diese Schleife und das Templating mit einem Tool gelöst werden sollten, das die Konfiguration automatisiert. Ich benutze jetzt ein Tool dieser Liste bei Wikipedia .


Mit anderen Worten: Verwenden Sie ein Konfigurationsverwaltungssystem, um mehrere nahezu identische Servicedateien zu generieren, um diese Aufgabe auszuführen. Hmmm vielleicht. Wie bei den meisten derartigen Angelegenheiten gibt es keine klare Trennlinie zwischen diesen.
Pgoetz

@pgoetz config management ist für mich noch neu, aber es hat einen Vorteil, wenn Sie sich das Thema dieser Frage ansehen: Wenn Sie sich das Ergebnis der Konfigurationsverwaltung ansehen, wird es jeder verstehen, der systemd-Servicedateien kennt: einfache und einfache Servicedateien . Ich denke, es ist sinnvoller, ein Konfigurationsverwaltungssystem zu erlernen und zu verwenden, da das Wissen für alle Konfigurationsdateien in / etc verwendet werden kann, nicht nur für systemd.
Guettli

Antworten:


47

Angenommen, das Einzige, was sich pro Einheitsdatei ändert, ist das remote.example.comTeil, dann können Sie einen instanziierten Dienst verwenden .

Von der systemd.unitManpage:

Optional können Einheiten zur Laufzeit aus einer Vorlagendatei instanziiert werden. Dies ermöglicht die Erstellung mehrerer Einheiten aus einer einzigen Konfigurationsdatei. Wenn systemd nach einer Einheitenkonfigurationsdatei sucht, sucht es zuerst nach dem wörtlichen Einheitennamen im Dateisystem. Wenn dies keinen Erfolg bringt und der Einheitenname ein "@" Zeichen enthält, sucht systemd nach einer Einheitenvorlage, die denselben Namen hat, wobei jedoch die Instanzzeichenfolge (dh der Teil zwischen dem "@" Zeichen und dem Suffix) entfernt wird. Beispiel: Wenn ein Dienst getty@tty3.service angefordert wird und keine Datei mit diesem Namen gefunden wird, sucht systemd nach getty @ .service und instanziiert einen Dienst aus dieser Konfigurationsdatei, wenn er gefunden wird.

Grundsätzlich erstellen Sie eine einzelne Unit-Datei, die (normalerweise %i) eine Variable enthält, in der die Unterschiede auftreten, und die dann verknüpft wird, wenn Sie diesen Dienst "aktivieren".

Zum Beispiel habe ich eine Unit-Datei /etc/systemd/system/autossh@.service, die so aussieht:

[Unit]
Description=AutoSSH service for ServiceABC on %i
After=network.target

[Service]
Environment=AUTOSSH_GATETIME=30 AUTOSSH_LOGFILE=/var/log/autossh/%i.log AUTOSSH_PIDFILE=/var/run/autossh.%i.pid
PIDFile=/var/run/autossh.%i.pid
#Type=forking
ExecStart=/usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC %i

[Install]
WantedBy=multi-user.target

Was ich dann aktiviert habe

[user@anotherhost ~]$ sudo systemctl enable autossh@somehost.example.com
ln -s '/etc/systemd/system/autossh@.service' '/etc/systemd/system/multi-user.target.wants/autossh@somehost.example.com.service'

Und kann mit interagieren

[user@anotherhost ~]$ sudo systemctl start autossh@somehost.example.com
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
autossh@somehost.example.service - AutoSSH service for ServiceABC on somehost.example
   Loaded: loaded (/etc/systemd/system/autossh@.service; enabled)
   Active: active (running) since Tue 2015-10-20 13:19:01 EDT; 17s ago
 Main PID: 32524 (autossh)
   CGroup: /system.slice/system-autossh.slice/autossh@somehost.example.com.service
           ├─32524 /usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC somehost.example.com
           └─32525 /usr/bin/ssh -L 40000:127.0.0.1:40000 -R 40000:127.0.0.1:40001 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC somehost.example.com

Oct 20 13:19:01 anotherhost.example.com systemd[1]: Started AutoSSH service for ServiceABC on somehost.example.com.
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
[user@anotherhost ~]$ sudo systemctl status autossh@somehost.example.com
autossh@somehost.example.com.service - AutoSSH service for ServiceABC on somehost.example.com
   Loaded: loaded (/etc/systemd/system/autossh@.service; enabled)
   Active: inactive (dead) since Tue 2015-10-20 13:24:10 EDT; 2s ago
  Process: 32524 ExecStart=/usr/bin/autossh -M 40000 -NR 5000:127.0.0.1:5000 -i /opt/ServiceABC/.ssh/id_rsa_ServiceABC -l ServiceABC %i (code=exited, status=0/SUCCESS)
 Main PID: 32524 (code=exited, status=0/SUCCESS)

Oct 20 13:19:01 anotherhost.example.com systemd[1]: Started AutoSSH service for ServiceABC on somehost.example.com.
Oct 20 13:24:10 anotherhost.example.com systemd[1]: Stopping AutoSSH service for ServiceABC on somehost.example.com...
Oct 20 13:24:10 anotherhost.example.com systemd[1]: Stopped AutoSSH service for ServiceABC on somehost.example.com.

Wie Sie sehen, werden alle Instanzen %iin der Unit-Datei durch ersetzt somehost.example.com.

Es gibt zwar eine Menge weiterer Spezifizierer , die Sie in einer Unit-Datei verwenden können, aber ich finde %i, dass sie in solchen Fällen am besten funktionieren.


Wow, Systemd ist großartig.
Guettli

Sie zeigen nicht, wie beim Booten automatisch gestartet wird, auch nicht, welche gestartet werden sollen.
Craig Hicks

Bei Systemd bewirkt die enableAktion, dass eine Einheit / ein Dienst beim Booten gestartet wird.
GregL

Kann ich die Instanzen unabhängig aktivieren / deaktivieren?
Soumya Kanti

Ja, genau das tun Sie, wenn Sie sie aktivieren / deaktivieren.
GregL

15

Hier ist ein Python-Beispiel, nach dem ich gesucht habe. Mit @dem Dateinamen im Dienst können Sie N Prozesse starten:

$ cat /etc/systemd/system/my-worker@.service

[Unit]
Description=manages my worker service, instance %i
After=multi-user.target

[Service]
PermissionsStartOnly=true
Type=idle
User=root
ExecStart=/usr/local/virtualenvs/bin/python /path/to/my/script.py
Restart=always
TimeoutStartSec=10
RestartSec=10

Verschiedene Methoden, um es aufzurufen

Verschiedene Zählungen aktivieren, zum Beispiel:

  • Erlaube 30 Arbeiter:

    sudo systemctl enable my-worker\@{1..30}.service
    
  • 2 Arbeiter aktivieren:

    sudo systemctl enable my-worker\@{1..2}.service
    

Stellen Sie dann sicher, dass Sie Folgendes neu laden:

sudo systemctl daemon-reload

Jetzt können Sie dann auf verschiedene Arten starten / stoppen:

  • Start 1:

    sudo systemctl start my-worker@2.service
    
  • Mehrere starten:

    sudo systemctl start my-worker@{1..2}
    
  • Mehrere stoppen:

    sudo systemctl stop my-worker@{1..2}
    
  • Status überprüfen:

    sudo systemctl status my-worker@1
    

UPDATE : Um Instanzen als einen Dienst zu verwalten, können Sie folgendermaßen vorgehen:

/etc/systemd/system/some-worker@.service:

[Unit]
Description=manage worker instances as a service, instance %i
Requires=some-worker.service
Before=some-worker.service
BindsTo=some-worker.service

[Service]
PermissionsStartOnly=true
Type=idle
User=root
#EnvironmentFile=/etc/profile.d/optional_envvars.sh
ExecStart=/usr/local/virtualenvs/bin/python /path/to/my/script.py
TimeoutStartSec=10
RestartSec=10

[Install]
WantedBy=some-worker.service

/usr/bin/some-worker-start.sh:

#!/bin/bash
systemctl start some-worker@{1..10}

/etc/systemd/system/some-worker.service:

[Unit]
Description=manages some worker instances as a service, instance

[Service]
Type=oneshot
ExecStart=/usr/bin/sh /usr/bin/some-worker-start.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Und jetzt können Sie alle Instanzen mit verwalten sudo systemctl some-worker (start|restart|stop)

Hier ist ein Kesselschild für Ihre script.py:

#!/usr/bin/env python

import logging


def worker_loop():
    shutdown = False
    while True:

        try:
            if shutdown:
                break

            # Your execution logic here.
            # Common logic - i.e. consume from a queue, perform some work, ack message
            print("hello world")

        except (IOError, KeyboardInterrupt):
            shutdown = True
            logging.info("shutdown received - processing will halt when jobs complete")
        except Exception as e:
            logging.exception("unhandled exception on shutdown. {}".format(e))


if __name__ == '__main__':
    worker_loop()

@radek: Zwei Dinge, die ich nicht verstehe: Erstens wird% i nur in der Beschreibung der Unit-Datei verwendet. Woher weiß der Startbefehl, was zu starten ist? Zweitens, woher systemctl some-worker (start|restart|stop)wissen Sie, an welchen Instanzen Sie arbeiten müssen?
U. Windl

% i ist die Ausgabe von @ im Namen der Servicedatei. Der zweite Teil ist bereits in der Antwort erläutert, vgl Now you can start/stop then in various ways.
Radtek

Ich denke, seine Antwort ist unvollständig, ohne dass die Skripte beteiligt sind. Die meiste "Magie" wird in den fehlenden Skripten ausgeführt.
U. Windl

Ich habe hier tatsächlich eine voll funktionsfähige Lösung bereitgestellt. Auf welche "Skripte" beziehen Sie sich? /path/to/my/script.py kann sein, was immer Sie wollen, eine "Hallo Welt", wenn Sie wollen. Etwas, das so lange aktiv bleibt, bis es ein Kill-Signal empfängt. Bitte beachten Sie, dass die Frage nicht spezifisch für Python ist.
Radtek

Wow, damit können Sie mehrere gleichzeitig starten?
umwerfend

1

GregLs Antwort hat mir sehr geholfen. Hier ist ein Beispiel für eine Einheitenvorlage, die ich in meinem Code anhand des obigen Beispiels für einen Gearman-Jobserver verwendet habe. Ich habe ein Shell-Skript erstellt, mit dem ich mithilfe dieser einen Vorlage eine Menge "Worker" erstellen kann.

[Unit]
Description=az gearman worker
After=gearman-job-server.service

[Service]
PIDFile=/var/run/gearman_worker_az%i.pid
Type=simple
User=www-data
WorkingDirectory=/var/www/mysite.com/jobs/
ExecStart=/usr/bin/php -f gearman_worker_az.php > /dev/null 2>&1
Restart=on-success
KillMode=process

[Install]
WantedBy=multi-user.target
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.