Запустить N процессов одним файлом службы systemd

36

Я нашел этот файл службы systemd, чтобы запустить autossh для поддержки 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

Есть ли способ настроить systemd для запуска нескольких туннелей в одном сервисе.

Я не хочу создавать N системных служебных файлов, так как я хочу избежать копирования + вставки.

Все служебные файлы будут идентичны, кроме «remote.example.com» будет заменено другими именами хостов.

1,5 года спустя ...

Я задал этот вопрос примерно 1,5 года назад.

Мое мнение немного изменилось. Да, хорошо, что вы можете сделать это с помощью systemd (я все еще использую его), но я буду использовать управление конфигурацией в будущем.

Почему systemd должен реализовывать язык шаблонов и заменять% h?

Несколько месяцев спустя я думаю, что этот цикл и шаблоны должны быть решены с помощью инструмента, который автоматизирует настройку. Сейчас я использую один инструмент из этого списка в Википедии .

guettli
источник
Другими словами, вы говорите использовать систему управления конфигурацией для создания нескольких практически идентичных служебных файлов для выполнения этой задачи? Хм, может быть. Как и в большинстве подобных вопросов, нет четкой разделительной линии, разделяющей их.
pgoetz
Управление конфигурацией @pgoetz для меня все еще ново, но оно имеет преимущество, если вы посмотрите на тему этого вопроса: если вы посмотрите на результат управления конфигурацией, то все, кто знает служебные файлы systemd, поймут это: простые и простые служебные файлы , Я думаю, что имеет больше смысла изучать и использовать систему управления конфигурациями, поскольку знания могут использоваться для всех конфигураций в / etc, а не только для systemd.
Геттли

Ответы:

47

Что ж, если предположить, что единственное, что изменяется для каждого файла модуля, это remote.example.comдеталь, вы можете использовать Instantiated Service .

Со systemd.unitстраницы руководства :

Необязательно, единицы могут быть созданы из файла шаблона во время выполнения. Это позволяет создавать несколько устройств из одного файла конфигурации. Если systemd ищет файл конфигурации модуля, он сначала ищет буквальное имя модуля в файловой системе. Если это не приводит к успеху, а имя модуля содержит символ «@», systemd будет искать шаблон модуля, который имеет то же имя, но со строкой экземпляра (т. Е. Часть между символом «@» и суффиксом) удалена. Пример: если запрашивается служба getty@tty3.service и файл с таким именем не найден, systemd будет искать getty @ .service и создавать экземпляр службы из этого файла конфигурации, если он найден.

По сути, вы создаете отдельный файл модуля, который содержит переменную (обычно %i), где возникают различия, а затем они связываются, когда вы «включаете» эту службу.

Например, у меня есть файл модуля, /etc/systemd/system/autossh@.serviceкоторый выглядит так:

[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

Который я тогда включил

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

И может взаимодействовать с

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

Как видите, все экземпляры %iв файле модуля заменяются на somehost.example.com.

Хотя есть еще несколько спецификаторов, которые вы можете использовать в модульном файле, но я считаю, %iчто лучше всего работать в подобных случаях.

GregL
источник
Вау, systemd отлично.
Геттли
Вы не показываете, как автоматически запускаться при загрузке, в том числе какие из них запускать.
Крейг Хикс
С Systemd enableдействие - это то, что заставляет юнит / сервис запускаться при загрузке.
Грегл
Могу ли я самостоятельно включить / отключить экземпляры?
Soumya Kanti
Да, это то, что вы делаете, когда вы включаете / отключаете их.
Грегл
15

Вот пример Python, который я искал. Имя @файла в сервисе позволяет запустить N процессов:

$ 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

Различные методы, чтобы назвать это

Включение различных подсчетов, например:

  • Включить 30 работников:

    sudo systemctl enable my-worker\@{1..30}.service
    
  • Включить 2 рабочих:

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

Тогда обязательно перезагрузите:

sudo systemctl daemon-reload

Теперь вы можете запустить / остановить затем различными способами:

  • Начало 1:

    sudo systemctl start my-worker@2.service
    
  • Начать несколько:

    sudo systemctl start my-worker@{1..2}
    
  • Остановить несколько:

    sudo systemctl stop my-worker@{1..2}
    
  • Проверить состояние:

    sudo systemctl status my-worker@1
    

ОБНОВЛЕНИЕ : Чтобы управлять экземплярами как одним сервисом, вы можете сделать что-то вроде этого:

/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

И теперь вы можете управлять всеми экземплярами с sudo systemctl some-worker (start|restart|stop)

Вот несколько шаблонов для вашего 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
источник
@radek: две вещи, которые я не понимаю: во-первых,% i используется только в описании файла модуля. Как команда start знает, с чего начать? Во-вторых, как systemctl some-worker (start|restart|stop)узнать, над какими экземплярами работать?
У. Уиндл
% i является выводом @ в имени служебного файла. Вторая часть уже объяснена в ответе, см Now you can start/stop then in various ways.
Радтек
Я думаю, что его ответ неполон без участия сценариев. Большая часть "магии" делается внутри отсутствующих скриптов.
У. Уиндл
Я предоставил полное рабочее решение здесь на самом деле. Какие "сценарии" вы имеете в виду? /path/to/my/script.py может быть любым, что вы хотите, "привет мир", если хотите. Что-то, что будет работать до тех пор, пока не получит сигнал уничтожения. Обратите внимание, что вопрос не относится к Python.
Радтек
Вау, это позволяет вам начинать несколько магазинов одновременно?
сумасшедший
1

Ответ Грегла мне очень помог. Вот пример шаблона модуля, который я использовал в своем коде на примере выше для сервера заданий Gearman. Я сделал сценарий оболочки, который позволяет мне создавать X «рабочих», используя этот шаблон.

[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
Кайл Андерсон
источник