在 systemd 服务脚本中创建 PID 文件时遇到问题

jia*_*103 2 systemd systemctl debian-jessie

我正在尝试在 Debian 上安装 RipRight,但似乎没有任何预先构建的软件包。我很难让 systemd 脚本开始/停止 RipRight 作为守护程序运行,因为它无法将 PID 文件写入/run.

我经历了通常的配置/制作/制作安装。我还创建了一个ripright用户/组并添加ripright到该cdrom组中。

这是我放入的 systemd 脚本/etc/systemd/system/ripright.service

[Unit]
Description=RipRight

[Service]
Type=forking
PrivateTmp=yes
User=ripright
Group=ripright

RuntimeDirectory=ripright
RuntimeDirectoryMode=0750

ExecStart=/usr/local/bin/ripright \
    --daemon \
    --w32-filenames \
    --require-art \
    --folder-art folder.png \
    --output-file "%B/%D/%C - %N %T.flac" \
    "/opt/ripright/data"
PIDFile=/var/run/ripright/ripright.pid

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

RuntimeDirectory在脚本中使用了最近添加的指令来创建一个作为所有者的/run/ripright文件夹ripright。这个目录在我运行时被创建:

# systemctl daemon-reload
# systemctl start ripright
Run Code Online (Sandbox Code Playgroud)

在单独的窗口中:

# ls -lhrt /run
...
drwxr-x---  2 ripright ripright   40 Jan  5 20:52 ripright
drwxr-xr-x 16 root     root      400 Jan  5 20:52 systemd
# ls -lahrt /run/ripright
total 0
drwxr-xr-x 16 root     root     540 Jan  5 20:52 ..
drwxr-x---  2 ripright ripright  40 Jan  5 20:52 .
# su - ripright
$ cd /run/ripright
$ pwd
/run/ripright
$ echo test > one.txt
$ cat one.txt
test
$ rm one.txt
$ exit
Run Code Online (Sandbox Code Playgroud)

我相信我的systemctl start命令不会因此返回,而是挂起。大约一分钟后,它超时:

# systemctl start ripright
Job for ripright.service failed. See 'systemctl status ripright.service' and 'journalctl -xn' for details.
Run Code Online (Sandbox Code Playgroud)

以下是推荐命令的输出:

# systemctl status ripright.service
? ripright.service - RipRight
   Loaded: loaded (/etc/systemd/system/ripright.service; enabled)
   Active: failed (Result: timeout) since Thu 2017-01-05 20:54:40 EST; 55s ago
  Process: 35396 ExecStart=/usr/local/bin/ripright --daemon --w32-filenames --require-art --folder-art folder.png --output-file %B/%D/%C - %N %T.flac /opt/ripright/data (code=exited, status=0/SUCCESS)
 Main PID: 33287 (code=killed, signal=TERM)

Jan 05 20:53:10 ripperd ripright[35397]: Started daemon mode (v0.11)
Jan 05 20:53:10 ripperd ripright[35398]: Waiting for a CD (/dev/cdrom)
Jan 05 20:54:40 ripperd systemd[1]: ripright.service start operation timed out. Terminating.
Jan 05 20:54:40 ripperd systemd[1]: Failed to start RipRight.
Jan 05 20:54:40 ripperd systemd[1]: Unit ripright.service entered failed state.

# journalctl -xn
-- Logs begin at Thu 2017-01-05 00:30:29 EST, end at Thu 2017-01-05 20:54:40 EST. --
Jan 05 20:52:00 ripperd ripright[35380]: Waiting for a CD (/dev/cdrom)
Jan 05 20:52:59 ripperd su[35385]: Successful su for ripright by root
Jan 05 20:52:59 ripperd su[35385]: + /dev/pts/1 root:ripright
Jan 05 20:52:59 ripperd su[35385]: pam_unix(su:session): session opened for user ripright by vagrant(uid=0)
Jan 05 20:53:10 ripperd ripright[35397]: Started daemon mode (v0.11)
Jan 05 20:53:10 ripperd ripright[35398]: Waiting for a CD (/dev/cdrom)
Jan 05 20:53:33 ripperd su[35385]: pam_unix(su:session): session closed for user ripright
Jan 05 20:54:40 ripperd systemd[1]: ripright.service start operation timed out. Terminating.
Jan 05 20:54:40 ripperd systemd[1]: Failed to start RipRight.
-- Subject: Unit ripright.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit ripright.service has failed.
-- 
-- The result is failed.
Jan 05 20:54:40 ripperd systemd[1]: Unit ripright.service entered failed state.
Run Code Online (Sandbox Code Playgroud)

