Системный и процессный нерест

14

Обычно не пишите здесь, но я вырываю свои волосы из-за этого. У меня есть скрипт Python, который разветвляется при запуске и отвечает за запуск нескольких других процессов. Этот скрипт запускался при запуске через sysvinit, но недавно я обновился до Debian Jessie, поэтому адаптировал его для запуска через systemd.

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

Когда запускается через systemd, если родительский процесс завершается, все дети тоже выходят (ну, экраны, которые они запускают в die и выглядят как Dead ???)

В идеале мне нужно иметь возможность перезапустить родительский скрипт, не убивая все дочерние процессы, есть что-то, чего мне не хватает?

Благодарность!

[Unit]
Description=Server commander
After=network.target

[Service]
User=serveruser
Type=forking
PIDFile=/var/Server/Server.pid

ExecStart=/var/Server/Server.py
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

Редактировать: Вероятно, для меня важно указать, что скрипт Python по сути является «контроллером» для своих дочерних процессов. Запускает и останавливает серверы на экранах GNU в соответствии с запросом от центрального сервера. Обычно он всегда работает, он не порождает сервисы и не завершает работу. Однако есть случаи, когда я хотел бы иметь возможность перезагрузить скрипт, не убивая дочерние процессы, даже если это означает, что процессы теряют связь с pid 1. На самом деле, даже не имеет значения, если скрипт Python запускает процессы как родительский процесс, если это вообще возможно.

Лучшее объяснение того, как это работает:

  • Systemd порождает /Server.py
  • Server.py разветвляется и записывает pid-файл для Systemd
  • Затем Server.py порождает процессы сервера в окне GNU в соответствии с его инструкциями
  • Server.py продолжает работать, чтобы выполнить любые перезапуски, запрошенные с сервера

При запуске без Systemd Server.py может быть перезапущен, и экраны gnu, которые он запускает, не затрагиваются. При запуске с Systemd, когда Server.py завершает работу, вместо тех экранных процессов, которые отключены от pid 1, они уничтожаются.

Bottswana
источник
1
Трудно найти решение, не имея Server.pyкода и описания того, как запускаются запущенные сервисы (если они работают). Однако, вообще говоря, это проблема несоответствия протокола готовности .
intelfx
Кстати, ExecStop=это не нужно. Действие systemd по умолчанию при остановке - уничтожение процессов. Вы можете взглянуть на документацию для KillMode=директивы.
intelfx
1
И, наконец ... Если нет подходящего протокола готовности (один из simpleили forking, собственно), последним средством будет Type=oneshot, RemainAfterExit=yesи KillMode=control-group.
intelfx
@intelfx По сути, скрипт Python запускает сервер на экране, используя Subprocess.call. Это сложнее, потому что скрипт получает команды из других мест, сообщая ему, какие экраны запускать, а какие нет. Доступные экраны также являются динамическими, поэтому они не могут быть системными сервисами сами по себе. В идеале я не хочу, чтобы systemd вообще рассматривал эти экраны как часть службы, но в настоящее время они сбрасываются в одну и ту же группу процессов и умирают вместе с мастером, если его перезапустить.
Ботсвана
Я догадываюсь, что systemd не «обрабатывает» такой процесс управления (он просто просматривает PID во время запуска, не распознает более поздние ...): |
rogerdpack

Ответы:

9

Мне удалось это исправить, просто установив KillMode для обработки вместо control-group (по умолчанию). Спасибо всем

Bottswana
источник
Это кажется чем-то вроде работы вокруг, а не исправления, посмотрите другие ответы ... если вы сделаете это и сделаете «systemctl stop», то это не убьет дочерние процессы, которые они все еще будут запускать [?] вне контроля systemctl?
rogerdpack
5

У меня есть скрипт Python, который разветвляется при запуске и отвечает за запуск нескольких других процессов.

Что указывает на то, что вы делаете это неправильно. Подробнее об этом через минуту.

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

Это не правильное поведение демона. Если «основной» процесс - в данном случае дочерний элемент, который вы разветвили, поскольку вы указали это Type=forking- завершается, systemd считает, что служба деактивирована, и завершает любые другие все еще работающие процессы (в контрольной группе), чтобы привести в порядок ,

Иногда преобразование из rcсценариев System 5 в systemd не является простым, потому что правильный подход к работе под systemd совсем другой. Правильный способ сделать (скажем) OpenVPN или OpenStack или OSSEC HIDS в Systemd не то же самое , как можно было бы сделать это с помощью rcсценария. Тот факт, что у вас есть скрипт, который разветвляется, затем порождает целую нагрузку процессов внуков, а затем ожидает, что эти внуки продолжат работать, указывает на то, что вы совершаете тот же ужас, что и ossec-control, хотя и с двумя уровнями разветвления. Если вы обнаружите, что пишете «главный» сценарий, который проверяет флаги «enable» и запускает дочерние процессы для «включенных» частей вашей системы, то вы совершаете ту же ошибку, что и ужасные ossec-control.

С systemd такие доморощенные механизмы не нужны. Это уже менеджер сервиса. Согласно /unix//a/200365/5132 , правильный способ сделать это в systemd - это не иметь один сервис, который порождает какую-то дурацкую и запутанную попытку иметь «подуслуги». Это означает, что каждый дочерний процесс является полноценной системной службой по отдельности. Затем один включает и отключает, а также запускает и останавливает различные части системы, используя обычные средства управления systemd. Как вы можете видеть в случае OSSEC HIDS, простой шаблонный сервисный блок покрывает почти все (одно исключение на /ubuntu//a/624871/43344 ) сервисы, позволяя делать такие вещи, как systemctl enable ossec@agentlessd.serviceвключение дополнительногоagentlessdсервис, без какой-либо необходимости в ужасающем механизме «главного сценария», который был необходим в System 5 rc.

Есть много случаев, возможно, не таких экстремальных, как OSSEC HIDS, где такое переосмысление необходимо. МТС, такие как exim и sendmail, два таких. Можно было бы иметь один rcсценарий, который порождает обработчик очереди, демон отправки SMTP и демон ретрансляции SMTP, с кучей специальных переменных оболочки в файле конфигурации, чтобы точно контролировать, какие из них запускаются. Но правильный способ сделать это с помощью systemd - это иметь три надлежащих сервисных модуля (два из которых имеют связанные сокетные блоки ) и никаких специальных вещей вообще, только обычные механизмы менеджера сервисов.

JdeBP
источник
Я ценю отзывы об этом. Хотя я согласен, что использование подмножеств сервисов имеет смысл, это было сделано в Python по причине, в которую я не могу вдаваться. Мое единственное решение - найти способ заставить этот метод работать. Спасибо хоть. Я хотел бы сделать это правильно.
Ботсвана
Субсервисы, которые запускает скрипт, - это просто серверы, работающие на экране gnu от имени конкретного пользователя. Эти серверы сильно меняются, некоторые добавляются, некоторые удаляются, и это контролируется в другом месте, поэтому они не могут быть реальными сервисами в systemd, потому что это увеличивает сложность и не может управляться централизованно. Также тот же сценарий также используется на серверах не systemd.
Ботсвана
В systemd есть явные средства, позволяющие добавлять и удалять службы без необходимости root-доступа. «Также используемый в несистемных сервисах» - это единственный аргумент, приведенный выше, который не может быть исправлен путем добавления большего количества systemd ... ну, возможно, даже тот, который может быть тоже. :)
Чарльз Даффи
0

Вы можете просто спать с родителем и ждать, пока systemd убьет его во время остановки.

Крейг Хикс
источник