56 votes

Démarrer N processus avec un seul fichier de service systemd

J'ai trouvé ce fichier de service systemd pour démarrer autossh afin de 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 qu'il démarre plusieurs tunnels à la fois ? un service.

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

Tous les fichiers de service seraient identiques, à l'exception de "remote.example.com" qui serait remplacé par d'autres noms d'hôtes.

1,5 an plus tard ...

J'ai posé cette question il y a environ un an et demi.

J'ai changé d'avis. Oui, c'est bien de pouvoir le faire avec systemd, mais j'utiliserai la gestion de configuration à l'avenir.

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

Plusieurs mois plus tard, je pense que ces boucles et ces modèles devraient être résolus à un autre niveau. J'utiliserais Ansible ou TerraForm pour cela maintenant.

62voto

Jojje Points 353

Eh bien, en supposant que le seulement Ce qui change par dossier unitaire, c'est la remote.example.com vous pouvez utiliser un Instancié Service .

からの systemd.unit page de manuel :

En option, les unités peuvent être instanciées à partir d'un modèle. Cela permet de créer plusieurs unités à partir d'un seul fichier de configuration. de configuration. Si systemd recherche un fichier de configuration d'unité, il va d'abord d'abord le nom littéral de l'unité dans le système de fichiers. Si cette recherche n'aboutit pas et que le nom de l'unité n'est pas succès et que le nom de l'unité contient un caractère "@", systemd cherchera un 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 getty@tty3.service est demandé et qu'aucun fichier de ce nom n'est trouvé, systemd cherchera getty@.service et instanciera un service à partir de ce fichier de configuration s'il est trouvé.

En principe, vous créez un seul fichier unitaire, qui contient une variable (généralement %i ) où se situent les différences, puis ils sont liés lorsque vous "activez" ce service.

Par exemple, j'ai un fichier d'unité appelé /etc/systemd/system/autossh@.service 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ée

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

Et peut interagir avec

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

Comme vous pouvez le constater, toutes les instances de %i dans le fichier de l'unité sont remplacés par somehost.example.com .

Il y en a encore beaucoup d'autres spécificateurs que l'on peut utiliser dans un fichier d'unité, mais je trouve qu'il n'y a pas d'autre solution que d'utiliser un fichier d'unité. %i sont les plus efficaces dans des cas comme celui-ci.

35voto

radtek Points 405

Voici un exemple en Python, qui correspond à ce que je cherchais. Les @ dans le nom du fichier de service permet de lancer N processus :

$ 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

Différentes méthodes pour l'appeler

Permettre divers décomptes, par exemple :

  • Permettre à 30 travailleurs de travailler :

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

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

Veillez ensuite à recharger :

sudo systemctl daemon-reload

Désormais, vous pouvez démarrer/arrêter de différentes manières :

  • Début 1 :

    sudo systemctl start my-worker@2.service
  • Début Multiple :

    sudo systemctl start my-worker@{1..2}
  • Stop Multiple :

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

    sudo systemctl status my-worker@1

MISE À JOUR : Pour gérer les instances en tant que service unique, vous pouvez procéder comme suit :

/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

Vous pouvez désormais gérer toutes les instances à l'aide de sudo systemctl some-worker (start|restart|stop)

Voici un modèle de document 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()

2voto

Kyle Anderson Points 161

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 travail gearman. J'ai créé un Shell Shell qui me permet de créer un nombre X 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

-1voto

diabolusss Points 11

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

J'avais besoin de créer plusieurs connexions ssh après que le vpn ait créé un tunnel, J'ai donc créé un service qui dépend de l'appareil tun et qui appelle Shell 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 admin@172.171.1.1 -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 admin@172.171.1.1 -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 admin@172.171.1.1 -p 9999 -L :3690:svn.newbox.ru:3690 -L :8888:10.1.20.55:80 ->
             168 ssh -i /home/user/.ssh/id_rsa -f admin@172.171.1.1 -p 9999 -L :587:mail.newbox.ru:5>
...

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

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X