如果我在 systemd 服务脚本中注释掉 PIDFile 指令:

#PIDFile=/var/run/ripright/ripright.pid
Run Code Online (Sandbox Code Playgroud)

然后我没有问题,但也没有推荐用于分叉服务类型的 PID 文件:

# systemctl daemon-reload
# systemctl start ripright
# ps -ef | grep ripright
ripright  35438      1  0 21:03 ?        00:00:00 /usr/local/bin/ripright --daemon --w32-filenames --require-art --folder-art folder.png --output-file %B/%D/%C - ripright %T.flac /opt/ripright/data
ripright  35439  35438  0 21:03 ?        00:00:00 /usr/local/bin/ripright --daemon --w32-filenames --require-art --folder-art folder.png --output-file %B/%D/%C - ripright %T.flac /opt/ripright/data
root      35442  31942  0 21:03 pts/0    00:00:00 grep ripright
root@ripperd:~# systemctl status ripright
? ripright.service - A minimal CD ripper for Linux modeled on autorip.
   Loaded: loaded (/etc/systemd/system/ripright.service; enabled)
   Active: active (running) since Thu 2017-01-05 21:03:11 EST; 13s ago
  Process: 35437 ExecStart=/usr/local/bin/ripright --daemon --w32-filenames --require-art --folder-art folder.png --output-file %B/%D/%C - %N %T.flac /opt/ripright/data (code=exited, status=0/SUCCESS)
 Main PID: 35438 (ripright)
   CGroup: /system.slice/ripright.service
           ??35438 /usr/local/bin/ripright --daemon --w32-filenames --require...
           ??35439 /usr/local/bin/ripright --daemon --w32-filenames --require...

Jan 05 21:03:11 ripperd ripright[35438]: Started daemon mode (v0.11)
Jan 05 21:03:11 ripperd ripright[35439]: Waiting for a CD (/dev/cdrom)
# ls -la /run/ripright
total 0
drwxr-x---  2 ripright ripright  40 Jan  5 21:04 .
drwxr-xr-x 16 root     root     540 Jan  5 21:04 ..
# systemctl stop ripright
Run Code Online (Sandbox Code Playgroud)

有趣的是,当我带回PIDFiles并注释掉UserGroup以 root 运行 ripright 时,守护进程重新加载然后启动脚本仍然挂起:

#User=ripright
#Group=ripright
PIDFile=/var/run/ripright/ripright.pid
Run Code Online (Sandbox Code Playgroud)

如果我离开UserGroup注释掉并设置PIDFile为直接在 /run 目录中生成 PID 文件(注意 /var/run 只是 Debian Jessie 中 /run 的符号链接),也会发生同样的事情:

#User=ripright
#Group=ripright
#PIDFile=/var/run/ripright/ripright.pid
PIDFile=/run/ripright.pid
Run Code Online (Sandbox Code Playgroud)

请注意,在所有情况下,我都可以在挂起期间按 Ctrl+C,并且 ripright 守护程序将继续运行;但是,如果我让开始超时,它会在打印错误并返回之前停止守护进程。

我也浏览了这篇文章及其评论。最初的使用方法ExecStartPre有相同的结果;我没有使用,tmpfiles.d因为我找不到有关如何在不重新启动的情况下使更改生效的任何信息。我试过了,mount -a但这似乎不起作用。

小智 6

PIDFile=遗憾的是,即使您在服务的单元文件中指定了一行,systemd 也不会为非分叉服务创建 PID 文件。但你也许可以用一行ExecStartPost=字来作弊,例如:

ExecStartPost=/bin/sh -c 'umask 022; pgrep YOURSERVICE > /var/run/YOURSERVICE.pid'
Run Code Online (Sandbox Code Playgroud)


小智 5

如果你问 systemd 是否会为守护进程创建一个 PID 文件,它不会,根据:

https://www.freedesktop.org/software/systemd/man/systemd.service.html#PidFile=

PID文件=

采用指向此守护程序的 PID 文件的绝对文件名。对于 Type= 设置为分叉的服务,建议使用 > 此选项。systemd 会在服务启动后读取守护进程主进程的PID。systemd 不会写入此处配置的文件,但如果该文件仍然存在,它会在服务关闭后删除该文件。

最好将其留空并尝试使用 GuessMainPID=。