在systemd服务中使用环境变量

systemd 读取环境变量的机制

根据systemd/User中的说明如下:

Environment variables

The user instance of systemd does not inherit any of the environment variables set in places like .bashrc etc. There are several ways to set environment variables for the systemd user instance:

  • For users with a $HOME directory, create a .conf file in the ~/.config/environment.d/ directory with lines of the form NAME=VAL. Affects only that user’s user unit. See environment.d(5) for more information.
  • Use the DefaultEnvironment option in /etc/systemd/user.conf file. Affects all user units.
  • Add a drop-in configuration file in /etc/systemd/system/user@.service.d/. Affects all user units; see #Service example
  • At any time, use systemctl --user set-environment or systemctl --user import-environment. Affects all user units started after setting the environment variables, but not the units that were already running.
  • Using the dbus-update-activation-environment --systemd --all command provided by dbus. Has the same effect as systemctl --user import-environment, but also affects the D-Bus session. You can add this to the end of your shell initialization file.
  • For “global” environment variables for the user environment you can use the environment.d directories which are parsed by some generators. See environment.d(5) and systemd.generator(7) for more information.
  • You can also write a systemd.environment-generator(7) script which can produce environment variables that vary from user to user, this is probably the best way if you need per-user environments (this is the case for XDG_RUNTIME_DIRDBUS_SESSION_BUS_ADDRESS, etc).

One variable you may want to set is PATH.

After configuration, the command systemctl --user show-environment can be used to verify that the values are correct.

