我有一个带systemd的Arch Linux系统,并且已经创建了自己的服务。的配置服务/etc/systemd/system/myservice.service
如下所示:
[Unit]
Description=My Daemon
[Service]
ExecStart=/bin/myforegroundcmd
[Install]
WantedBy=multi-user.target
现在我想为设置环境变量/bin/myforegroundcmd
。我怎么做?
我有一个带systemd的Arch Linux系统,并且已经创建了自己的服务。的配置服务/etc/systemd/system/myservice.service
如下所示:
[Unit]
Description=My Daemon
[Service]
ExecStart=/bin/myforegroundcmd
[Install]
WantedBy=multi-user.target
现在我想为设置环境变量/bin/myforegroundcmd
。我怎么做?
Answers:
时代在变化,最佳实践也在变化。
在当前要做到这一点最好的方法是运行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
。
有关完整的详细信息,请参阅有关如何编写systemd脚本的 Fedora文档。
/etc/sysconfig
是Fedora特有的。AFAIR Arch Linux一直在推动配置文件位于特定于软件包的/etc
位置,而不是特定于Fedora的位置。就像一样/etc/myservice.conf
,尽管在这里使用多余的文件似乎不是正确的方法。
DJANGO_SETTINGS_MODULE=project.settings
,每行一对。
答案取决于变量是应该是常量(即不应由用户获取单位来修改)还是变量(应由用户设置)。
由于它是您的本地单位,因此边界非常模糊,无论哪种方式都可以。但是,如果您开始分发它并且最终将在中发行/usr/lib/systemd/system
,那么这将变得很重要。
如果不需要为每个实例更改值,则首选方法是将其作为放置Environment=
在单元文件中:
[Unit]
Description=My Daemon
[Service]
Environment="FOO=bar baz"
ExecStart=/bin/myforegroundcmd
[Install]
WantedBy=multi-user.target
这样做的好处是变量与单元一起保存在单个文件中。因此,单位文件更易于在系统之间移动。
但是,当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的命令
http://0pointer.de/public/systemd-man/systemd.exec.html#Environment=-您有两种选择(其中一种已经由Michael指出):
Environment=
和
EnvironmentFile=
通过这些问题的答案迈克尔和米哈尔是有益的,并回答了如何设置一个环境变量的systemd服务原来的问题。但是,环境变量的一种常见用法是在一个不会意外地使用应用程序代码进行源代码控制的地方配置敏感数据,例如密码。
如果这就是为什么你需要一个环境变量传递给你的服务,不使用Environment=
的单元配置文件中 使用EnvironmentFile=
并将其指向仅服务帐户(和具有root访问权限的用户)可读的另一个配置文件。
使用以下命令,任何用户都可以看到单元配置文件的详细信息:
systemctl show my_service
我将配置文件放在其中/etc/my_service/my_service.conf
,并将我的秘密放在其中:
MY_SECRET=correcthorsebatterystaple
然后在服务单元文件中,我使用了EnvironmentFile=
:
[Unit]
Description=my_service
[Service]
ExecStart=/usr/bin/python /path/to/my_service.py
EnvironmentFile=/etc/my_service/my_service.conf
User=myservice
[Install]
WantedBy=multi-user.target
我检查了ps auxe
看不到这些环境变量,并且其他用户没有访问权限/proc/*/environ
。当然,请检查您自己的系统。
Michael提供了一个简单的解决方案,但我想从脚本中获取更新的env变量。不幸的是,在systemd单元文件中无法执行bash命令。幸运的是,您可以在ExecStart中触发bash:
http://www.dsm.fordham.edu/cgi-bin/man-cgi.pl?topic=systemd.service§=5
请注意,此设置不直接支持Shell命令行。如果要使用shell命令行,则需要将它们显式传递给某种shell实现。
那么我们的例子是:
[Service]
ExecStart=/bin/bash -c "ENV=`script`; /bin/myforegroundcmd"
/bin/bash -a -c 'source /etc/sysconfig/whatever && exec whatever-program'
。在-a
确保环境导出到子进程(除非你想在前缀所有变量whatever
与export
)
ExecStart=/usr/bin/env ENV=script /bin/myforegroundcmd
在这种情况下,也许是更好的解决方案。
sysconfig
路径特定于Fedora,但问题是关于Arch Linux。我认为paluh的答案更有趣