我有一个systemd
服务在特定用户下运行。
我错误地认为该服务可以访问所有用户从脚本/导出继承的环境变量/etc/profile.d
systemd
有没有一种方法可以完成此任务,而无需手动复制单元文件定义中的变量。
例如,我有以下内容
$ cat /etc/profile.d/somexports
export VAR1=VALUE1
export VAR2=VALUE2
这可以传递/导出到systemd
服务吗?
答案1
有几种可能的环境来源:
- 使用
Environment=
它可以设置变量 - 使用
EnvironmentFile=
它可以从文件加载值 - 使用
PassEnvironment=
它可以让您定义应从 PID1 传递的变量。 - 静态配置(例如
$USER
)
这听起来可能EnvironmentFile=/etc/profile.d/someexports
就是您想要的,但事实并非如此。 /etc/profile.d/*
通常由您的 shell 获取并可以由您的 shell 进行解析。 systemd
与 shell 无关,因此它不会依赖 bash 语法。应该EnvironmentFile
包含更严格的换行符分隔的变量赋值。
systemd
的设计不鼓励动态改变单元或其环境。甚至这个EnvironmentFile=
选项也是迫于压力才添加的,后来被systemd
开发者认为是一个错误。这种设计的一个例子是,它$PATH
不会影响使用哪些二进制文件。这使事情更具确定性,因为当您定义一个单元时,您正在定义有关该单元应如何运行的所有内容,而无需担心外部影响。
所以简短的回答是:不。你无法加载/etc/profile.d/*
,systemd
这是故意的。
但您可能想要的答案是:是的,您可以加载它。您只需要通过 shell 运行您的应用程序即可。
您可以通过更改来做到这一点:
ExecStart=/usr/bin/myservice
到
ExecStart=/usr/bin/bash -lc myservice
这将导致bash
成为父进程,加载/etc/profile.d/
该环境并将其转发给其子进程。另请注意,我没有指定 的完整绝对路径myservice
。在这种情况下,myservice
将基于$PATH
并且可能是也可能不是/usr/bin/myservice
。您可以看到这可能会使故障排除变得更加困难,而这正是采用此方法的缺点。
答案2
我认为这个问题可以解决如下
ExecStart=/bin/sh -lc /path/to/binary
该-l
标志使 shell 调用成为登录 shell。我们需要这个,因为只有登录 shell 源配置文件脚本。
$ bash --help | grep -- -l
GNU bash, version 4.4.12(1)-release-(x86_64-pc-linux-gnu)
--login