![systemd 调用 bash 脚本在守护进程之前创建符号链接](https://linux22.com/image/143358/systemd%20%E8%B0%83%E7%94%A8%20bash%20%E8%84%9A%E6%9C%AC%E5%9C%A8%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B%E4%B9%8B%E5%89%8D%E5%88%9B%E5%BB%BA%E7%AC%A6%E5%8F%B7%E9%93%BE%E6%8E%A5.png)
在 systemd 执行守护进程之前,我需要创建或更改符号链接的目标。守护进程将其标准输出重定向到此符号链接,并随之重定向到每个启动的守护进程的特殊文件中。这就是我们的想法。我设置了名为“test_start.service”的服务单元文件:
[Unit]
Description=Test Server
After=network-online.target test_start.socket
Requires=network-online.target test_start.socket
[Service]
User=test1
Group=test1
Type=simple
ExecStartPre=/bin/bash /etc/testServer/Debug/makeOutfile.sh
ExecStart=/etc/testServer/Debug/testServer
StandardInput=socket
StandardOutput=file:/etc/testServer/Debug/test_outLink
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
bash 脚本“/etc/testServer/Debug/makeOutfile.sh”如下所示:
#!/usr/bin/env bash
timeStamp=$(date +%y-%m-%d_%Hh%Mm%Ss)
myfolder="/etc/testServer/Debug"
# create new logfile
touch $myfolder/started_$timeStamp
# remove old symlink if exists (owned by test1)
if [ -h $myfolder/test_outLink ]; then
rm $myfolder/test_outLink
fi
# create new symlink
ln -s $myfolder/started_$timeStamp $myfolder/test_outLink
它在某些情况下起作用。如果符号链接存在并且它指向的文件也存在,那么一切都很好。 bash 脚本“makeOutfile.sh”通过终端运行以进行测试,并通过 systemd 服务启动运行。
但:
如果指向的文件(名称:“started_atSomeDate”)不存在(因为它同时被某人删除),则脚本的终端调用将按预期工作,但启动 systemd 服务将添加一个由 root 拥有的附加文件root 具有原始旧文件名:“started_atSomeDate”。
这是从哪里来的?
如果旧的符号链接“test_outLink”不存在(因为它同时被某人删除),则脚本的终端调用将按预期工作,但启动 systemd 服务会将新创建的“test_outLink”添加为 root 拥有的常规文件具有 root 组并且服务无法启动。
这里出了严重的问题,虽然 systemd 服务单元用户和组是 test1,但 root 却混在了这里。有人能解释一下吗?我究竟做错了什么?
答案1
我的建议是您应该使用 shell 脚本来设置日志文件和使用适当的重定向执行测试服务器,从而绕过StandardOutput=
不适用于您的情况的 systemd 设置。
创建一个像这样的 bash 脚本/etc/testServer/Debug/runTestServer.sh
:
#!/usr/bin/env bash
timeStamp=$(date +%y-%m-%d_%Hh%Mm%Ss)
myfolder="/etc/testServer/Debug"
# create new logfile
touch $myfolder/started_$timeStamp
# remove old symlink if exists (owned by test1)
if [ -h $myfolder/test_outLink ]; then
rm $myfolder/test_outLink
fi
# create new symlink
ln -s $myfolder/started_$timeStamp $myfolder/test_outLink
# run the actual testServer
exec /etc/testServer/Debug/testServer >/etc/testServer/Debug/test_outLink
与原始脚本的唯一区别makeOutfile.sh
是,该脚本执行时testServer
使用适当的重定向,将其标准输出发送到您刚刚设置的日志文件。
它还用于exec
确保 shell 脚本不会保留并被替换testServer
(这样 systemd 就会知道服务的主进程是什么。)
在您的单元文件中,删除ExecStartPre=
和StandardOutput=
并将其替换ExecStart=
为:
ExecStart=/etc/testServer/Debug/runTestServer.sh
(或者调用脚本/bin/bash
也是可能的,尽管只要脚本设置了可执行位就没有必要。)
通过像这样的脚本设置服务器,您甚至可以完全绕过符号链接并直接重定向到最终started_$timeStamp
日志文件。
我没有直接查看 systemd 代码,文档也不清楚它们之间的交互StandardOutput=
以及ExecStartPre=
具体的交互...但是 systemd 执行步骤的顺序肯定存在问题(以及哪个进程执行它们,这会导致不同的权限/所有权),所以我对您报告的结果并不感到太惊讶。我想,无论如何,我的建议是使用单个包装执行器脚本来简化它,所以希望这能解决您的问题。