Rozpocznij N procesów za pomocą jednego pliku usługi systemowej

36

Znalazłem ten plik usługi systemowej, aby uruchomić autossh, aby utrzymać tunel ssh: 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

Czy istnieje sposób skonfigurowania systemd, aby uruchamiał kilka tuneli w jednej usłudze.

Nie chcę tworzyć plików usługi systemowej N, ponieważ chcę uniknąć kopiowania i wklejania.

Wszystkie pliki usług byłyby identyczne, z wyjątkiem „remote.example.com” zostałyby zastąpione innymi nazwami hosta.

1,5 roku później ...

Zadałem to pytanie około 1,5 roku temu.

Mój umysł trochę się zmienił. Tak, fajnie, że możesz to zrobić za pomocą systemd (nadal go używam), ale w przyszłości będę używać zarządzania konfiguracją.

Dlaczego systemd powinien wdrożyć język szablonów i zastąpić% h?

Kilka miesięcy później myślę, że tę pętlę i szablony należy rozwiązać za pomocą narzędzia automatyzującego konfigurację. Używam teraz jednego narzędzia z tej listy na wikipedii .

guettli
źródło
Innymi słowy, mówisz, aby użyć systemu zarządzania konfiguracją do wygenerowania wielu prawie identycznych plików usług, aby wykonać to zadanie? Hmmm, może. Jak w większości takich spraw, nie ma wyraźnej linii podziału między nimi.
pgoetz
@pgoetz zarządzanie konfiguracją wciąż jest dla mnie nowe, ale przynosi korzyść, jeśli spojrzysz na temat tego pytania: Jeśli spojrzysz na wynik zarządzania konfiguracją, zrozumie go każdy, kto zna pliki usług systemowych: zwykłe i proste pliki usług . Myślę, że sensowniej jest uczyć się i używać systemu zarządzania konfiguracją, ponieważ wiedza ta może być wykorzystana do wszystkich konfiguracji w / etc, nie tylko systemd.
guettli

Odpowiedzi:

47

Zakładając, że jedyną zmianą na plik jednostkowy jest remote.example.comczęść, możesz skorzystać z usługi tworzenia instancji .

Ze strony podręcznika systemd.unit:

Opcjonalnie jednostki mogą być tworzone z pliku szablonu w czasie wykonywania. Umożliwia to tworzenie wielu jednostek z jednego pliku konfiguracyjnego. Jeśli systemd szuka pliku konfiguracji jednostki, najpierw szuka literalnej nazwy jednostki w systemie plików. Jeśli to się nie powiedzie, a nazwa jednostki zawiera znak „@”, systemd wyszuka szablon jednostki o tej samej nazwie, ale z ciągiem instancji (tj. Część między znakiem „@” a sufiksem) usunięta. Przykład: jeśli zażądano usługi [email protected] i nie znaleziono pliku o tej nazwie, systemd wyszuka getty@ .service i utworzy instancję usługi z tego pliku konfiguracyjnego, jeśli zostanie znaleziona.

Zasadniczo tworzysz pojedynczy plik jednostkowy, który zawiera zmienną (zwykle %i), w której występują różnice, a następnie łączy się ją, gdy „włączysz” tę usługę.

Na przykład mam plik o nazwie, /etc/systemd/system/[email protected]który wygląda następująco:

[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

Które następnie włączyłem

[user@anotherhost ~]$ sudo systemctl enable [email protected]
ln -s '/etc/systemd/system/[email protected]' '/etc/systemd/system/multi-user.target.wants/[email protected]'

I może wchodzić w interakcje z

[user@anotherhost ~]$ sudo systemctl start [email protected]
[user@anotherhost ~]$ sudo systemctl status [email protected]
[email protected] - AutoSSH service for ServiceABC on somehost.example
   Loaded: loaded (/etc/systemd/system/[email protected]; 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/[email protected]
           ├─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 [email protected]
[user@anotherhost ~]$ sudo systemctl status [email protected]
[email protected] - AutoSSH service for ServiceABC on somehost.example.com
   Loaded: loaded (/etc/systemd/system/[email protected]; 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.

Jak widać, wszystkie wystąpienia %ipliku jednostkowego zostają zastąpione przez somehost.example.com.

Jest jeszcze kilka specyfikatorów , których można użyć w pliku jednostkowym, ale uważam, że %inajlepiej działa w takich przypadkach.

GregL
źródło
Wow, systemd jest świetny.
guettli
Nie pokazujesz, jak uruchomić automatycznie przy starcie systemu, w tym tych, które chcesz uruchomić.
Craig Hicks,
W Systemd enableakcja powoduje, że jednostka / usługa zaczyna się przy starcie.
GregL,
Czy mogę samodzielnie włączyć / wyłączyć instancje?
Soumya Kanti
Tak, właśnie to robisz, kiedy je włączasz / wyłączasz.
GregL,
15

Oto przykład python, którego szukałem. Nazwa @pliku usługi umożliwia uruchomienie N procesów:

$ cat /etc/systemd/system/[email protected]

[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

Różne metody, aby to nazwać

Włączanie różnych zliczeń, na przykład:

  • Włącz 30 pracowników:

    sudo systemctl enable my-worker\@{1..30}.service
    
  • Włącz 2 pracowników:

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

Następnie pamiętaj, aby ponownie załadować:

sudo systemctl daemon-reload

Teraz możesz zacząć / zatrzymać na różne sposoby:

  • Rozpocznij 1:

    sudo systemctl start [email protected]
    
  • Rozpocznij wiele:

    sudo systemctl start my-worker@{1..2}
    
  • Zatrzymaj wiele:

    sudo systemctl stop my-worker@{1..2}
    
  • Sprawdź status:

    sudo systemctl status my-worker@1
    

AKTUALIZACJA : Aby zarządzać instancjami jako jedną usługą, możesz zrobić coś takiego:

/etc/systemd/system/[email protected]:

[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

A teraz możesz zarządzać wszystkimi instancjami za pomocą sudo systemctl some-worker (start|restart|stop)

Oto płyta dla Twojego 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()
radtek
źródło
@radek: Dwie rzeczy, których nie rozumiem: po pierwsze,% i jest używany tylko w opisie pliku jednostki. Skąd polecenie start wie, od czego zacząć? Po drugie, skąd systemctl some-worker (start|restart|stop)wiadomo, w których przypadkach należy pracować?
U. Windl
% i jest wyjściem @ w nazwie pliku usługi. Druga część jest już wyjaśniona w odpowiedzi, patrz Now you can start/stop then in various ways.
radtek
Myślę, że jego odpowiedź jest niepełna bez udziału scenariuszy. Większość „magii” odbywa się w brakujących skryptach.
U. Windl
Dostarczyłem tutaj w pełni funkcjonujące rozwiązanie. O których „skryptach” mówisz? /path/to/my/script.py może być czymkolwiek chcesz, „cześć światem”, jeśli chcesz. Coś, co pozostanie uruchomione, dopóki nie otrzyma sygnału zabicia. Uwaga: pytanie nie jest specyficzne dla Pythona.
radtek
Wow, pozwala na rozpoczęcie wielokrotności naraz? umysł
oszalały
1

Odpowiedź GregLa bardzo mi pomogła. Oto przykład szablonu jednostki, którego użyłem w moim kodzie, korzystając z powyższego przykładu dla serwera zadań gearman. Zrobiłem skrypt powłoki, który pozwala mi utworzyć X „pracowników” przy użyciu tego jednego szablonu.

[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
Kyle Anderson
źródło