Systemd服务运行而不退出

Systemd服务运行而不退出

我为 jekyll 创建了自己的服务,当我启动该服务时,它似乎没有作为后台进程运行,因为我被迫退出ctrlc。由于--watch,它只是停留在前台。我不知道如何绕过它并使其在后台运行。有什么想法吗?

# /etc/systemd/system/jekyll-blog.service

[Unit]
Description=Start blog jekyll

[Service]
Type=forking
WorkingDirectory=/home/blog
ExecStart=/usr/local/bin/jekyll build --watch --incremental -s /home/blog -d /var/www/html/blog &
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
User=root
Group=root

[Install]
WantedBy=multi-user.target

答案1

Systemd 能够处理各种不同的服务类型,特别是以下之一

  • simple- 一个长时间运行的进程,不将其自身置于后台并保持附加到外壳。
  • forking- 一个典型的守护进程,它会自行分叉,将其与运行它的进程分离,从而有效地将自身置于后台。
  • oneshot- 预计将退出的短暂进程。
  • dbus- 与简单类似,但进程启动完成的通知是通过 dbus 发送的。
  • notify- 与简单类似,但进程启动完成的通知是通过 inotify 发送的。
  • idle- 与简单一样,但二进制文件在作业分派后启动。

在您的情况下,您选择了Type=forking这意味着 systemd 正在等待进程自行分叉并等待父进程结束,这表明进程已成功启动。但是,您的进程并没有执行此操作 - 它保留在前台,因此systemctl start将无限期挂起或直到进程崩溃。

相反,您需要Type=simple,这是默认值,因此您可以完全删除该行以获得相同的效果。在这种模式下,systemd 不会等待进程完成启动(因为它无法知道何时发生),因此会立即继续执行和依赖服务。在你的情况下没有,所以这并不重要。

关于安全性的一个小注意事项:

您以 root 身份运行该服务,这是不鼓励的,因为它比以非特权用户身份运行它的安全性更低。这样做的原因是如果jekyll 中存在一个漏洞,该漏洞以某种方式允许执行命令(可能是通过它正在解析的代码),那么攻击者无需执行任何其他操作即可完全控制您的系统。另一方面,如果它以非特权用户身份运行,则攻击者只能造成与该用户一样多的破坏,现在必须尝试获得 root 权限才能完全控制您的系统。它只是增加了攻击者必须通过的额外一层。

您可以简单地以与运行 Web 服务器的用户相同的用户身份运行它,但这会让您面临另一种潜在的攻击。如果您的 Web 服务器中存在允许用户操纵系统上的文件的漏洞,他们可以修改生成的 html 文件,或者最坏的源文件并导致您的服务器提供他们想要的任何服务。但是,如果生成的文件和源文件只能由 Web 服务器读取并且可由其他非特权用户写入,那么他们将无法通过攻击 Web 服务器轻松地修改它们。

但是,如果您只是从该服务器提供静态文件并保持服务器最新,则这些攻击的可能性非常小 - 但仍然有可能。您有责任根据系统的重要性来权衡风险与设置费用,但这两个技巧的设置都非常简单,并且几乎没有维护费用。

答案2

此外 @迈克尔·达芬的解决方案,您还可以使用守护进程forking工具来实现如下例所示的用法。

给定一个我想要守护并控制 systemd 的小 shell 脚本,我将其保存为/home/pi/testscript.sh

#!/bin/bash

while true;
do
    sleep 1
    echo -n "."
done

如果你还没有安装守护进程,请安装它,如下所示:

sudo apt install daemonize

现在创建文件服务定义文件:

sudo vi /etc/systemd/system/testomat.service
# It is not recommended to modify this file in-place, because it will
# be overwritten during package upgrades. If you want to add further
# options or overwrite existing ones then use
# $ systemctl edit testomat.service
# See "man systemd.service" for details.

# copied from https://github.com/bitcoin/bitcoin/blob/master/contrib/init/bitcoind.service and modified by Michael 

[Unit]
Description=Test service
After=network.target

[Service]
ExecStart=daemonize -p /run/testomat/testomat.pid -o /home/pi/testscript.log /home/pi/testscript.sh
TimeoutSec=1200

# Make sure the config directory is readable by the service user
PermissionsStartOnly=true

# Process management
####################
Type=forking
PIDFile=/run/testomat/testomat.pid
Restart=on-failure
GuessMainPID = true

# Directory creation and permissions
####################################

# Run as pi:pi
User=pi
Group=pi

# /run/testomat
RuntimeDirectory=testomat
RuntimeDirectoryMode=0710

# /var/lib/testomat
StateDirectory=testomat
StateDirectoryMode=0710

# Hardening measures
####################

# Provide a private /tmp and /var/tmp.
PrivateTmp=true

# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full

# Allow access to /home, /root and /run/user
# Chosing "false" is actually no hardening, this is just to demonstrate the usage of a service. Well, I could have omitted it. True. :)
ProtectHome=false

# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true

# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true

# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true

[Install]
WantedBy=multi-user.target

新创建的服务必须向 systemd 声明:

systemctl daemon-reload

现在您可以启动服务,并且脚本会分叉。正如预期的那样,服务启动立即返回到 shell。结果显而易见:

$ tail -f testscript.log 
.....................

相关内容