Iniciar N procesos con un archivo de servicio systemd

36

Encontré este archivo de servicio systemd para iniciar autossh para mantener un túnel 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

¿Hay alguna manera de configurar systemd para iniciar varios túneles en un servicio?

No quiero crear archivos de servicio del sistema N, ya que quiero evitar copiar y pegar.

Todos los archivos de servicio serían idénticos, excepto que "remote.example.com" se reemplazaría con otros nombres de host.

1.5 años después ...

Hice esta pregunta hace aproximadamente 1,5 años.

Mi mente ha cambiado un poco. Sí, es bueno que pueda hacer esto con systemd (todavía lo uso), pero usaré la gestión de configuración en el futuro.

¿Por qué systemd debería implementar un lenguaje de plantilla y sustituir% h?

Varios meses después, creo que este ciclo y la plantilla deberían resolverse con una herramienta que automatice la configuración. Ahora uso una herramienta de esta lista en wikipedia .

guettli
fuente
En otras palabras, ¿está utilizando un sistema de gestión de configuración para generar múltiples archivos de servicio casi idénticos para realizar esta tarea? Hmmm, tal vez. Como con la mayoría de estos asuntos, no hay una línea divisoria clara que los separe.
pgoetz el
@pgoetz config management todavía es nuevo para mí, pero tiene un beneficio si nos fijamos en el tema de esta pregunta: si nos fijamos en el resultado de la gestión de la configuración, todos los que conocen los archivos de servicio systemd lo entenderán: archivos de servicio simples y sencillos . Creo que tiene más sentido aprender y usar un sistema de administración de configuración ya que el conocimiento se puede usar para toda la configuración en / etc, no solo systemd.
guettli

Respuestas:

47

Bueno, suponiendo que lo único que cambia por archivo de unidad es la remote.example.comparte, puede usar un Servicio instanciado .

Desde la systemd.unitpágina del manual:

Opcionalmente, las unidades se pueden instanciar desde un archivo de plantilla en tiempo de ejecución. Esto permite la creación de múltiples unidades desde un único archivo de configuración. Si systemd busca un archivo de configuración de la unidad, primero buscará el nombre de la unidad literal en el sistema de archivos. Si eso no tiene éxito y el nombre de la unidad contiene un carácter "@", systemd buscará una plantilla de unidad que comparta el mismo nombre pero con la cadena de instancia (es decir, la parte entre el carácter "@" y el sufijo) eliminada. Ejemplo: si se solicita un servicio [email protected] y no se encuentra ningún archivo con ese nombre, systemd buscará getty @ .service e instanciará un servicio de ese archivo de configuración si se encuentra.

Básicamente, crea un archivo de unidad única, que contiene una variable (generalmente %i ) donde ocurren las diferencias y luego se vinculan cuando "habilita" ese servicio.

Por ejemplo, tengo un archivo de unidad llamado /etc/systemd/system/[email protected]que se ve así:

[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 luego he habilitado

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

Y puede interactuar con

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

Como puede ver, todas las instancias del %iarchivo de la unidad se reemplazan consomehost.example.com .

Sin embargo, hay muchos más especificadores que puedes usar en un archivo de unidad, pero creo %ique funciona mejor en casos como este.

GregL
fuente
Wow, systemd es genial.
guettli
No muestra cómo iniciar automáticamente en el arranque, ni cuáles comenzar.
Craig Hicks
Con Systemd, la enableacción es lo que hace que una unidad / servicio comience en el arranque.
GregL
¿Puedo habilitar / deshabilitar las instancias de forma independiente?
Soumya Kanti
Sí, eso es lo que estás haciendo cuando los habilitas / deshabilitas.
GregL
15

Aquí hay un ejemplo de Python, que era lo que estaba buscando. El @nombre de archivo en el servicio le permite iniciar N procesos:

$ 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

Varios métodos para llamarlo

Habilitar varios recuentos, por ejemplo:

  • Habilitar 30 trabajadores:

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

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

Entonces asegúrese de recargar:

sudo systemctl daemon-reload

Ahora puede iniciar / detener luego de varias maneras:

  • Inicio 1:

    sudo systemctl start [email protected]
    
  • Inicio múltiple:

    sudo systemctl start my-worker@{1..2}
    
  • Detener múltiples:

    sudo systemctl stop my-worker@{1..2}
    
  • Comprobar estado:

    sudo systemctl status my-worker@1
    

ACTUALIZACIÓN : para administrar instancias como un servicio, puede hacer algo como esto:

/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

Y ahora puede administrar todas las instancias con sudo systemctl some-worker (start|restart|stop)

Aquí hay algunos ejemplos para su 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
fuente
@radek: Dos cosas que no entiendo: Primero,% i solo se usa en la descripción del archivo de la unidad. ¿Cómo sabe el comando de inicio qué comenzar? Segundo, ¿cómo systemctl some-worker (start|restart|stop)sabe en qué instancias trabajar?
U. Windl
% i es la salida de @ en el nombre del archivo de servicio. La segunda parte ya se explica en la respuesta, ver Now you can start/stop then in various ways.
radtek
Creo que su respuesta es incompleta sin los guiones involucrados. La mayoría de la "magia" se realiza dentro de los guiones que faltan.
U. Windl
He proporcionado una solución de trabajo completa aquí en realidad. ¿A qué "guiones" te refieres? /path/to/my/script.py puede ser lo que quieras, un "hola mundo" si quieres. Algo que seguirá funcionando hasta que reciba una señal de muerte. Tenga en cuenta que la pregunta no es específica de Python.
Radtek
Wow, te permite comenzar múltiples a la vez? alucinante ...
rogerdpack
1

La respuesta de GregL me ayudó mucho. Aquí hay un ejemplo de una plantilla de unidad que utilicé en mi código usando el ejemplo anterior para un servidor de trabajo gearman. Hice un script de shell que me permite crear una cantidad X de "trabajadores" usando esta plantilla.

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