Systemd убивает сервис сразу после запуска

14

Я пишу файл системного модуля для OSSEC HIDS. Проблема в том, что когда systemd запускает сервис, он немедленно останавливает их.

Когда я использую эту директиву ExecStart, все работает нормально.

ExecStart=/var/ossec/bin/ossec-control start

Но когда я делаю небольшое улучшение, я замечаю в журналах OSSEC, что он получает SIG 15 после запуска.

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'

Если я сделаю еще одно небольшое изменение, сервис получит SIG 15 через 20 секунд.

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'

Итак, я думаю, что systemd убивает процесс / bin / sh после запуска службы, а bin / sh затем убивает OSSEC.

Как я могу решить эту проблему?

Даниил Светлов
источник
1
Какой тип услуги?
Виланд
@Wieland, я пробовал просто и разветвленно, но результат все тот же.
Даниил Светлов

Ответы:

36

несоответствие протокола готовности

Как и предполагал Виланд, Typeуслуги важны. Этот параметр обозначает, какой протокол готовности systemd ожидает, что служба будет говорить. Предполагается, что simpleуслуга немедленно готова. forkingСлужба берется , чтобы быть готовым после его первоначальный процесс разветвляется ребенка , а затем завершает свою работу. dbusСлужба берется , чтобы быть готовым , когда на Desktop Bus появляется сервер. И так далее.

Если вы не получите протокол готовности, объявленный в сервисном модуле, чтобы он соответствовал тому, что делает сервис, тогда все пошло не так. Несоответствия протокола готовности приводят к тому, что службы запускаются некорректно или (чаще) диагностируются (ошибочно) системой systemd как сбой. Когда служба считается не способной запустить systemd, она гарантирует, что каждый потерянный дополнительный процесс службы, который мог остаться запущенным как часть сбоя (с его точки зрения), завершается, чтобы надлежащим образом вернуть службу в неактивное состояние. государство.

Вы делаете именно это.

Прежде всего, простые вещи: sh -cне соответствует Type=simpleили Type=forking.

В simpleпротоколе, начальный процесс берется быть процесс обслуживания. Но на самом деле sh -cоболочка запускает реальную сервисную программу как дочерний процесс . Так что MAINPIDпойдет не так и ExecReloadперестает работать, для начала. При использовании Type=simpleнужно либо использовать, sh -c 'exec …'либо не использовать sh -c в первую очередь. Последнее чаще является правильным курсом, чем думают некоторые.

sh -cне соответствует Type=forkingни. Протокол готовности к forkingуслуге довольно специфичен. Начальный процесс должен разветвить ребенка, а затем выйти. systemd применяет тайм-аут к этому протоколу. Если начальный процесс не разветвляется в течение выделенного времени, это не готовность к готовности. Если начальный процесс не завершается в течение отведенного времени, это тоже сбой.

ненужный ужас, который ossec-control

Что приводит нас к сложным вещам: этот ossec-controlсценарий.

Оказывается , это rcсценарий System 5, который запускает от 4 до 10 процессов, которые, в свою очередь, тоже разветвляются и выходят. Это один из тех rcсценариев System 5, который пытается управлять целым набором серверных процессов в одном сценарии с forциклами, состояниями гонки, произвольными значениями, sleepчтобы попытаться их избежать, режимами сбоев, которые могут задушить систему в начальном состоянии, и все остальные ужасы, которые заставили людей изобретать такие вещи, как AIX System Resource Controller и daemontools два десятилетия назад. И давайте не будем забывать скрытый сценарий оболочки в двоичном каталоге, который он переписывает на лету, для реализации уникальных enableи disableглаголов.

Итак, когда вы, /bin/sh -c '/var/ossec/bin/ossec-control start'что происходит, это:

  1. systemd разветвляет процесс обслуживания.
  2. Это оболочка, которая разветвляется ossec-control.
  3. Это в свою очередь раздваивает от 4 до 10 внуков.
  4. Внуки все разветвляются и выходят по очереди.
  5. Все правнуки разветвляются и выходят параллельно.
  6. ossec-control выходы.
  7. Первая оболочка выходит.
  8. Процессы обслуживания были большие-пра внуков, а потому , что этот путь рабочих матчей ни forking ниsimple протокол готовности, Systemd не считает службу в целом, не удалось , и закрывает его обратно вниз.

Ничто из этого ужаса на самом деле не нужно в systemd вообще. Ничего из этого.

системный сервисный шаблон

Вместо этого пишется очень простой шаблонный блок :

[Единица измерения]
Описание = Сервер OSSEC HIDS% i
После того, как = network.target 

[Обслуживание]
Тип = простой
ExecStartPre = / usr / bin / env / var / ossec / bin /% p-% i -t
ExecStart = / usr / bin / env / var / ossec / bin /% p-% i -f

[Установить]
WantedBy = multi-user.target

Сохраните это как /etc/systemd/system/ossec@.service.

