访问 systemd 服务文件中的 docker 环境变量时出现问题

问题描述 投票:0回答:2

1)我正在使用以下cmd运行docker容器(使用-e选项传递一些环境变量)

$ docker run --name=xyz -d -e CONTAINER_NAME=xyz -e SSH_PORT=22 -e NWMODE=HOST -e XDG_RUNTIME_DIR=/run/user/0 --net=host -v /mnt:/mnt -v /dev:/dev -v /etc/sysconfig/network-scripts:/etc/sysconfig/network-scripts -v /:/hostroot/ -v /etc/hostname:/etc/host_hostname -v /etc/localtime:/etc/localtime -v /var/run/docker.sock:/var/run/docker.sock --privileged=true cf3681e04bfb

2)按上述方式运行容器后,我检查容器内的环境变量 NWMODE,它显示正确,如下所示:

$ docker exec -it xyz bash
$ env | grep NWMODE
NWMODE=HOST

3)现在,我创建了一个示例服务“b”,如下所示,它执行脚本 b.sh(我尝试访问 NWMODE):

root@ubuntu16:/etc/systemd/system# cat b.service
[Unit]
Description=testing service b

[Service]
ExecStart=/bin/bash /etc/systemd/system/b.sh

root@ubuntu16:/etc/systemd/system# cat b.sh
#!/bin/bash`
systemctl import-environment
echo "NWMODE:" $NWMODE`

4)现在,如果我启动服务“b”并查看其日志,它表明它无法访问 NWMODE 环境变量

$ systemctl start b
$ journalctl -fu b
...
systemd[1]: Started testing service b.
bash[641]: NWMODE:      //blank for $NWMODE here`

5)现在,如果我执行以下操作,则 b.service 日志将显示 NWMODE 环境变量的正确值,而不是在 b.sh 中使用“systemctl import-environment”:

$ systemctl import-environment
$ systemctl start b

虽然上面的步骤 5 有效,但我不能这样做,因为我系统中的所有服务都将由 systemd 自动启动。在这种情况下,任何人都可以让我知道如何访问服务文件中的环境变量(使用上面的“docker run...”cmd 传递)(例如上面的 b.sh 中)。这可以通过

systemctl import-environment
以某种方式实现吗?或者还有其他方法吗?

docker ubuntu-16.04 systemd
2个回答
1
投票

systemd 取消设置所有环境变量以提供干净的环境。 Afaik 这旨在成为一项安全功能。

解决方法:创建一个文件

/etc/systemd/system.conf.d/myenvironment.conf

[Manager]
DefaultEnvironment=CONTAINER_NAME=xyz NWMODE=HOST XDG_RUNTIME_DIR=/run/user/0

systemd 将设置此文件中声明的环境变量。

您可以设置一个

ENTRYPOINT
脚本,在运行
systemd
之前自动创建此文件。示例:

RUN echo '#! /bin/bash \n\
echo "[Manager] \n\
DefaultEnvironment=$(while read -r Line; do echo -n "$Line" ; done < <(env)) \n\
" >/etc/systemd/system.conf.d/myenvironment.conf \n\
exec /lib/systemd/systemd \n\
' >/usr/bin/setmyenv && chmod +x /usr/bin/setmyenv

ENTRYPOINT /usr/bin/setmyenv

您可以将其存储在外部并使用

Dockerfile
添加它,而不是在
COPY
中创建脚本:

#! /bin/bash
echo "[Manager]
DefaultEnvironment=$(while read -r Line; do echo -n "$Line" ; done < <(env))
" >/etc/systemd/system.conf.d/myenvironment.conf
exec /lib/systemd/systemd

0
投票

TL;博士

使用 bash 运行命令,首先将 docker 环境变量存储到文件中(或者只是通过管道将它们两个

awk
),提取并导出变量,最后运行主脚本。

ExecStart=/bin/bash -c "cat /proc/1/environ | tr '\0' '\n' > /home/env_file; export MY_ENV_VARIABLE=$(awk -F= -v key="MY_ENV_VARIABLE" '$1==key {print $2}' /home/env_file); /usr/bin/python3 /usr/bin/my_python_script.py"


无论@mviereck所说的是真的,我仍然找到了解决这个问题的另一种解决方案。

我的用例是在 Docker 运行命令 (

docker run -e MY_ENV_VARIABLE="some_val"
) 中将环境变量传递到我的 system-d 容器,并在通过 system-d 单元文件运行的 python 脚本中使用它。

根据这篇文章(https://forums.docker.com/t/where-are-stored-the-environment-variables/65762)容器环境变量可以在运行进程中找到

/proc/1/environ
容器。执行
cat
确实表明环境变量
MY_ENV_VARIABLE=some_val
确实存在,尽管以某种损坏的形式存在。

$ cat /proc/1/environ

HOSTNAME=271fbnd986bdMY_ENV_VARIABLE=some_valcontainer=dockerLC_ALL=CDEBIAN_FRONTEND=noninteractiveHOME=/rootroot@271fb0d986bd

现在的主要任务是提取

MY_ENV_VARIABLE="some_val"
值并将其传递给 system-d 单元文件中的
ExecStart
指令。

(提取代码引用自How to grep for value in a key-value store from plain text

# this outputs a nice key,value pair
$ cat /proc/1/environ | tr '\0' '\n'

HOSTNAME=861f23cd1b33
MY_ENV_VARIABLE=some_val
container=docker
LC_ALL=C
DEBIAN_FRONTEND=noninteractive
HOME=/root

# we can store this in a file for use, too
$ cat /proc/1/environ | tr '\0' '\n' > /home/env_var_file

# we can then reuse the file to extract the value of interest against a key
$ awk -F= -v key="MY_ENV_VARIABLE" '$1==key {print $2}' /home/env_file

some_val

现在,在 system-d 单元文件中的

ExecStart
指令中,我们可以执行以下操作:

[Service]
Type=simple
ExecStart=/bin/bash -c "cat /proc/1/environ | tr '\0' '\n' > /home/env_file; export MY_ENV_VARIABLE=$(awk -F= -v key="MY_ENV_VARIABLE" '$1==key {print $2}' /home/env_file); /usr/bin/python3 /usr/bin/my_python_script.py"

© www.soinside.com 2019 - 2024. All rights reserved.