Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access Docker set Environment Variables From a Cron Job

I've recently tried running a cron job from within a linked docker container and run into an issue. My main docker container is linked to a postgres container and its port number is set as an environment variable by docker upon the containers creation. This environment variable is not set in ~/.profile or any other source file that I could load when running my cron job. How can I then access these environment variables from my cron job?

Thanks!

like image 342
Fabio Berger Avatar asked Jan 05 '15 00:01

Fabio Berger


People also ask

Can crontab access environment variables?

You can define environment variables in the crontab itself when running crontab -e from the command line. This feature is only available to certain implementations of cron.

How do I access docker environment variables?

Fetch Using docker exec Command Here, we are executing the /usr/bin/env utility inside the Docker container. Using this utility, you can view all the environment variables set inside Docker containers.

How do I see environment variables in running container?

The --env option is used to pass the environment variable called ENVVARIABLE with a value foobar to the container. Now you have access to the bash of the container. Inside the bash, execute the env command. This will list all the environment variables of the container.


7 Answers

I ran into this same problem. I have a docker container that runs cron to execute some shell scripts periodically. I too had a hard time finding out why my scripts would run fine when I manually executed them inside the container. I tried all the tricks of creating a shell script that would run first to set the environment, but they never worked for me (most likely I did something wrong). But I continued looking and found this and it does work.

  1. Setup a start or entry point shell script for your cron container
  2. Make this the first line to execute printenv | grep -v "no_proxy" >> /etc/environment

The trick here is the /etc/environment file. When the container is built that file is empty, I think on purpose. I found a reference to this file in the man pages for cron(8). After looking at all the versions of cron they all elude to an /etc/? file that you can use to feed environment variables to child processes.

Also, note that I created my docker container to run cron in the foreground, cron -f. This helped me avoid other tricks with tail running to keep the container up.

Here is my entrypoint.sh file for reference and my container is a debian:jessie base image.

printenv | grep -v "no_proxy" >> /etc/environment

cron -f

Also, this trick worked even with environment variables that are set during, docker run commands.

like image 139
Tim Schruben Avatar answered Sep 30 '22 16:09

Tim Schruben


I would recommend using declare to export your environment and avoid escaping issues. Can be used in CMD or ENTRYPOINT or directly in a wrapper script which might be called by one of them:

declare -p | grep -Ev 'BASHOPTS|BASH_VERSINFO|EUID|PPID|SHELLOPTS|UID' > /container.env

Grep -v takes care of filtering out read-only variables.

You can later easily load this environment like this:

SHELL=/bin/bash
BASH_ENV=/container.env
* * * * * root /test-cron.sh
like image 38
Alex Fedulov Avatar answered Sep 30 '22 16:09

Alex Fedulov


One can append the system environment variables to the top of a crontab file by using wrapper shell script to run the cron daemon. The following example is from CentOs 7,

In the Dockerfile

COPY my_cron /tmp/my_cron
COPY bin/run-crond.sh run-crond.sh
RUN chmod -v +x /run-crond.sh
CMD ["/run-crond.sh"]

run_cron.sh:

#!/bin/bash

# prepend application environment variables to crontab
env | egrep '^MY_VAR' | cat - /tmp/my_cron > /etc/cron.d/my_cron

# Run cron deamon
# -m off : sending mail is off 
# tail makes the output to cron.log viewable with the $(docker logs container_id) command
/usr/sbin/crond -m off  && tail -f /var/log/cron.log

This is based on a great blog post somewhere, but I lost the link.

like image 35
Michael Moyle Avatar answered Sep 30 '22 18:09

Michael Moyle


You can run the following command

. <(xargs -0 bash -c 'printf "export %q\n" "$@"' -- < /proc/1/environ)

This is exceptionally works when you have the environment variables with special characters like ' " =

like image 44
Kannan Kumarasamy Avatar answered Sep 30 '22 18:09

Kannan Kumarasamy


inspired by @Kannan Kumarasamy answer:

  for variable_value in $(cat /proc/1/environ | sed 's/\x00/\n/g'); do
    export $variable_value
  done

I can't state for sure, what process with pid1 is and that its stable during lifetime of OS. but as it is the first process to be run, inside a container i guess we can take it for granted it is a process with desired env vars set. take all of this with pich of salt unless some linux/docker docs proves this is completely ok.

like image 32
Ondřej Želazko Avatar answered Sep 30 '22 18:09

Ondřej Želazko


The environment is set, but not available to the cron job. To fix that, you can do these two simple things

1) Save the env to a file in your ENTRYPOINT or CMD

CMD env > /tmp/.MyApp.env && /bin/MyApp

2) Then read that env into your cron command like this:

0 5 * * * . /tmp/.MyApp.env; /bin/MyApp
like image 31
Mark Riggins Avatar answered Sep 30 '22 17:09

Mark Riggins


You should export your environment variable before you run cronjobs.

Other solutions are fine but they will fail when there are any special characters in your environment variable.

I have found the solution:

eval $(printenv | awk -F= '{print "export " "\""$1"\"""=""\""$2"\"" }' >> /etc/profile)

like image 29
Amul Avatar answered Sep 30 '22 18:09

Amul