我有一个 systemd 服务,需要在 中创建一个目录/run
,但以非 root 用户身份运行。从博客的例子中,我得出了以下解决方案:
[Unit]
Description=Startup Thing
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 -u /opt/thing/doStartup
WorkingDirectory=/opt/thing
StandardOutput=journal
User=thingUser
# Make sure the /run/thing directory exists
PermissionsStartOnly=true
ExecStartPre=-/bin/mkdir -p /run/thing
ExecStartPre=/bin/chmod -R 777 /run/thing
[Install]
WantedBy=multi-user.target
神奇之处在于评论后面的三行。显然,ExecStartPre
将以这种方式以 root 身份运行,但将以ExecStart
指定用户身份运行。
但这导致了 3 个问题:
-
the 前面有什么作用/bin/mkdir
?我不知道它为什么在那里,也不知道它有什么作用。- 当一个单元文件中有多个
ExecStartPre
' 时,它们是否只是按照在单元文件中找到的顺序串行运行?或者其他方法? - 这实际上是实现我创建运行目录以便非 root 用户可以使用它的目标的最佳技术吗?
答案1
对于有关 systemd 指令的任何问题,您可以man systemd.directives
查找记录该指令的手册页。对于ExecStartPre=
,您会发现它记录在 中man systemd.service
。
在 的文档中ExecStartPre=
,您会发现它解释了前导“-”用于表示这些命令可以容忍失败。在这种情况下,如果/run/thing
已经存在,则可以容忍。
那里的文档还解释说“允许使用多个命令行,并且命令会依次执行”。
对预创建目录方法的一项改进是,当您只需要某个特定用户可写该目录时,不要将其设置为全局可写。更有限的权限可以通过以下方式完成:
ExecStartPre=-/bin/chown thingUser /run/thing
ExecStartPre=-/bin/chmod 700 /run/thing
这使得该目录由特定用户拥有并可以完全访问。
答案2
回答#3:
查看RuntimeDirectory=
&RuntimeDirectoryMode=
指令。完整文档这里。但总而言之(对文字略有修改,但本质应该保留):
RuntimeDirectory=
This option take a whitespace-separated list of directory names. The
specified directory names must be relative, and may not include "..". If
set, one or more directories by the specified names will be created
(including their parents) below /run (for system services) or below
$XDG_RUNTIME_DIR (for user services) when the unit is started. Also, the
$RUNTIME_DIRECTORY environment variable is defined with the full path of
directories. If multiple directories are set, then in the environment
variable the paths are concatenated with colon (":").
The innermost subdirectories are removed when the unit is stopped. It is
possible to preserve the specified directories in this case if
RuntimeDirectoryPreserve= is configured to restart or yes. The innermost
specified directories will be owned by the user and group specified in
User= and Group=.
If the specified directories already exist and their owning user or group
do not match the configured ones, all files and directories below the
specified directories as well as the directories themselves will have their
file ownership recursively changed to match what is configured. As an
optimization, if the specified directories are already owned by the right
user and group, files and directories below of them are left as-is, even if
they do not match what is requested. The innermost specified directories
will have their access mode adjusted to the what is specified in
RuntimeDirectoryMode=.
Use RuntimeDirectory= to manage one or more runtime directories for the
unit and bind their lifetime to the daemon runtime. This is particularly
useful for unprivileged daemons that cannot create runtime directories in
/run due to lack of privileges, and to make sure the runtime directory is
cleaned up automatically after use. For runtime directories that require
more complex or different configuration or lifetime guarantees, please
consider using tmpfiles.d(5).
RuntimeDirectoryMode=
Specifies the access mode of the directories specified in
RuntimeDirectory= as an octal number. Defaults to 0755. See "Permissions"
in path_resolution(7) for a discussion of the meaning of permission bits.
因此,为了利用这一点,这应该可以解决问题:
[Unit]
Description=Startup Thing
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 -u /opt/thing/doStartup
WorkingDirectory=/opt/thing
StandardOutput=journal
User=thingUser
# Make sure the /run/thing directory exists
PermissionsStartOnly=true
RuntimeDirectory=thing
RuntimeDirectoryMode=0777
[Install]
WantedBy=multi-user.target