Определение псевдонима команды похоже на это:
MyAlias = /absolute/path/to/script /absolute/path/to/folder -a option\='value', \
/absolute/path/to/script /absolute/path/to/folder -a option\='othervalue'
Отметьте обратную косую черту перед =
знак: необходимо выйти из символов, которые имеют особое значение (,:=\
). Обратная косая черта в конце первой строки означает, что определение псевдонима продолжает следующую строку.
Отметьте это ./script
и path/to/folder
должны быть полные пути. Вы не можете знать то, чем будет текущий каталог, когда кто-то вызовет sudo
.
Как подразумевал Виланд, важен Тип
службы. Этот параметр указывает, какой протокол готовности systemd ожидает от службы. Предполагается, что простой
сервис будет готов немедленно. Служба forking
считается готовой после того, как ее начальный процесс вызовет дочерний, а затем выйдет из него. Служба dbus
считается готовой, когда сервер появляется на шине Desktop Bus. И так далее.
Если протокол готовности, объявленный в единице службы, не соответствует тому, что делает служба, то все пойдет не так. Несоответствие протокола готовности приводит к тому, что службы не запускаются правильно или (чаще всего) неправильно диагностируются systemd как неработающие. Когда считается, что служба не запускается, systemd гарантирует, что каждый осиротевший дополнительный процесс службы, который мог остаться запущенным как часть сбоя (с его точки зрения), будет убит, чтобы вернуть службу в неактивное состояние.
Вы делаете именно это.
Прежде всего, простые вещи: sh -c
не соответствует Type=simple
или Type=forking
.
В протоколе simple
начальный процесс принимается за be процесс обслуживания. Но на самом деле обертка sh -c
запускает фактическую служебную программу как дочерний процесс. Поэтому MAINPID
идет неправильно, а ExecReload
перестает работать, для начала. При использовании Type=simple
нужно либо использовать sh -c 'exec ...'
, либо не использовать sh -c
вообще. Последний вариант чаще всего оказывается правильным, чем некоторые думают.
sh -c
также не соответствует Type=forking
. Протокол готовности для forking
сервиса довольно специфичен. Начальный процесс должен форкнуть дочерний, а затем выйти. systemd применяет таймаут к этому протоколу. Если начальный процесс не выполнит форкинг в течение отведенного времени, это будет означать, что он не готов. Если начальный процесс не завершается в течение отведенного времени, это тоже считается неудачей.
ossec-control
Что приводит нас к сложным вещам: этому ossec-control
скрипту.
Оказывается, это скрипт System 5 rc
, который форкает от 4 до 10 процессов, которые в свою очередь тоже форкаются и выходят. Это один из тех скриптов System 5 rc
, который пытается управлять целым набором серверных процессов в одном скрипте, с for
циклами, условиями гонки, произвольными sleep
s, чтобы попытаться избежать их, режимами отказа, которые могут задушить систему в полузапущенном состоянии, и всеми другими ужасами, которые заставили людей изобрести такие вещи, как AIX System Resource Controller и daemontools два десятилетия назад. И давайте не будем забывать о скрытом сценарии оболочки в двоичном каталоге, который он переписывает на лету, чтобы реализовать идиосинкразические включить
и отключить
глаголы.
Поэтому, когда вы /bin/sh -c '/var/ossec/bin/ossec-control start'
, происходит следующее:
ossec-control
. ossec-control
exits. форкингу
, ни протоколу простой
готовности, systemd считает, что сервис в целом потерпел неудачу, и отключает его обратно. Ничего из этого ужаса на самом деле не нужно в systemd вообще. Ничего из этого.
Вместо этого можно написать очень простой шаблонный блок:
[Unit] Description=The OSSEC HIDS %i server After=network.target [Service] Type=simple ExecStartPre=/usr/bin/env /var/ossec/bin/%p-%i -t ExecStart=/usr/bin/env /var/ossec/bin/%p-%i -f [Install] 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 enable ossec@dbd ossec@agentlessd ossec@csyslogd ossec@maild ossec@execd ossec@analysisd ossec@logcollector ossec@remoted ossec@syscheckd ossec@monitord
Более того, systemd получает информацию о каждой реальной службе и отслеживает ее непосредственно. Она может фильтровать их журналы с помощью journalctl -u
. Он может знать, когда отдельная служба потерпела неудачу. Он знает, какие службы должны быть включены и запущены.
Кстати: Type=simple
и опция -f
здесь так же уместны, как и во многих других случаях. Очень немногие сервисы в природе действительно сигнализируют о своей готовности посредством выхода
, и эти случаи тоже не являются таковыми. Но именно это и означает тип forking
. Сервисы в природе в основном просто форкают и выходят из-за какого-то ошибочного представления о том, что именно так должны поступать деймоны. На самом деле, это не так. Это не так с 1990-х годов. Пришло время наверстать упущенное.
Обратите внимание, что модель демона systemd упрощена и несовместима со многими существующими демонами, которые выполняют множественное форкование, выполнение и установку. Наиболее распространены демоны, которые запускаются как root для настройки, а затем переключаются на менее привилегированный UID для рутинной работы. например Инициализация файла Pid - это то, что не удается под systemd из-за проблем с привилегиями. Есть обходные пути (не исправления), но они плохо документированы.
Объяснение JdeBP можно только приветствовать, но оно неполное, и его заявление о том, что во всем виноват ossec-control, просто не соответствует действительности. Проблематичны даже самые тривиальные вещи, например получение неусеченных строк журнала для отладки проблем или значимых сообщений об ошибках от самого systemd, когда он убивает процессы.
Оставьте Type=forking
и укажите местоположение файла PID, если стартовая служба/приложение поддерживает какой-либо pid.
[Unit]
Description="Run app on boot"
After=network.target syslog.target auditd.service
[Service]
Type=forking
PIDFile=/var/run/apache2/apache2.pid
ExecStart=/etc/init.d/apache2 start
ExecStop=/etc/init.d/apache2 stop
StandardOutput=syslog
StandardError=syslog
Restart=on-failure
SyslogIdentifier=webappslog
[Install]
WantedBy=multi-user.target
Alias=webapps
В некотором роде, у меня был сервис 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 с.