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

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

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

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

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

例如,我有以下内容

$ cat /etc/profile.d/somexports

export VAR1=VALUE1
export VAR2=VALUE2

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

答案1

有几种可能的环境来源:

  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

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

相关内容