web-dev-qa-db-fra.com

Démarrer N processus avec un fichier de service systemd

J'ai trouvé ce fichier de service systemd pour démarrer l'autossh pour maintenir un tunnel 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

Existe-t-il un moyen de configurer systemd pour démarrer plusieurs tunnels dans un service.

Je ne veux pas créer de fichiers de service système N, car je veux éviter le copier-coller.

Tous les fichiers de service seraient identiques, sauf que "remote.example.com" serait remplacé par d'autres noms d'hôte.

1,5 an plus tard ...

J'ai posé cette question il y a environ 1,5 an.

Mon esprit a changé. Oui, c'est bien que vous puissiez le faire avec systemd, mais j'utiliserai la gestion de la configuration à l'avenir.

Pourquoi systemd devrait-il implémenter un langage de modèle et remplacer% h? .. Je pense que cela n'a aucun sens.

Plusieurs mois plus tard, je pense que cette boucle et ce modèle devraient être résolus à un niveau différent. J'utiliserais Ansible ou TerraForm pour cela maintenant.

39
guettli

Eh bien, en supposant que la chose seulement qui change par fichier d'unité est le remote.example.com partie, vous pouvez utiliser un InstanciéService .

Du systemd.unit page de manuel:

Facultativement, les unités peuvent être instanciées à partir d'un fichier modèle lors de l'exécution. Cela permet la création de plusieurs unités à partir d'un seul fichier de configuration. Si systemd recherche un fichier de configuration d'unité, il recherchera d'abord le nom d'unité littéral dans le système de fichiers. Si cela ne réussit pas et que le nom de l'unité contient un caractère "@", systemd recherchera un modèle d'unité qui partage le même nom mais avec la chaîne d'instance (c'est-à-dire la partie entre le caractère "@" et le suffixe) supprimée. Exemple: si un service [email protected] est demandé et qu'aucun fichier de ce nom n'est trouvé, systemd recherchera getty @ .service et instanciera un service à partir de ce fichier de configuration s'il est trouvé.

Fondamentalement, vous créez un fichier d'unité unique, qui contient une variable (généralement %i) où les différences se produisent, puis elles sont liées lorsque vous "activez" ce service.

Par exemple, j'ai un fichier d'unité appelé /etc/systemd/system/[email protected] qui ressemble à ceci:

[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

Que j'ai ensuite activé

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

Et peut interagir avec

[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.

Comme vous pouvez le voir, toutes les instances de %i dans le fichier d'unité est remplacé par somehost.example.com.

Il y a beaucoup plus spécificateurs que vous pouvez utiliser dans un fichier d'unité, mais je trouve %i pour fonctionner au mieux dans des cas comme celui-ci.

50
GregL

Voici un exemple python, ce que je cherchais. Le @ Dans le nom de fichier du service vous permet de démarrer N processus:

$ 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

Différentes méthodes pour l'appeler

Activer divers comptages par exemple:

  • Activer 30 employés:

    Sudo systemctl enable my-worker\@{1..30}.service
    
  • Activer 2 travailleurs:

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

Assurez-vous ensuite de recharger:

Sudo systemctl daemon-reload

Vous pouvez maintenant démarrer/arrêter de différentes manières:

  • Début 1:

    Sudo systemctl start [email protected]
    
  • Démarrer plusieurs:

    Sudo systemctl start my-worker@{1..2}
    
  • Arrêter plusieurs:

    Sudo systemctl stop my-worker@{1..2}
    
  • Vérifier l'état:

    Sudo systemctl status my-worker@1
    

UPDATE : Pour gérer les instances comme un seul service, vous pouvez faire quelque chose comme ceci:

/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

Et maintenant, vous pouvez gérer toutes les instances avec Sudo systemctl some-worker (start|restart|stop)

Voici un passe-partout pour votre 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()
19
radtek

La réponse de GregL m'a beaucoup aidé. Voici un exemple de modèle d'unité que j'ai utilisé dans mon code en utilisant l'exemple ci-dessus pour un serveur de tâches Gearman. J'ai fait un script Shell qui me permet de créer X quantité de "travailleurs" en utilisant ce modèle.

[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
1
Kyle Anderson

J'ai cherché une solution à une tâche similaire et en ai trouvé une, que je crois plus facile à accomplir, mais qui est censée être hacky . (et n'est pas mentionné ici)

J'avais besoin de créer plusieurs connexions ssh après que vpn ait créé un tunnel, j'ai donc créé un service qui dépend du périphérique tun et appelle le script Shell avec les commandes appropriées.

Service /etc/systemd/system/ssh_tunnel.service:

[Unit]
Description=Reverse SSH Service to access hidden services
ConditionPathExists=|/usr/bin
Wants=sys-devices-virtual-net-tun0.device
After=network.target sys-devices-virtual-net-tun0.device

[Service]
Type=forking
ExecStart=/bin/sh /etc/openvpn/ssh_tunnels.sh 
RemainAfterExit=yes
TimeoutSec=0
GuessMainPID=no

[Install]
WantedBy=multi-user.target

/etc/openvpn/ssh_tunnels.sh:

!/bin/bash
#sleep 15

echo 'Tunelling some ports'
killall -HUP ssh

su - user -c 'ssh -f [email protected] -p 9999 -L :3690:svn.newbox.ru:3690 -L :8888:10.1.20.55:80 -L :8181:10.1.10.10:80 -N -vvv'

ssh -i /home/user/.ssh/id_rsa -f [email protected] -p 9999 -L :587:mail.domain.ru:587 -L :995:mail.newbox.ru:995 -L :22:10.1.2.1:22 -N -vvv &

exit 0

Résultat:

# systemctl status ssh_tunnel.service
● ssh_smartex.service - Reverse SSH Service to access hidden services
     Loaded: loaded (/etc/systemd/system/ssh_tunnel.service; enabled; vendor preset: disabled)
     Active: active (running) since Fri 2020-03-20 16:01:07 UTC; 22min ago
    Process: 156 ExecStart=/bin/sh /etc/openvpn/ssh_tunnel.sh (code=exited, status=0/SUC>
      Tasks: 2 (limit: 4915)
     Memory: 3.8M
     CGroup: /system.slice/ssh_tunnel.service
             ├─166 ssh -f [email protected] -p 9999 -L :3690:svn.newbox.ru:3690 -L :8888:10.1.20.55:80 ->
             └─168 ssh -i /home/user/.ssh/id_rsa -f [email protected] -p 9999 -L :587:mail.newbox.ru:5>
...

Cependant, je n'ai pas encore vérifié comment il survit au redémarrage de VPN, mais c'est un autre sujet.

0
diabolusss