Systemd:启动后单元文件超时

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 上仍然有一些内容,即使其中指定了一项作业?这很好奇。

答案1

这基本上只是从systemd.service 文档因为这已经足够了。

Type=

<...>

类型exec类似于simple,但服务管理器将在主服务二进制文件执行后立即启动该单元。服务管理器将延迟启动后续单元,直到该时间点。(换句话说:返回simple后立即继续执行其他作业,而服务进程中的和均成功之前不会继续执行。)请注意,这意味着fork()execfork()execve()系统控制启动exec当服务的二进制文件无法成功调用时(例如因为选定的二进制文件User=不存在,或者服务二进制文件丢失),服务的命令行将报告失败。

如果设置为forking,则预期配置为 的进程将在启动时ExecStart=调用。预期在启动完成且所有通信通道都设置好后,父进程将退出。子进程继续作为主服务进程运行,服务管理器将在父进程退出时认为该单元已启动。这是传统 UNIX 服务的行为。如果使用此设置,建议也使用选项,以便 systemd 可以可靠地识别服务的主进程。一旦父进程退出,systemd 将继续启动后续单元。fork()PIDFile=

您的进程显然不是一个分叉进程,当它由 systemd 原生支持时,您已尝试多次破解它以使其成为一个分叉进程。


PIDFile=

采用指向服务 PID 文件的路径。建议对Type=设置为 的服务使用此选项forking。指定的路径通常指向 下面的某个文件/run/。如果指定了相对路径,则应在其前面加上 前缀/run/。服务启动后,服务管理器将从此文件读取服务主进程的 PID。服务管理器不会写入此处配置的文件,但如果文件仍然存在,它会在服务关闭后将其删除。PID 文件不需要由特权用户拥有,但如果它由非特权用户拥有,则必须实施额外的安全限制:该文件不能是指向其他用户拥有的文件的符号链接(无论是直接还是间接),并且 PID 文件必须引用已经属于该服务的进程。

您正在将 systemdMAINPID变量写入该文件,但不仅MAINPID没有记录ExecStartPost=,而且更重要的是,由于PIDFile已设置,它实际上是从该文件中读取的(此时,我不太确定它扩展为什么,因为在这种情况下,它没有意义;它应该在ExecStart=返回时被读取,所以我会说它是空的)。


ExecStart=本节介绍、ExecStartPre=ExecStartPost=ExecReload=ExecStop=和选项的命令行解析以及变量和说明符替换ExecStopPost=

<...>

此语法受 shell 语法启发,但只理解以下段落中描述的元字符和扩展,变量的扩展有所不同。具体来说,重定向使用“<”、“<<”、“>”和“>>”,管道使用“|”,后台运行程序使用“&”,以及不支持 shell 语法的其他元素

您的ExecStart=ExecRestart=显然已被破坏,而且对于Type=和的默认实现来说毫无意义ExecRestart=


到目前为止,您的 bash 包装器已经毫无用处,根据其用途,您应该将其完全删除,并直接将 UT 服务器设置为参数ExecStart=。服务器命令行可以从中获取EnvironmentFile=,然后您就大功告成了!

此外,除非该服务器绝对是一场噩梦,否则使用 SIGKILL 停止任何类型的服务都是……糟糕的,至少可以这么说。的默认实现ExecStop=可能更适合。

下次编写服务脚本时,请尝试从默认脚本开始,逐步更改参数,而不是更改所有内容,然后想知道二十个参数中的哪一个坏了,这样更容易调试

相关内容