将 shell 脚本作为守护进程运行的“正确”方式

use*_*676 31 linux debian shell-script daemon

我正在编写一个shell 脚本,我想在启动时作为守护程序运行,而不使用daemontoolsdaemonize等外部工具


Linux 守护进程编写 HOWTO

根据Linux Daemon Writing HOWTO,一个合适的守护进程具有以下特征:

  • 来自父进程的分叉
  • 关闭所有文件描述符(即stdin, stdout, stderr
  • 打开日志以进行写入(如果已配置)
  • 工作目录更改为持久目录(通常为/
  • 重置文件模式掩码(umask)
  • 创建唯一的会话 ID (SID)

daemonize简介

守护进程介绍更进一步,指出一个典型的守护程序也:

  • 与其控制终端(如果有)解除关联并忽略所有终端信号
  • 与其进程组分离
  • 把手 SIGCLD

我将如何做到这一切的shdashbash只用普通的Linux工具脚本?

该脚本应该能够在尽可能多的发行版上运行而无需额外的软件,尽管Debian是我们的主要关注点。


注意:我知道StackExchange网络上有很多建议使用nohup或的答案setsid,但是这些方法都没有解决上述所有要求。


编辑:守护进程(7)用户手册还给出了一些三分球,虽然似乎有老式的之间的一些差异SysV守护程序和更新systemd的。由于与各种发行版的兼容性很重要,请确保答案明确说明任何差异。


小智 31

使用systemd,您应该能够通过创建一个简单的单元来将脚本作为守护程序运行。您可以添加许多不同的选项,但这与您可以获得的一样简单。

假设您有一个脚本/usr/bin/mydaemon

#!/bin/sh

while true; do
  date;
  sleep 60;
done
Run Code Online (Sandbox Code Playgroud)

不要忘记sudo chmod +x /usr/bin/mydaemon

您创建一个单元/etc/systemd/system/mydaemon.service

[Unit]
Description=My daemon

[Service]
ExecStart=/usr/bin/mydaemon
Restart=on-failure

[Install]
WantedBy=multi-user.target 
Run Code Online (Sandbox Code Playgroud)

启动你运行的恶魔

systemctl start mydaemon.service 
Run Code Online (Sandbox Code Playgroud)

要在启动时启动,请启用它

systemctl enable mydaemon.service
Run Code Online (Sandbox Code Playgroud)

如果在基于 systemd 的系统上(当今大多数 Linux 发行版都在使用),这实际上并不是一个外部工具。消极的是它不会在任何地方都有效。

  • 对于使用 systemd 的发行版,`systemd` 不再是 `bash` 的“外部工具”。 (9认同)
  • 虽然我喜欢 systemd 方法,但 OP 说“没有外部工具”。有些 Linux 发行版还没有 systemd,或者让您在 systemd 和其他东西之间进行选择,例如 OpenRC。 (3认同)

LSe*_*rni 8

我可能在这里遗漏了一些东西;为什么nohup不合适?当然光靠它是不够的,但补充它似乎很简单。

#!/bin/bash

if [ "$1" = "DAEMON" ]; then
    # is this necessary? Add other signals at will (TTIN TTOU INT STOP TSTP)
    trap '' INT
    cd /tmp
    shift
    ### daemonized section ######
    for i in $( seq 1 10 ); do
        date
        sleep 5
    done
    #### end of daemonized section ####
    exit 0
fi

export PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
umask 022
# You can add nice and ionice before nohup but they might not be installed
nohup setsid $0 DAEMON $* 2>/var/log/mydaemon.err >/var/log/mydaemon.log &
Run Code Online (Sandbox Code Playgroud)

据我所知:

  • 输出被适当重定向(如有必要,使用 /dev/null)
  • umask 是继承的
  • stdin 无论如何都会在父脚本的末尾死亡
  • daemon.sh 脚本重新指向init(或systemd

我有一种强烈的感觉,我错过了显而易见的事情。Downvote,但请告诉我它是什么:-)

  • 我正要提出一些非常相似的建议。我使用带有 `&` 和 I/O 重定向的 `nohup` 来启动几个非 `C` 守护程序实用程序,这可能增加了将 `nohup` 命令包装在 `su -c "nohup ... &" 中的安全性-s /bin/bash systemUser` 以非特权用户身份运行守护程序。 (2认同)