Назад | Перейти на главную страницу

Systemd: таймаут модульного файла после запуска

Я написал bashscript со следующим содержанием:

#!/bin/bash
cd /opt/ut_server/System
./ucc-bin-linux-amd64 server DM-Rankin?game=XGame.xDeathMatch?mutator=AntiTCC2009r6.MutAntiTCCFinal,utcompv17a.MutUTComp?AdminName=admin?AdminPassword=1111 ini=server.ini -port=1234 -log=s9.log -nohomedir &

sleep 10
echo "finish ucc"
exit 0

и теперь я хочу запустить его с юнит-файла и systemd:

[Unit]
Description=Unreal Tournament 2004 Server
After=network.target

[Service]
WorkingDirectory=/home/unreal-user/
User=unreal-user
Group=unreal-user
Type=forking
ExecStart=/home/unreal-user/start_ut_serv.sh &
ExecStartPost=/bin/bash -c "umask 022; echo $MAINPID > /home/unreal-user/ut2k4-server.pid"
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -9 $MAINPID
TimeoutSec=400
ExecRestart=/bin/kill -9 $MAINPID && /home/unreal-user/start_ut_serv.sh
PIDFile=/home/unreal-user/ut2k4-server.pid
RestartSec=30
Restart=on-failure
#Restart=always

[Install]
WantedBy=multi-user.target

Когда я запускаю служебный файл, у меня появляется такая ошибка, как:

ut2k4-serv.service: Start operation timed out. Terminating.
systemd[1]: ut2k4-serv.service: Control process exited, code=killed, status=15/TERM

Почему это время истекло? Как справиться с этой проблемой?

Когда я запускаю руководство по bashscript, также кажется, что в STDOUT все еще есть что-то из него, даже если в нем было указано задание? Это просто любопытно ..

В основном это просто копипаст из systemd.service документация поскольку этого достаточно.

Type=

<...>

В exec тип похож на simple, но диспетчер служб будет считать, что модуль запущен сразу после выполнения основного двоичного файла службы. Менеджер по обслуживанию отложит запуск последующих единиц до этого момента. (Или другими словами: simple приступает к дальнейшей работе сразу после fork() возвращается, а exec не начнется раньше обоих fork() и execve() в процессе обслуживания успешно.) Обратите внимание, что это означает systemctl start командные строки для exec службы сообщат об ошибке, если двоичный файл службы не может быть успешно запущен (например, потому что выбранный User= не существует или двоичный файл службы отсутствует).

Если установлено на forking, ожидается, что процесс, настроенный с ExecStart= позвоню fork() как часть его запуска. Ожидается, что родительский процесс завершится после завершения запуска и настройки всех каналов связи. Дочерний процесс продолжает работать как основной процесс службы, и диспетчер службы считает, что модуль запущен, когда родительский процесс завершается. Это поведение традиционных служб UNIX. Если используется этот параметр, рекомендуется также использовать PIDFile= вариант, чтобы systemd мог надежно идентифицировать основной процесс службы. systemd продолжит запуск последующих модулей, как только родительский процесс завершится.

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


PIDFile=

Указывает путь к файлу PID службы. Использование этой опции рекомендуется для сервисов, где Type= установлен на forking. Указанный путь обычно указывает на файл ниже /run/. Если указан относительный путь, он, следовательно, имеет префикс /run/. После запуска службы диспетчер служб считывает PID основного процесса службы из этого файла. Диспетчер служб не будет записывать в файл, настроенный здесь, хотя он удалит файл после завершения работы службы, если он все еще существует. Файл PID не обязательно должен принадлежать привилегированному пользователю, но если он принадлежит непривилегированному пользователю, применяются дополнительные ограничения безопасности: файл не может быть символической ссылкой на файл, принадлежащий другому пользователю (ни прямо, ни косвенно) , а файл PID должен относиться к процессу, уже принадлежащему службе.

Вы пишете systemd MAINPID переменной в этот файл, но не только MAINPID без документов для ExecStartPost= но что более важно, поскольку PIDFile установлен, он фактически считывается из этого файла (на данный момент я не слишком уверен, до чего он расширяется, поскольку в этой ситуации это не имеет смысла; его следовало прочитать, когда ExecStart= вернулся, так что я бы сказал, что он пустой).


В этом разделе описывается синтаксический анализ командной строки и замены переменных и спецификаторов для ExecStart=, ExecStartPre=, ExecStartPost=, ExecReload=, ExecStop=, и ExecStopPost= параметры.

<...>

Этот синтаксис основан на синтаксисе оболочки, но понятны только метасимволы и расширения, описанные в следующих параграфах, а раскрытие переменных отличается. В частности, перенаправление с использованием «<», «<<», «>» и «>>», каналов с использованием «|», запуск программ в фоновом режиме с использованием «&» и другие элементы синтаксиса оболочки не поддерживаются.

Ваш ExecStart= и ExecRestart= явно нарушены, а также бессмысленны в отношении Type= и реализация по умолчанию ExecRestart=.


На данный момент ваша оболочка bash бесполезна, и в зависимости от ее цели вы должны полностью удалить ее и установить сервер UT непосредственно как ExecStart= аргумент. Командная строка сервера может быть получена из EnvironmentFile= и вы сделали!

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

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