(systemd версия 229, fwiw)
У меня есть первичная служба A и вторичная служба B. Первичная служба A может работать сама по себе. Но служба B не может работать сама по себе: для нее необходимо, чтобы A работал (технически B может работать, но это то, что я хочу, чтобы systemd предотвратил). Моя цель: Если A не работает, B не должен работать. Учитывая, что A и B работают, когда A останавливается или умирает / выходит из строя, то B следует остановить.
Как мне этого добиться?
Я приближаюсь к добавлению элементов [Unit] в b.service, используя
Requisite=A.service
After=A.service
Результатом вышесказанного является то, что
1) B won't start unless A is running (good).
2) B is stopped when A is stopped (good).
3) However, if I kill A, service B continues to run (bad).
Как я могу исправить это последнее поведение №3? Я пробовал использовать BindsTo вместо Requisite, как это в служебном файле B:
BindsTo=A.service
After=A.service
и я получаю:
1) If A is not running and I start B, then A is also started
(I want an error, I don't want A started)
2) B is stopped when A is stopped (good).
3) B is stopped when A is killed (good)
Итак, теперь №3 - это хорошо, но №1 - нежелательное поведение. Ни PartOf, ни BindsTo, похоже, не помогают, но, возможно, у меня нет правильного заклинания комбинаций опций? Из справочных страниц мне не ясно, какие варианты можно комбинировать.
С BindsTo я также попытался неудачно запустить B с помощью ExecStartPre, но, конечно, это не сработало, потому что начало B уже определило, что ему нужно A для запуска (и запустило его), до того, как он запустил B.
Есть ли способ добиться поведения между Requisite и BindsTo? 1-2-3, которые я перечислил выше?
Спасибо заранее!
Я тоже ищу более элегантное решение. Здесь есть открытый тикет systemd для запроса на улучшение: https://github.com/systemd/systemd/issues/5966
В настоящее время мой обходной путь выглядит следующим образом: B.service
Requisite=A.service
After=A.service
Услуга
OnFailure=Stop-B.service
Стоп-Б.сервис
[Service]
Type=oneshot
TimeoutSec=0
ExecStart=/bin/systemctl stop B.service
Мне нужно было решить похожую ситуацию. Подход, который я придумал, предполагает создание целевого отряда как барьер между двумя службами.
услуга:
[Unit]
Wants=a.target
цель:
[Unit]
Requisite=a.service
After=a.service
PartOf=a.service
RefuseManualStart=true
RefuseManualStop=true
б. сервис:
[Unit]
BindsTo=a.target
After=a.target
Эта настройка обеспечивает поведение, желаемое OP, поскольку a.target всегда активен с a.service (PartOf останавливает a.target, когда a.service остановлен, RefuseManual * избегает команд systemctl start / stop на a.target) и b. сервис не может запустить a.service через a.target.
Я использовал тот же подход, что и Крис, но без необходимости создавать отдельную службу для остановки B:
Б. сервис:
[Unit]
Requisite=A.service
After=A.service
Услуга:
[Service]
ExecStopPost=/bin/systemctl stop B.service
В Requisite
строка в B.service гарантирует, что B.service не может быть запущен, если A.service еще не запущен, в то время как ExecStopPost
строка в A.service гарантирует, что B.service будет остановлен, когда A.service остановлен или переходит в неактивное состояние.