Avviare N processi con un file di servizio systemd


36

Ho trovato questo file di servizio systemd per avviare l'autossh per mantenere 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

C'è un modo per configurare systemd per avviare diversi tunnel in un servizio.

Non voglio creare file di servizio di sistema N, poiché voglio evitare copia + incolla.

Tutti i file di servizio sarebbero identici eccetto "remote.example.com" sarebbe sostituito con altri nomi host.

1,5 anni dopo ...

Ho fatto questa domanda circa 1,5 anni fa.

La mia mente è cambiata un po '. Sì, è bello poterlo fare con systemd (lo uso ancora), ma in futuro userò la gestione della configurazione.

Perché systemd dovrebbe implementare un linguaggio modello e sostituire% h?

Diversi mesi dopo penso che questo ciclo e il modello dovrebbero essere risolti con uno strumento che automatizza la configurazione. Ora uso uno strumento di questo elenco su Wikipedia .


In altre parole, stai dicendo che utilizzare un sistema di gestione della configurazione per generare più file di servizio quasi identici per eseguire questa attività? Hmmm, forse. Come con la maggior parte di tali questioni, non esiste una chiara linea di demarcazione che li separa.
pgoetz,

La gestione della configurazione di @pgoetz è ancora nuova per me, ma ha un vantaggio se si esamina l'argomento di questa domanda: se si osserva il risultato della gestione della configurazione, tutti coloro che conoscono i file di servizio di sistema lo capiranno: file di servizio chiari e semplici . Penso che abbia più senso imparare e usare un sistema di gestione della configurazione poiché le conoscenze possono essere usate per tutte le configurazioni in / etc, non solo per systemd.
Guettli,

Risposte:


47

Bene, supponendo che l' unica cosa che cambia per file unitario sia la remote.example.comparte, è possibile utilizzare un servizio di istanza .

Dalla systemd.unitpagina man:

Facoltativamente, le unità possono essere istanziate da un file modello in fase di esecuzione. Ciò consente la creazione di più unità da un singolo file di configurazione. Se systemd cerca un file di configurazione dell'unità, cercherà prima il nome letterale dell'unità nel file system. Se ciò non ha esito positivo e il nome dell'unità contiene un carattere "@", systemd cercherà un modello di unità che condivida lo stesso nome ma con la stringa di istanza (ovvero la parte tra il carattere "@" e il suffisso) rimossa. Esempio: se viene richiesto un servizio getty@tty3.service e non viene trovato alcun file con quel nome, systemd cercherà getty @ .service e se verrà trovato un servizio da quel file di configurazione.

Fondamentalmente, si crea un singolo file di unità, che contiene una variabile (di solito %i) in cui si verificano le differenze e quindi vengono collegate quando si "abilita" quel servizio.

Ad esempio, ho un file di unità chiamato /etc/systemd/system/autossh@.serviceche assomiglia a questo:

[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

Che ho quindi abilitato

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

E può interagire con

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

Come puoi vedere, tutte le istanze di %inel file unit vengono sostituite con somehost.example.com.

Ci sono molti altri identificatori che puoi usare in un file unitario, ma trovo %iche funzioni meglio in casi come questo.


Wow, systemd è fantastico.
Guettli,

Non si mostra come avviare automaticamente all'avvio, inclusi quelli da avviare.
Craig Hicks,

Con Systemd, l' enableazione è ciò che avvia un'unità / servizio all'avvio.
GregL

Posso abilitare / disabilitare le istanze in modo indipendente?
Soumya Kanti,

Sì, è quello che stai facendo quando li abiliti / disabiliti.
GregL

15

Ecco un esempio di pitone, che era quello che stavo cercando. Il @nome file nel servizio consente di avviare N processi:

$ 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

Vari metodi per chiamarlo

Abilitazione di vari conteggi, ad esempio:

  • Abilita 30 lavoratori:

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

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

Quindi assicurati di ricaricare:

sudo systemctl daemon-reload

Ora puoi avviare / arrestare quindi in vari modi:

  • Inizia 1:

    sudo systemctl start my-worker@2.service
    
  • Inizia multiplo:

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

    sudo systemctl stop my-worker@{1..2}
    
  • Controllare lo stato:

    sudo systemctl status my-worker@1
    

AGGIORNAMENTO : per gestire le istanze come un servizio, puoi fare qualcosa del genere:

/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

E ora puoi gestire tutte le istanze con sudo systemctl some-worker (start|restart|stop)

Ecco alcuni piatti per il tuo 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: due cose che non capisco: in primo luogo,% i viene utilizzato solo nella descrizione del file dell'unità. In che modo il comando start sa cosa iniziare? Secondo, come fa a systemctl some-worker (start|restart|stop)sapere su quali istanze lavorare?
U. Windl,

% i è l'output di @ nel nome del file di servizio. La seconda parte è già spiegata nella risposta, vedi Now you can start/stop then in various ways.
Radtek,

Penso che la sua risposta sia incompleta senza che gli script siano coinvolti. La maggior parte della "magia" viene eseguita all'interno degli script mancanti.
U. Windl

In realtà qui ho fornito una soluzione completa. A quali "script" ti riferisci? /path/to/my/script.py può essere quello che vuoi, un "ciao mondo" se vuoi. Qualcosa che rimarrà attivo fino a quando non riceverà un segnale di uccisione. Si noti che la domanda non è specifica per Python.
Radtek,

Wow, ti permette di iniziare multipli alla volta? mind blown ...
rogerdpack

1

La risposta di GregL mi ha aiutato moltissimo. Ecco un esempio di un modello di unità che ho usato nel mio codice usando l'esempio sopra per un job server di Gearman. Ho creato uno script di shell che mi consente di creare una quantità X di "lavoratori" utilizzando questo modello.

[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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.