Iniciar processos N com um arquivo de serviço systemd

36

Encontrei este arquivo de serviço systemd para iniciar o autossh e manter um 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

Existe uma maneira de configurar o systemd para iniciar vários túneis em um serviço.

Não quero criar arquivos de serviço do sistema N, pois quero evitar copiar e colar.

Todos os arquivos de serviço seriam idênticos, exceto que "remote.example.com" seria substituído por outros nomes de host.

1,5 ano depois ...

Eu fiz essa pergunta aproximadamente 1,5 ano atrás.

Minha mente mudou um pouco. Sim, é bom que você possa fazer isso com o systemd (eu ainda o uso), mas usarei o gerenciamento de configurações no futuro.

Por que o systemd deve implementar uma linguagem de modelo e substituir% h?

Vários meses depois, acho que esse loop e modelagem devem ser resolvidos com uma ferramenta que automatiza a configuração. Eu uso uma ferramenta desta lista na wikipedia agora.

guettli
fonte
Em outras palavras, você está dizendo usar um sistema de gerenciamento de configuração para gerar vários arquivos de serviço quase idênticos para realizar essa tarefa? Hummm, talvez. Como na maioria desses assuntos, não há uma linha divisória clara que os separa.
pgoetz 12/01
O gerenciamento de configuração do @pgoetz ainda é novo para mim, mas tem um benefício se você examinar o tópico desta pergunta: Se você observar o resultado do gerenciamento de configuração, todos que souberem os arquivos de serviço systemd o entenderão: arquivos de serviço simples e simples . Eu acho que faz mais sentido aprender e usar um sistema de gerenciamento de configurações, pois o conhecimento pode ser usado para todas as configurações no / etc, não apenas no systemd.
guettli

Respostas:

47

Bem, assumindo que a única coisa que muda por arquivo de unidade é a remote.example.comparte, você pode usar um Serviço Instanciado .

Na systemd.unitpágina do manual:

Opcionalmente, as unidades podem ser instanciadas a partir de um arquivo de modelo em tempo de execução. Isso permite a criação de várias unidades a partir de um único arquivo de configuração. Se o systemd procurar um arquivo de configuração da unidade, ele primeiro procurará o nome da unidade literal no sistema de arquivos. Se isso não der certo e o nome da unidade contiver um caractere "@", o systemd procurará um modelo de unidade que compartilhe o mesmo nome, mas com a cadeia de instância (ou seja, a parte entre o caractere "@" e o sufixo) removida. Exemplo: se um serviço [email protected] for solicitado e nenhum arquivo com esse nome for encontrado, o systemd procurará getty @ .service e instanciará um serviço desse arquivo de configuração, se for encontrado.

Basicamente, você cria um único arquivo de unidade, que contém uma variável (geralmente %i) onde as diferenças ocorrem e, em seguida, elas são vinculadas quando você "ativa" esse serviço.

Por exemplo, eu tenho um arquivo de unidade chamado /etc/systemd/system/[email protected]que se parece com isso:

[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 eu habilitei

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

E pode interagir com

[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 você pode ver, todas as instâncias do %iarquivo de unidade são substituídas por somehost.example.com.

Porém, existem muitos outros especificadores que você pode usar em um arquivo de unidade, mas acho %ique funciona melhor em casos como este.

GregL
fonte
Uau, o systemd é ótimo.
guettli
Você não mostra como iniciar automaticamente na inicialização, incluindo quais iniciar.
Craig Hicks
Com o Systemd, a enableação é o que inicia uma unidade / serviço na inicialização.
11688 GregLog em 12/07/18
Posso ativar / desativar independentemente as instâncias?
Soumya Kanti 01/10/1918
Sim, é isso que você está fazendo quando os ativa / desativa.
GregL
15

Aqui está um exemplo de python, que era o que eu estava procurando. O @nome do arquivo no serviço permite iniciar N processos:

$ 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

Vários métodos para chamá-lo

Ativando várias contagens, por exemplo:

  • Permita 30 trabalhadores:

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

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

Certifique-se de recarregar:

sudo systemctl daemon-reload

Agora você pode iniciar / parar de várias maneiras:

  • Início 1:

    sudo systemctl start [email protected]
    
  • Iniciar vários:

    sudo systemctl start my-worker@{1..2}
    
  • Parar vários:

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

    sudo systemctl status my-worker@1
    

ATUALIZAÇÃO : para gerenciar instâncias como um serviço, você pode fazer algo assim:

/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

E agora você pode gerenciar todas as instâncias com sudo systemctl some-worker (start|restart|stop)

Aqui está um exemplo para o seu 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
fonte
@radek: Duas coisas que eu não entendo: Primeiro,% i é usado apenas na descrição do arquivo da unidade. Como o comando start sabe o que começar? Segundo, como systemctl some-worker (start|restart|stop)saber em quais instâncias trabalhar?
U. Windl
% i é a saída de @ no nome do arquivo de serviço. A segunda parte já está explicada na resposta, consulte Now you can start/stop then in various ways.
radtek 20/03
Eu acho que a resposta dele é incompleta sem os scripts envolvidos. A maioria das "mágicas" é feita dentro dos scripts que estão faltando.
U. Windl
Na verdade, eu forneci uma solução de trabalho completa aqui. A quais "scripts" você está se referindo? /path/to/my/script.py pode ser o que você quiser, um "olá mundo", se quiser. Algo que continuará funcionando até receber um sinal de morte. Observe que a pergunta não é específica para python.
radtek
Uau, ele permite que você comece múltiplos de uma vez? - mente soprada ...
rogerdpack 24/06
1

A resposta de GregL me ajudou bastante. Aqui está um exemplo de um modelo de unidade que eu usei no meu código usando o exemplo acima para um servidor de tarefas gearman. Eu criei um script de shell que me permite criar uma quantidade X de "trabalhadores" usando este modelo.

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