我有一个应用程序(以 root 身份作为服务运行),它在下创建一个 PID 文件/var/run
。但我想知道这是否不再是最佳实践。
在Linux - 存储 pid 文件的替代位置(而不是 /var/run),在 2012 年提出,提问者问 PID 文件是否应该放在/var/run
其中。不过,那主要是在 systemd 出现之前,以及 systemd 操作系统从转变为/var/run
仅仅/run
(作为 systemd 之一)之前。API 文件系统“并列于systemd 文件层次结构要求)。
类似的事情XDG 基础目录规范Lennart Poettering (和其他人) 讨论了“用户特定的非必要运行时文件和其他文件对象(例如套接字、命名管道等)”的其他地方。systemdfile-hierarchy
手册页。
我在其他地方读到的给我的印象/var/run/user/$UID
是新的systemd 操作系统上此类内容的标准位置。
- 答案在https://unix.stackexchange.com/questions/162900/讨论“用于运行进程的文件”。它表明,如果程序以 root 身份运行,则 /var/run/user/0 将是合适的位置 - 但此帖子还表示,当没有更多活动会话时,目录将被删除/清除。由于这是一项服务,这真的是正确的位置吗?
- https://github.com/systemd/systemd/issues/735#issuecomment-126309537显示 systemd 使用命令行参数调用的进程
--pid-file /run/user/1000/uzbl/event/pid
- https://lists.debian.org/debian-user/2015/10/msg01315.html在 Debian 用户邮件列表上的一个讨论中,有一个人说 PID 文件的“Full Freedesktop Monty” “
/run/user
对此有具体说明”。
我们还可以找到许多其他的例子。
那么我的应用程序是否应该改为使用/var/run/user/$UID
?由于它是一项服务(没有活动会话),pam_systemd 会清除/删除目录吗?还是$XDG_RUNTIME_DIR
?这是 systemd 特有的东西吗?还是它是所有 Unices 的新标准?
什么是最佳实践如今在 systemd 操作系统上?一般来说其他(非 systemd,但类似 Unix)操作系统也是如此?
答案1
你问:
/var/run/user/$UID 是 PID 文件的新 /var/run 吗?
最简洁的答案是不”。
长话短说,答案仍然是“不”。
或者大声明确地说:传统 PID 文件不得低于/run/user/$UID/
(又名/var/run/user/$UID/
)。将它们保留在/run/
或中,/run/package/
如常,因为/run/user/$UID/
它们对于会话服务而言具有完全不同的用途。
供参考:
正如@Daniel B 所指出的,
/var/run
今天是一个指向 的软链接/run
。这不是特定于 的systemd
,在当今的大多数系统中都可以找到。如果您想与旧系统保持兼容,有两种解决方案:要么继续使用/var/run/
而不是/run/
,要么让某人为 创建一个软链接/run
,指向/var/run
这些旧系统。另请注意,
/run/user/$UID/
仅适用于运行 的系统systemd-logind
。旧系统也不支持它。
对于那些尚不清楚的人来说,详细说明如下:
服务有 3 种类型:系统服务、用户服务和会话服务。这 3 种类型都可以在后台或前台运行,因此有 6 种变体。
前台系统服务传统上由 启动/etc/inittab
,现在则systemd
通过 启动/etc/init/
。前台系统服务通常不需要 PID 文件,因为它们由 控制init
,如果发生故障可以重生。
后台系统服务传统上由运行级别脚本启动/etc/rc.d/
。这些通常需要 PID 文件,因为它们在后台运行,因此无法控制它们是否运行。PID 文件很容易出错(因为无法保证 PID 在服务终止后保持空闲状态),当 rc 脚本需要关闭服务时,它们会用于再次查找已启动的服务。这些 PID 文件传统上位于 中,/var/run
现在位于 中/run/package/
(或者,如果每个包只有一个文件,则位于 中/run/package.pid
)。
用户服务是由用户启动的服务,需要在用户会话结束后继续存在。例如,Minecraft 服务器,或使用短期会话按需触发的长寿命 SAP 查询进程。它们与系统服务略有不同,因为它们不能使用/run/
。相反,它们需要使用/tmp/
或下面的某个目录$HOME
(如果是网络共享,在多台计算机之间共享,则会出现问题$HOME
)。
前台用户服务有时会有点问题,因为它们通常需要tty
,因此如果用户注销,它们就会终止。因此,有很多方法可以让它们在用户离开后继续运行,例如nohup
或screen
。但甚至可能有一些奇特的变体,例如socat tcp-connect:host:port exec:service.sh,pty
。
前台用户服务的另一种变体是 cron 作业,它存在于crontab
用户中。但是,这些 cron 作业也可以是后台服务,例如,如果它们不应该并行运行,即使一个进程超过了 cron 下一次调用的时间。
后台用户服务与后台系统服务存在同样的问题,因为它们需要跟踪哪些服务已在运行并控制已在运行的服务。过去,由于需要使用每个/tmp
人都可以创建文件和目录的地方,这导致了各种问题和修复,例如目录遍历攻击等。
然而这一点至今仍未改变,因为/run/user/$UID/
它并非为此类用户服务而设计的。它旨在解决会话服务中更为棘手的问题。
会话服务是一种通常在用户登录时启动并在用户注销时停止的服务。这听起来很简单,但如果每个用户允许不止一个会话,那么它就会变得更加强大。要解决的难题是:“会话何时真正结束”?
会话从首次登录开始。这很容易理解。但它并不一定在此次登录注销时结束!因此,会话服务可以在首次登录时(或之后)启动,但通常需要继续运行,直到用户的最后一次会话注销。
前台会话服务通常是最简单的变体。例如,X-Windowdbus
服务以图形登录启动和终止。但是,如果您开始打印大型 PDF,您肯定希望这项工作能够成功完成或干净地终止而不留下任何残渣,对吗?
这些类型的会话服务要么需要在后台继续运行,要么在服务意外终止后必须有某种方式进行清理。在我们的移动世界中,设备经常会终止。想想你的显示器。你可以随时插入和拔下显示器。无需重新启动计算机。但是,如果你拔下所有屏幕会发生什么?当然,X11 会终止。对于在 X11 会话中运行的某些用户服务来说,这种情况是意外发生的,可能是在较长时间运行的任务中。
这很/run/user/$UID/
方便,因为最后一个用户会话结束后,此目录会被自动清除。因此,服务可以相信,用户将清除存储在 中的所有内容/run/user/$UID/
!
因此所有与会话相关的服务都应使用该目录。
另外请注意,我们dbus
今天有。因此,您不再需要依赖 PID 文件来查明某个服务是否正在运行。对于会话服务尤其如此,因为有一种称为“会话”的东西,它可以让您更好地处理事情,例如使用可以存在于中的共享内存段或锁定文件/run/user/$UID/
。
事情并不容易。为了让它变得更加复杂,还有诸如screen
、tmux
或ssh
(从 shell 中分叉出来的那个)之类的东西,它们有两个方面,一个方面是用户服务(即守护进程),另一个方面是会话服务(tty)。虽然它们通常与会话绑定,但并不总是如此。例如,如果您使用端口ssh
转发并退出 shell,ssh
则保持打开状态,直到最后一个转发的端口关闭。您甚至可以打开新端口,只要其他端口保持活动状态。在这种“双重”服务的情况下,PID 文件之类的东西可能会派上用场,在这种情况下,它甚至可能存在于 之下/run/user/$UID/
。
(请注意,cron
可用于打开用户会话,因此可能/run/user/$UID/
也可用于 cronjobs。但如果是这种情况,则/run/user/$UID/
在所有 cronjobs 完成后,将再次有资格进行清理。这可能意味着移交给其他地方的文件会消失,不像它们存在于 中时/tmp/
,因为只有重新启动才能无条件地删除那里的文件。)
把它们加起来:
如果您有一个设计合理的服务,那么您永远不需要普通的 PID 文件/run/user/$UID/
,因为会话服务(唯一使用此目录的服务)通常有更好的方法(会话)来保持控制,即使它们在后台运行。
因此,如果您发现您的服务需要 PID 文件,则很可能会得到类似/run/package/
或/run/package.pid
的内容/tmp/package-$UID/
。
/run/user/$UID/
仅当您想确保文件在用户完全注销后立即消失时才使用。另请注意,root
用户并非始终处于登录状态,因此可能不存在/run/user/0/
。
并且,请不要在您自己下面创建目录/run/user/
!
希望现在一切都很顺利。但我有件事要坦白:
我骗了你。我是故意这样做的(但并非出于恶意)。
因为会话(从systemd-logind
的角度来看)不仅仅绑定到login
。是的,当然,涉及到一些类似于 的事情login
,但事情要复杂得多:
https://dvdhrm.wordpress.com/2013/08/24/session-management-on-linux/
然而:
对于此处的帖子(简短但错误的故事),对您的问题的答案是“否”。
幸运的是,根据有关会议的长期(和真实)背景(参见链接),答案仍然是“否”。
仅对于一些非常少数非常特殊的情况,为了非常明确的目的,您才可以考虑将您的 PID 文件放入
/run/user/$UID/
。
祝你今天过得愉快。
答案2
这systemd.exec
手册对其选项有如下说明RuntimeDirectory
:
接受目录名称列表。如果设置,则在单元启动时将在下面
/run
(用于系统服务)或下面$XDG_RUNTIME_DIR
(用于用户服务)创建指定名称的一个或多个目录,并在单元停止时删除。
此外,在pam_systemd
手册页,我们可以找到以下信息$XDG_RUNTIME_DIR
(重点是我的):
与用户登录机器时绑定的用户私有用户可写目录的路径。它会在用户首次登录时自动创建,在用户最后一次注销时删除。
使用这两个手册,我们可以推断出$XDG_RUNTIME_DIR
(/run/user/$UID
在我的 Arch 安装中)不是系统服务的正确选择。相反,它们通常被放入/run
(至少在 Arch 和 Gentoo 上)。也可以RuntimeDirectory
按照上述方法在 中创建它们。
/var/run
只不过是/run
这些天的一个符号链接。