Як створити віртуальну системну службу для зупинки / запуску кількох примірників разом?


12

Я планую розмістити кілька примірників одного веб-додатку для користувачів, які користуються systemd. Я хотів би мати можливість stopі startкожен екземпляр клієнта з використанням systemd, а також обробляти всю колекцію примірників клієнтів в якості однієї служби , які можуть бути зупинені і почали разом.

systemdначебто надає потрібні мені будівельні блоки PartOfта файли одиничних шаблонів, але я перестав зупиняти батьківську службу, дочірнє обслуговування клієнтів не припиняється. Як я можу зробити цю роботу з systemd? Ось що я маю досі.

Файл батьківського блоку app.service:

[Unit]
Description=App Web Service

[Service]
# Don't run as a deamon (because we've got nothing to do directly)
Type=oneshot
# Just print something, because ExecStart is required
ExecStart=/bin/echo "App Service exists only to collectively start and stop App instances"
# Keep running after Exit start finished, because we want the instances that depend on this to keep running
RemainAfterExit=yes
StandardOutput=journal

Файл шаблону з іменем app@.service, який використовується для створення екземплярів клієнта:

[Unit]
Description=%I Instance of App Web Service

[Service]
PartOf=app.service
ExecStart=/home/mark/bin/app-poc.sh %i
StandardOutput=journal

Мій app-poc.shсценарій (Доказ концепції, яка щойно друкує файл журналу в циклі):

#!/bin/bash
# Just a temporary code to fake a full daemon.
while :
do
  echo "The App PoC loop for $@"
  sleep 2;
done

Для підтвердження концепції, я маю файли системного блоку ~/.config/systemd/user.

Потім запускаю батьківський і екземпляр на основі шаблону (після systemctl --user daemon-reload):

systemctl --user start app
systemctl --user start app@customer.service

З використання journalctl -fя можу побачити, що і почалося, і що екземпляр клієнта продовжує працювати. Тепер я очікую, що відключення батька зупинить дитину (тому що я звикла PartOf), але це не так. Крім того, запуск батька не починає дитину, як очікувалося.

systemctl --user stop app

Спасибі!

(Я використовую Ubuntu 16.04 з systemd 229).


1
"PartOf = Конфігурує залежності, схожі на Requires =, але обмежується зупинкою та перезапуском одиниць." Якщо ви хочете почати працювати, вам не потрібно використовувати Requires=замість цього?
sourcejedi

Відповіді:


10

Вам потрібно перемістити лінію

PartOf=app.service

з [Service]і в [Unit]розділі, і додати до [Unit]з app.serviceсписку клієнтів , щоб почати, наприклад ,

Wants=app@customer1.service app@customer2.service

або як сказали джерела в коментарях, Requires=те саме. Ви можете зберігати PartOfпослуги, які ви починаєте вручну, як це не вказано у наведеному вище списку systemctl --user start app@customer3.service.


Я підтвердив, що ви мали рацію PartOf. Спасибі. Я збираюся обробляти "Хоче" через симпосилання, що стає єдиною дією, яку мені потрібно вжити, щоб активувати нового клієнта з системою. Для мого тестового випадку: `ln -s /home/mark/.config/systemd/user/app@.service / home / mark / .config / systemd / user / app.service.wants / Единство @ foo.service`
Марк Стосберг

14

Я дізнався, що це те, для чого системні "Цільові одиниці". Використовуючи цільову одиницю, я отримую потрібні переваги, не потребуючи створення фальшивого [Service]розділу, який я мав вище. Робочий приклад файлу "Цільова одиниця" виглядає так:

# named like app.target
[Unit]
Description=App Web Service

# This collection of apps should be started at boot time.
[Install]
WantedBy=multi-user.target

Потім кожен екземпляр клієнта повинен включати PartOfв [Unit]розділ (як зазначив @meuh), а також повинні мати [Install]розділ так , що enableі disableбуде працювати на конкретній послуги:

# In a file name like app@.service
[Unit]
Description=%I Instance of App Web Service
PartOf=app.target

[Service]
ExecStart=/home/mark/bin/app-poc.sh %i
Restart=on-failure
StandardOutput=journal

# When the service runs globally, make it run as a particular user for added security
#User=myapp
#Group=myapp

# When systemctl enable is used, make this start when the App service starts
[Install]
WantedBy=app.target

Щоб вивести екземпляр клієнта і запустити його при запуску цілі, використовується ця команда одноразового включення:

 systemctl enable app

Тепер я можу використовувати stopі startввімкнути app@customerдля конкретного примірника, або можу використовувати start appта stop appзупиняти всі програми разом.


Як щодо статусу? Я не можу знайти простий спосіб отримати статус усіх служб, які хотів додаток. Я знаю, як я можу це сценарій, але ...
Tommi Kyntola

1
Я маю на увазі, як отримати статус додатків у цій цільовій групі, не перераховуючи все, що входить до неї, підказки чи ні, бажано, використовуючи назву цієї групи і навіть не піклуючись про те, з чого вони створені.
Томмі Кінтола

2
Це не так просто. До якого пакету належав би цей скрипт? Його потрібно було б змінювати щоразу, коли додається новий компонент. Забудьте про те, що розгортання / технічне обслуговування перебуває в усьому світі. Я, очевидно, хотів би - просто додати новий пакет з налаштуваннями partOf, що вказує на його присутність у цій групі, а не змінювати деякі сценарії, що затримуються. А потім зупинити і почати, що ціль працює як раніше. Це працює, але статус, схоже, випадає з цієї межі. Я навіть не можу знайти перелік одиниць, які виконуються в цілі. Цей випадок використання не охоплюється systemd.
Томмі Кінтола

2
@TommiKyntola Ось башмайн-лайн, який не потрібно оновлювати, оскільки цільові залежності змінюються:systemctl status $(systemctl list-dependencies --plain otp.target)
Марк Стосберг

2
@TommiKyntola Я згоден, що це systemdможе покращити зручність використання тут. Я відкрив запит на функцію, щоб запропонувати покращений статус для цілей.
Марк Стосберг
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.