使用 systemd 的 Exec* 命令将命令传递给进程

使用 systemd 的 Exec* 命令将命令传递给进程

我正在通过为不同的游戏服务器设置服务来积累我的 Linux 知识(至少我正在尝试)。

目前我正在开发一个 Minecraft 服务器,该服务器将在服务器重启时自动启动。一切似乎都正常,但我认为我在停止命令上终止服务器的方式不是最好的。

这是当前的单元文件:

[Unit]
Description=Minecraft Dedicated Server
After=network.service

[Service]
User=user
Group=user_group
Type=simple
WorkingDirectory=/usr/local/bin/services/minecraft/
ExecStart=/usr/local/bin/services/minecraft/run.sh
ExecStop=/bin/kill -9 $MAINPID
RestartSec=15
Restart=on-failure

[Install]
WantedBy=multi-user.target

我读到过,仅仅使用 kill 命令无法正常终止服务器,而应该使用 minecraft-internal “stop” 命令。不幸的是,我无法弄清楚如何修改 ExecStop 命令以将内部命令发送到 minecraft 进程。

编辑:

已实施以下措施:

minecraft.service:

[Unit]
Description=Minecraft Dedicated Server
After=network.service

[Service]
User=user
Group=user_group
Type=simple
KillSignal=SIGCONT
Sockets=minecraft.socket
WorkingDirectory=/usr/local/bin/services/minecraft/
ExecStart=/bin/sh -c "java -Xms2G -Xmx4G -XX:+UseConcMarkSweepGC -jar spigot-1.14.4.jar < /run/minecraft.control"
ExecStop=/bin/sh -c "echo /stop > /run/minecraft.control"
RestartSec=15
Restart=on-failure

[Install]
WantedBy=multi-user.target

minecraft.socket:

[Unit]
BindsTo=minecraft.service

[Socket]
ListenFIFO=/run/minecraft.control
RemoveOnStop=true
sockeSocketMode=0664
SocketUser=user
SocketGroup=user_group

不幸的是,通过 minecraft.control fifo 传递的命令不起作用。

我观察到以下行为:使用

echo "/help" > /run/minecraft.control 

有时在查看 minecraft.control fifo(使用 cat)时会给出输出,有时则不会。如果 fifo 中没有输出,则 minecraft.service 单元的日志会显示未知命令。输入“/help”获取帮助。尽管我已发送“/help”作为命令。此外,该设备的 ExecStop 命令

echo "/stop" > /run/minecraft.control 

也不起作用,服务器会被 sigkill 信号杀死。

知道为什么这不起作用吗?

答案1

添加一个新的 minecraft.socket 文件(假设您的服务名为 minecraft.service)以将您的服务器的输入绑定到:

[单元]
绑定到=minecraft.service

[插座]
ListenFIFO=/run/minecraft.control
FileDescriptorName=control
RemoveOnStop=true
套接字模式=0660
SocketUser=用户
套接字组=用户组

然后修改 minecraft.service 文件以不发送 SIGTERM,通过使用 exec 包装器修改 ExecStart 将标准输入绑定到套接字。然后 ExecStop 将简单地写入新套接字以将“/stop\n”发送到输入。

[服务]
...
KillSignal=SIGCONT
套接字=minecraft.socket
ExecStart=/bin/sh -c "exec /usr/local/bin/services/minecraft/run.sh </run/test.control"
ExecStop=/bin/sh -c "echo /stop >/run/minecraft.control"

另外,您可以echo "/command" > /run/minecraft.control随时向服务器发送命令。

您不必担心向 .service 文件添加依赖项,它会由 Sockets= 选项自动添加,BindsTo= 选项将负责在服务停止时停止套接字并清理 FIFO 文件。


以下是根据原作者的建议做出的一些澄清。

为什么我们必须使用 KillSignal=SIGCONT?

这可防止向服务器进程发送 SIGTERM 并导致进程过早停止。除非您添加更多参数(man systemd.kill),否则它仍会在一定时间后发送 SIGKILL。

Sockets=xxx 包含您上面创建的 Socket 的名称,对吗?

是的

套接字文件(在本例中为 minecraft.socket?)必须放在与服务相同的目录中吗?

是的,如果由系统管理员添加,通常是 /etc/systemd/system/。

相关内容