1

1) I am running a docker container with following cmd (passing few env variables with -e option)

$ 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) After running the container as above, i check the env variable NWMODE inside the container, and it shows correctly as shown below :

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

3) Now, i created a sample service 'b' shown below which executes a script b.sh (where i try to access 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) Now if i start service 'b' and see its logs, it shows that it is not able to access NWMODE env variable

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

5) Now rather than having 'systemctl import-environment' in b.sh, if i do following then the b.service logs show the correct value of NWMODE env variable: $ systemctl import-environment $ systemctl start b

Though the step 5 above works i can't go for it, as all the services in my system will be started automatically by systemd. In that case, can anyone please let me know how can i access the environment variables (passed using 'docker run...' cmd above) in a service file (say for e.g. in b.sh above). Can this be achieved somehow with systemctl import-environment or there is some other way ?

user111
  • 33
  • 1
  • 7
  • Are you sure your service is not being started before the environment variables are being set? I'll bet it is. If that is the case you need to make some dependencies for systemd so it starts at the appropriate time. – Matt Runion Sep 29 '18 at 19:17
  • @mrunion : env variables are set the moment i run the `docker run...` cmd. In the above example, i am trying to run the service manually. Even before running the service manually, i have shown above that the env variable exists. – user111 Sep 29 '18 at 19:26

2 Answers2

1

systemd unsets all environment variables to provide a clean environment. Afaik that is intended to be a security feature.

Workaround: Create a file /etc/systemd/system.conf.d/myenvironment.conf:

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

systemd will set the environment variables declared in this file.

You can set up an ENTRYPOINT script that automatically creates this file before running systemd. Example:

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

Instead of creating the script within Dockerfile you can store it outside and add it with 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
Community
  • 1
  • 1
mviereck
  • 1,309
  • 1
  • 12
  • 15
0

TL;DR

Run the the command using bash, first store the docker environment variables to a file (or just pipe them two awk), extract & export the variable and finally run your main script.

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"


Whatever @mviereck is saying is true, still I have found another solution to this problem.

My use case is to pass an environment variable to my system-d container in the Docker run command (docker run -e MY_ENV_VARIABLE="some_val") and use that in the python script that is run through the system-d unit file.

According to this post (https://forums.docker.com/t/where-are-stored-the-environment-variables/65762) the container environment variables can be found in the running process /proc/1/environ inside the container. Performing a cat does show that the environment variable MY_ENV_VARIABLE=some_val does exist, though in some mangled form.

$ cat /proc/1/environ

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

The main task now would be to extract MY_ENV_VARIABLE="some_val" value and pass it to the ExecStart directive in the system-d unit file.

(extraction code referenced from 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

Now in the ExecStart directive in the system-d unit file we can do this:

[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"

Rafay Khan
  • 1,070
  • 13
  • 25