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!
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.
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.
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.
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.
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.
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
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.
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 '
"
=
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.
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
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With