搜刮网上的一些说法后,总结如下:

  • /etc/profile或者/etc/security/limit.d这些文件中配置的环境变量仅对通过pam登录的用户生效,而systemd是不读这些配置的,所以这就造成登录到终端时查看环境变量和手动启动应用都一切正常,但是systemd无法正常启动应用
  • 如果需要给systemd配置默认参数,全局的配置在/etc/systemd/system.conf/etc/systemd/user.conf中。同时还会加载两个配置文件对应的目录中所有的.conf配置文件/etc/systemd/system.conf.d/*.conf/etc/systemd/user.conf.d/*.conf,一般的服务单元使用system.conf即可。加载优先级system.conf最低,所以system.conf.d目录中的配置会覆盖system.conf的配置
  • 目前已知的是更改system.conf配置,需要重启系统才能生效,还没找到如何重新加载此配置

虚拟机实验

实验目的: 看通过systemd运行的程序可以读取到哪些环境变量。

实验方法: 配置同一个脚本,脚本输出env的内容,比较shell下和systemd下启动该脚本的输出内容的区别。

试验文件准备

创建环境变量文件/etc/profile.d/env.sh,在其中设置环境变量MY_ENV="helloworld"

 

1

2

3

 

# cat /etc/profile.d/env.sh

export MY_ENV="helloworld"

#

创建service使用的脚本/usr/local/bin/systemctl_env_test.sh

 

1

2

3

4

5

 

#!/bin/bash

LOG_FILE="/tmp/systemctl_env_test.log"

echo "========================================================" > $LOG_FILE

env | sort >> $LOG_FILE

echo "========================================================" >> $LOG_FILE

 

1

2

3

4

5

6

7

8

 

#!/bin/bash

LOG_FILE="/tmp/systemctl_env_test.log"

echo "Start...." > $LOG_FILE

echo "======= Before load /etc/profile.d/env.sh" >> $LOG_FILE

env >> $LOG_FILE

source /etc/profile.d/env.sh >> $LOG_FILE

echo "======= After load /etc/profile.d/env.sh" >> $LOG_FILE

env >> $LOG_FILE

添加权限sudo chmod a+x /usr/local/bin/systemctl_env_test.sh

创建system service文件,/usr/lib/systemd/system/systemctl_env_test.service

 

1

2

3

4

5

6

7

8

9

10

11

 

[Unit]

Description=systemctl_env_test service

After=syslog.target network.target

[Service]

Type=forking

ExecStart=/usr/local/bin/systemctl_env_test.sh

PrivateTmp=false

[Install]

WantedBy=multi-user.target

导入service: systemctl daemon-reload

启动service命令: systemctl start systemctl_env_test.service

执行输出

当在shell下直接运行/usr/local/bin/systemctl_env_test.sh时,日志文件systemctl_env_test.log的输出如下:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

 

# bash /usr/local/bin/systemctl_env_test.sh

#

# cat /tmp/systemctl_env_test.log

========================================================

HISTCONTROL=ignoredups

HISTSIZE=1000

HOME=/root

HOSTNAME=jk-server

LANG=zh_CN.UTF-8

LESSOPEN=||/usr/bin/lesspipe.sh %s

LOGNAME=root

LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:

MAIL=/var/spool/mail/root

MY_ENV=helloworld

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

PWD=/root

SELINUX_LEVEL_REQUESTED=

SELINUX_ROLE_REQUESTED=

SELINUX_USE_CURRENT_RANGE=

SHELL=/bin/bash

SHLVL=2

SSH_CLIENT=192.168.187.1 54467 22

SSH_CONNECTION=192.168.187.1 54467 192.168.187.81 22

SSH_TTY=/dev/pts/0

TERM=xterm-color

USER=root

_=/usr/bin/env

XDG_RUNTIME_DIR=/run/user/0

XDG_SESSION_ID=77

========================================================

#

可以看到/etc/profile.d/env.sh中设置的MY_ENV=helloworld能够被脚本/usr/local/bin/systemctl_env_test.sh读取到。

使用systemctl运行systemctl_env_test.service来执行脚本/usr/local/bin/systemctl_env_test.sh时,输出如下:

 

1

2

3

4

5

6

7

8

9

10

11

 

# systemctl start systemctl_env_test.service

#

# cat /tmp/systemctl_env_test.log

========================================================

LANG=zh_CN.UTF-8

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

PWD=/

SHLVL=1

_=/usr/bin/env

========================================================

#

可以看到除了/etc/profile.d/env.sh中设置的MY_ENV=helloworld没有被读取外,连基础的HOSTNAME,SHELL等环境变量都没有。

结论
  • 可以看到shell中运行脚本可以读取到全部正常的环境变量

  • systemd中运行脚本,只读取到最最基础的LANG,PATHPWD几个环境变量, /etc/profile下的环境变量并没有读取。

systemd添加使用环境变量的方法

使用Environment设置环境变量

可以在systemdservice中使用Environment来设置环境变量。

修改原文件/usr/lib/systemd/system/systemctl_env_test.service,使用Environment关键字来添加如下环境变量:

 

1

2

3

 

Environment="One=1" "Three=3"

Environment="Two=2"

Environment="Four=4"

此时/usr/lib/systemd/system/systemctl_env_test.service变为:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

 

[Unit]

Description=systemctl_env_test service

After=syslog.target network.target

[Service]

Type=forking

Environment="One=1" "Three=3"

Environment="Two=2"

Environment="Four=4"

ExecStart=/usr/local/bin/systemctl_env_test.sh

PrivateTmp=false

[Install]

WantedBy=multi-user.target

执行systemctl start后查看脚本env的输出日志,结果如下:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

 

# systemctl start systemctl_env_test.service && cat /tmp/systemctl_env_test.log

========================================================

Four=4

LANG=zh_CN.UTF-8

One=1

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

PWD=/

SHLVL=1

Three=3

Two=2

_=/usr/bin/env

========================================================

#

可以看出systemdservice文件中设置的环境变量,可以被ExecStart指定的脚本读取到。

使用EnvironmentFile导入环境变量文件

使用Environment导入少数固定的环境变量是可行的,但是如果需要导入大量的,或者时常要变动的环境变量,那么使用EnvironmentFile 关键字通过导入文件的方式会更合适。

试验方法如下:

创建测试用环境变量文件/usr/local/etc/environment_file_test/load.conf, 内容如下:

 

1

2

 

MY_ENV="helloworld"

GLOBAL_ENV="nihaoshijie"

修改原文件/usr/lib/systemd/system/systemctl_env_test.service,使用EnvironmentFile关键字来导入文件/usr/local/etc/environment_file_test/load.conf

 

1

 

EnvironmentFile=/usr/local/etc/environment_file_test/load.conf

此时/usr/lib/systemd/system/systemctl_env_test.service变为:

 

1

2

3

4

5

6

7

8

9

10

11

12

 

[Unit]

Description=systemctl_env_test service

After=syslog.target network.target

[Service]

Type=forking

EnvironmentFile=/usr/local/etc/environment_file_test/load.conf

ExecStart=/usr/local/bin/systemctl_env_test.sh

PrivateTmp=false

[Install]

WantedBy=multi-user.target

执行systemctl start后查看脚本env的输出日志,结果如下:

 

1

2

3

4

5

6

7

8

9

10

11

 

# systemctl start systemctl_env_test.service && cat /tmp/systemctl_env_test.log

========================================================

GLOBAL_ENV=nihaoshijie

LANG=zh_CN.UTF-8

MY_ENV=helloworld

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

PWD=/

SHLVL=1

_=/usr/bin/env

========================================================

#

可以看出systemdservice文件中设置的环境变量,可以被ExecStart指定的脚本读取到。

注意: /usr/local/etc/environment_file_test/load.conf文件是配置文件,就是key=value的格式,和/etc/profile.d/中导入的shell文件是不同的,需要加以区别。所以load.conf配置文件中,不能使用export xx=yy的格式

在执行命令或脚本中设置或者source环境变量文件

除了在systemdservice文件中指定EnvironmentEnvironmentFile外,还有一个方法就是在ExecStartExecStop等执行的脚本中直接指定环境变量或者source环境变量文件。

在上面的几个例子中,也可以不在/usr/lib/systemd/system/systemctl_env_test.service文件中使用EnvironmentEnvironmentFile,而是直接在执行的shell脚本/usr/local/bin/systemctl_env_test.shsource /etc/profile.d/environment_file_test.sh

试验方法如下:

修改ExecStart执行的shell脚本/usr/local/bin/systemctl_env_test.sh, 在里面添加source /etc/profile.d/env.sh , 添加后的文件内容为:

 

1

2

3

4

5

6

 

#!/bin/bash

LOG_FILE="/tmp/systemctl_env_test.log"

echo "========================================================" > $LOG_FILE

source /etc/profile.d/env.sh

env | sort >> $LOG_FILE

echo "========================================================" >> $LOG_FILE

其中/etc/profile.d/env.sh文件的内容如下:

 

1

 

export MY_ENV="helloworld"

还原文件/usr/lib/systemd/system/systemctl_env_test.service去除EnvironmentEnvironmentFile的设置,变为:

 

1

2

3

4

5

6

7

8

9

10

11

 

[Unit]

Description=systemctl_env_test service

After=syslog.target network.target

[Service]

Type=forking

ExecStart=/usr/local/bin/systemctl_env_test.sh

PrivateTmp=false

[Install]

WantedBy=multi-user.target

执行systemctl start后查看脚本env的输出日志,结果如下:

 

1

2

3

4

5

6

7

8

9

10

 

# systemctl start systemctl_env_test.service && cat /tmp/systemctl_env_test.log

========================================================

LANG=zh_CN.UTF-8

MY_ENV=helloworld

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

PWD=/

SHLVL=1

_=/usr/bin/env

========================================================

#

可以看出也能加载出MY_ENV这个环境变量。

注意这边是shell脚本中source /etc/profile.d/env.sh, 所以文件中需要加上export,父shell才能读取对应的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值