让systemd服务继承/etc/profile.d中的环境变量

pka*_*mol 14 environment-variables systemd

我有一个systemd服务在特定用户下运行。

我错误地认为该服务可以访问所有用户从脚本/导出继承的环境变量/etc/profile.d

有没有一种方法可以完成此任务,而无需手动复制systemd单元文件定义中的变量。

例如,我有以下内容

$ cat /etc/profile.d/somexports

export VAR1=VALUE1
export VAR2=VALUE2
Run Code Online (Sandbox Code Playgroud)

这可以传递/导出到systemd服务吗?

Ste*_*art 15

有几种可能的环境来源:

  1. 使用Environment=它可以设置变量
  2. 使用EnvironmentFile=它可以从文件加载值
  3. 使用PassEnvironment=它可以让您定义应从 PID1 传递的变量。
  4. 静态配置(例如$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
Run Code Online (Sandbox Code Playgroud)

到

ExecStart=/usr/bin/bash -lc myservice
Run Code Online (Sandbox Code Playgroud)

这将导致bash成为父进程,加载/etc/profile.d/该环境并将其转发给其子进程。另请注意,我没有指定 的完整绝对路径myservice。在这种情况下,myservice将基于$PATH并且可能是也可能不是/usr/bin/myservice。您可以看到这可能会使故障排除变得更加困难,而这正是采用此方法的缺点。

  • systemd 不关心 `/etc/profile` 或 `/etc/profile.d` 的另一个原因是 systemd 被设计为与 shell 无关。`/etc/profile` 及其中使用的语法特定于 Bourne 类型 shell。Systemd 希望独立于 shell,并且应该可以在具有不同 shell 的系统上使用 systemd,甚至在没有任何 shell 的系统上使用 systemd。 (3认同)

pka*_*mol 5

我认为这个问题可以解决如下

ExecStart=/bin/sh -lc /path/to/binary
Run Code Online (Sandbox Code Playgroud)

该-l标志使 shell 调用成为登录 shell。我们需要这个,因为只有登录 shell 源配置文件脚本。

$ bash --help | grep -- -l
GNU bash, version 4.4.12(1)-release-(x86_64-pc-linux-gnu)
    --login
Run Code Online (Sandbox Code Playgroud)