我有一个带有systemd的Arch Linux系统,并且已经创建了自己的服务。 /etc/systemd/system/myservice.service上的配置服务如下所示:

[Unit]
Description=My Daemon

[Service]
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target


现在我想为/bin/myforegroundcmd设置一个环境变量。我该怎么办?

#1 楼

时间会改变,因此也会采取最佳做法。

当前的最佳做法是运行systemctl edit myservice,它将为您创建一个替代文件或让您编辑现有文件。

在常规安装中,这将创建一个目录/etc/systemd/system/myservice.service.d,并在该目录内创建一个名称以.conf结尾的文件(通常为override.conf),您可以在此文件中添加或覆盖该文件的任何部分

例如,在文件/etc/systemd/system/myservice.service.d/myenv.conf中:

 [Service]
Environment="SECRET=pGNqduRFkB4K9C2vijOmUDa2kPtUhArN"
Environment="ANOTHER_SECRET=JP8YLOc2bsNlrGuD6LVTq7L36obpjzxd"
 


还要注意,如果目录存在且为空,则将禁用您的服务!如果您不打算在目录中放置某些内容,请确保该目录不存在。


作为参考,旧方法是:

推荐这样做的方法是创建一个包含变量的文件/etc/sysconfig/myservice,然后用EnvironmentFile加载它们。

有关完整的详细信息,请参见Fedora的文档,该文件有关如何编写systemd脚本。

评论


我想sysconfig路径特定于Fedora,但问题是关于Arch Linux。我认为paluh的答案更有趣

–Ludovic Kuty
2013年4月27日在8:49

/ etc / sysconfig是特定于Fedora的。 AFAIR Arch Linux一直在推动将配置文件放在特定于软件包的某个位置,而不是在/ etc中,而不是该Fedora特定的位置。像/etc/myservice.conf一样,尽管使用多余的文件在这里似乎不是正确的方法。

–MichałGórny
2014年4月23日在7:13

不不不。不建议/ etc / sysconfig。不鼓励与debian中的/ etc / default / *一起使用,因为它们是毫无意义的,并且名称是没有意义的,并且仅出于向后兼容的原因才有意义(所有/ etc都是关于系统的配置,而不仅仅是/ etc / sysconfig和/ etc / defaults用于覆盖,而不是默认值)。只需将定义直接放在单元文件中,或者如果不可能的话,将其放在具有程序包特定位置的环境文件中(如Michał的注释所示)。

–zbyszek
2014年10月4日在18:41

@FrederickNord这只是变量=值对,例如DJANGO_SETTINGS_MODULE = project.settings,每行一个。

–迈克尔·汉普顿
2015年11月2日于17:01

@MichaelHampton您能否为“当前最佳方法”添加文档链接?

– jb。
2015年12月31日下午13:26

#2 楼

答案取决于变量是应该是常量(即不应该由用户获取单位进行修改)还是变量(应由用户设置)。

因为这是您的本地单位,边界很模糊,无论哪种方式都可以。但是,如果您开始分发它,并最终出现在/usr/lib/systemd/system中,这将变得很重要。

常量值

如果不需要每个实例更改值,首选方法是将其作为Environment=直接放置在单元文件中:

 [Unit]
Description=My Daemon

[Service]
Environment="FOO=bar baz"
ExecStart=/bin/myforegroundcmd

[Install]
WantedBy=multi-user.target
 


这样的优点是变量与单元一起保存在单个文件中。因此,单位文件更易于在系统之间移动。

变量值

但是,当sysadmin应该更改sysadmin的值时,上述解决方案效果不佳本地环境变量。更具体地说,每次单位文件更新时都需要设置新值。

在这种情况下,将使用额外的文件。方式-通常取决于分发策略。

一种特别有趣的解决方案是使用/etc/systemd/system/myservice.service.d目录。与其他解决方案不同,此目录由systemd本身支持,因此没有特定于发行版的路径。在这种情况下,您放置了一个文件/etc/systemd/system/myservice.service.d/local.conf之类的文件,其中添加了单位文件的缺失部分:

 [Service]
Environment="FOO=bar baz"
 


此后,systemd在启动服务时合并两个文件(在更改其中一个后请记住systemctl daemon-reload其中)。而且由于此路径由systemd直接使用,因此您不必为此使用EnvironmentFile=

如果仅在某些受影响的系统上应更改该值,则可以结合使用两种解决方案,默认值直接在单元中,而本地替代在另一个文件中。

评论


systemctl daemon-reload是重新加载systemd的命令

–德米特里·布佐林
18年4月22日在23:57

当值是密码之类的秘密时,EnvironmentFile ==更好。有关详细信息,请参见我的答案。

–唐·柯比(Don Kirkby)
18年5月4日在0:31

#3 楼

http://0pointer.de/public/systemd-man/systemd.exec.html#Environment=-您有两种选择(Michael已经指出了一种选择):

Environment=




EnvironmentFile=


#4 楼

Michael和Michał的回答很有帮助,回答了有关如何为systemd服务设置环境变量的原始问题。但是,环境变量的一种常见用法是在一个不会意外地使用应用程序代码进行源代码控制的地方配置敏感数据(例如密码)。

如果这就是为什么要传递环境服务变量,请勿在设备配置文件中使用Environment=。使用EnvironmentFile=并将其指向只能由服务帐户(和具有root用户访问权限的用户)读取的另一个配置文件。

使用以下命令,任何用户都可以看到单元配置文件的详细信息:

systemctl show my_service


我在/etc/my_service/my_service.conf上放了一个配置文件,并把我的秘密放在那里:
服务单元文件中,我使用了EnvironmentFile=

MY_SECRET=correcthorsebatterystaple


我检查了ps auxe看不到那些环境变量,并且其他用户无权访问/proc/*/environ。当然,请检查您自己的系统。

#5 楼

迈克尔给出了一个干净的解决方案,但我想从脚本中获取更新的环境变量。
不幸的是,在systemd单元文件中无法执行bash命令。幸运的是,您可以在ExecStart中触发bash:

http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service&sect=5


请注意,此设置不直接支持Shell命令行。如果要使用shell命令行,则需要将它们显式传递给某种shell实现。


我们的例子是:

[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"


评论


由于多种原因,这将不起作用(除非它是“一次性”服务,这毫无意义)。我设法使以下各项起作用:/ bin / bash -a -c'source / etc / sysconfig / whatever && exec what-program'。 -a确保将环境导出到子进程(除非您要在export中添加所有变量的前缀)

–奥修斯
15年4月29日在22:42

为什么它不起作用?它应该始终触发包括执行脚本在内的整个命令,不是吗?

–user1830432
15年4月30日在8:29

在这种情况下,也许ExecStart = / usr / bin / env ENV = script / bin / myforegroundcmd是一个更好的解决方案。

–kstep
15年11月26日在6:18

@Otheus:很好的答案,在我不得不创建Tomcat 8 Unit文件的那天就保存下来了。

–丹尼尔(Daniel)
16年4月13日在6:58

有一种方法可以在systemd服务文件中“执行” bash命令。请参阅此链接:coreos.com/os/docs/latest/…

–马克·拉卡塔(Mark Lakata)
17年1月13日,0:35