系统服务运行而不会退出


30

我创建了自己的服务,为化身,当我启动服务,好像是因为我被迫它不作为后台进程运行ctrl+ c的出来。由于--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

如果您正在使用systemd,它将启动您的进程,并期望它派生另一个进程Type=forking。而且,它不会execStart作为shell扩展运行,因此&最后永远不会被理解为背景标志。
俗气的

我的坏人是我在测试它。那么输入应该简单吗?
madmanali93 2013年

2
如果我没有记错的话,jekyll是一个rails类型的东西,即在ruby中的小型weby服务器。是的,Type=simple这是适当的。另外,这不是我将以root身份运行的应用程序,至少不是在面向Internet的计算机上运行(可能不是您的情况)。
grochmal

谢谢,很简单。此外,此命令还会为Apache生成静态html,以便jekyll不能在服务器上运行。我认为如果以root身份运行应该很好。不确定是否正在辩论。
madmanali93 2013年

哦,好的,这就是--incremental:)。是的,我看不到以root身份重新生成文件的安全问题。当然,由于这些文件不是用户提供的。
俗的

Answers:


54

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

  • simple -长时间运行的进程,不会自身后台运行,并且始终与外壳连接。
  • forking -一个典型的守护程序,将其自身分叉,将其从运行它的进程中分离出来,从而有效地使其自身成为后台。
  • oneshot -预计将退出的短暂进程。
  • dbus -很简单,但是启动完成的通知是通过dbus发送的。
  • notify -很简单,但是启动完成的通知是通过inotify发送的。
  • idle -就像简单一样,但是二进制文件是在工作分配后启动的。

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

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

安全注意事项:

您正在以root用户身份运行服务,因此不建议这样做,因为它比以非特权用户身份运行它的安全性低。这样做的原因是,如果 jekyll中存在一个漏洞,该漏洞以某种方式允许执行命令(可能通过它正在解析的代码),则攻击者无需执行任何其他操作即可完全拥有您的系统。另一方面,如果它以非特权用户身份运行,则攻击者只能造成与该用户相同的损害,并且现在必须尝试获取root特权才能完全拥有您的系统。它只是增加了攻击者必须经过的额外一层。

您可以简单地以与运行Web服务器相同的用户身份运行它,但这会使您容易遭受另一种潜在的攻击。如果您的Web服务器中存在一个漏洞,该漏洞允许用户操纵系统上的文件,则他们可以修改生成的html文件,或者更糟的是,源文件并使服务器提供他们想要的任何服务。但是,如果生成的文件和源文件仅可由Web服务器读取并且可写为另一个非特权用户,则它们将无法像通过攻击Web服务器那样容易地对其进行修改。

但是,如果您只是从该服务器提供静态文件并使服务器保持最新状态,则这些攻击极不可能发生,但仍然可能。您有责任根据系统的重要性来权衡设置风险和开销,但是这两个技巧都很容易设置,而且几乎没有维护开销。


0

除了@ Michael Daffin的解决方案之外,您还可以使用守护程序工具来实现用法,forking如以下示例所示。

给定一个我想守护并希望控制systemd的外壳程序脚本,我将其保存为/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

现在,您可以启动服务和脚本派生。如预期的那样,服务启动立即返回到外壳。结果很明显:

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


使用daemonize+ Type=forking代替Type=simple并让systemd照顾启动服务的好处是什么?Type=forking是systemd中的一种兼容性设置,用于支持写入fork的旧程序。
JohanMyréen

我认为这是一个等效的解决方案。我只是想为OP提供一种替代解决方案,并使他知道我已经在/etc/init.d时代使用过的该工具,因为问题还在于如何守护进程。
迈克尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.