Различные реальные сервисы являются экземплярами этого шаблона и называются:

  • ossec@dbd.service
  • ossec@agentlessd.service
  • ossec@csyslogd.service
  • ossec@execd.service
  • ossec@agentd.service
  • ossec@logcollector.service
  • ossec@syscheckd.service
  • ossec@maild.service
  • ossec@analysisd.service
  • ossec@remoted.service
  • ossec@monitord.service

Затем функция включения и выключения поступает прямо из системы управления службамиисправленной ошибкой RedHat 752774 ), без необходимости скрытых сценариев оболочки.

 systemctl включить ossec @ dbd ossec @ agentlessd ossec @ csyslogd ossec @ maild ossec @ execd ossec @ analysisd ossec @ logcollector ossec @ удаленный ossec @ syscheckd ossec @ monitord

Кроме того, systemd узнает и отслеживает каждую реальную службу напрямую. Он может фильтровать их журналы с journalctl -u. Он может знать, когда произошел сбой отдельной службы. Он знает, какие службы должны быть включены и запущены.

Кстати, Type=simpleи -fвариант здесь, как и во многих других случаях. Очень немногие службы в дикой природе фактически сигнализируют о своей готовности посредством exit, и это тоже не такие случаи. Но это то, что forkingозначает тип. Службы в дикой природе в основном просто разветвляются и выходят из-за ошибочно полученного мудрого представления о том, что именно этим и должны заниматься демоны. На самом деле это не так. Это не было с 1990-х годов. Пришло время наверстать упущенное.

дальнейшее чтение

JdeBP
источник
2
Очень подробный ответ! Я бы также предложил создать «группирующую» цель, скажем, ossec.target, которая будет содержать Requires=все необходимые экземпляры, а затем установить PartOf=ossec.targetв ossec @ .service. Это позволит запустить и остановить ossec, запустив и остановив ossec.target.
intelfx
@JdeBP, вау! Большое спасибо за такой подробный ответ. Надеюсь, я сделаю этот блок и напишу здесь о результатах. Я был тем, что мне будет легче. Но вы правы, ossec-контроль - это адский ад.
Даниил Светлов
1
В чем причина использования / usr / bin / env в качестве оболочки?
Мариус Гедминас
1

Оставьте Type = разветвление и укажите местоположение файла pid, если служба запуска / приложение поддерживает какой-либо pid.

[Модуль]
Описание = «Запуск приложения при загрузке»
После = network.target syslog.target auditd.service

[Служба]
Тип = разветвление
PIDFile = / var / run / apache2 / apache2.pid
ExecStart = / etc / init.d / apache2 start
ExecStop = / etc / init.d / apache2 stop
StandardOutput = syslog
StandardError = syslog
Перезапуск = при
ошибке SyslogIdentifier = webappslog

[Установить]
WantedBy = multi-user.target
Alias ​​= webapps

Раушан
источник
0

В некотором роде у меня был сервис systemd, который, как оказалось, systemd «убьет» его через 30 секунд.

systemctl status service-nameбудет показывать main process exited, code=exited, status=1/FAILUREпосле 30-х годов прошло.

Он будет работать нормально "в изоляции" (как вручную в терминале с той же средой ).

Оказывается, это было

Type=forking
...
Environment=ABC="TRUE"
ExecStart=/path/to/my_script_to_spawn_process.sh

внутри my_script_to_spawn_process.shэто делало

/bin/something > /dev/null 2>&1 &

который работает, но отбрасывает информацию журнала вывода (обычно это идет в файл, или, если нет, возможно journalctl).

Изменение его для входа в другое место, как /bin/something > /tmp/my_file

затем выслеживая /tmp/my_fileвыявленную фактическую причину. Это было (по существу) то, что вы не можете использовать синтаксис, который вы можете использовать Environment=ABC="true"в bash, это не должно быть кавычек или значения ключа в кавычках, как Environment="ABC=true"это было причиной того, что мой процесс завершил работу «в фазе установки» примерно через 30 секунд.

rogerdpack
источник
-4

Обратите внимание, что модель демона systemd является упрощенной и несовместимой со многими существующими демонами, которые выполняют множественное разветвление, выполнение и установку. Наиболее распространенными являются демоны, которые запускаются с правами root для настройки, а затем переключаются на менее привилегированный UID для обычной работы. Например, инициализация PID-файла - это то, что не работает в systemd из-за проблем с привилегиями. Есть обходные пути (не исправления), но они плохо документированы.

Объяснение JdeBP приветствуется, но неполно, и его утверждение о том, что во всем виноват ossec-контроль, просто не соответствует действительности. Даже довольно тривиальные вещи проблематичны, например, получение не усеченных строк журнала для отладки проблем или значимых сообщений об ошибках от самой systemd, когда он убивает процессы.

Джон
источник
1
В любом случае, для чего нужны PID-файлы? Если он существует для данной услуги, может существовать или не существовать фактический процесс с этим PID, а когда процесс с правильным PID существует, он может быть или не быть ожидаемой услугой.
JoostM