Docker, cron, environment variables, and Kubernetes
I recently mentioned that I am running cron in some of the docker containers I need for a new service. Now that we moved to Kubernetes and Rancher for deployment, I moved most of the configuration into Kubernetes ConfigMaps, and expose the key/value pairs their as environment variables. Sounded like a good idea, but …
but well, reading the documentation would have helped. Cron scripts do not see the normal environment of the surrounding process (cron, init, whatever), but get a cleaned up environment. As a consequence, none of the configuration keys available in the environment did show up in the cron jobs – and as a consequence they badly failed of course 😉
After some thinking and reading, I came up with two solutions, one “Dirty Harry^WNorby” solution and one clean and nice, but annoying solution.
Dirty Harry^WNorby solution
What is available in the environment of the cron jobs is minimal, and in fact more or less what is defined in /etc/environment
and stuff set by the shell (if it is a shell script). So the solution was adding the necessary variable definitions to /etc/environment
in a way that they are properly set. For that, I added the following code in the start-syslog-cron
script that is the entry point of the container:
# prepare for export of variables to cron jobs
if [ -r /env-vars-to-be-exported ]
then
for i in `cat /env-vars-to-be-exported`
do
echo "$i=${!i}" >> /etc/environment
done
fi
Meaning, if the container contains a file /env-vars-to-be-exported
then the lines of it are considered variable names and are set in the environment with the respective values at the time of invocation.
Using this quick and dirty trick it is now dead-easy to get the ConfigMap variables into the cron job’s environment by adding the necessary variables names to the file /env-vars-to-be-exported
. Thus, no adaption of the original source code was necessary – a big plus!
Be warned, there is no error checking etc, so one can mess up the container quite easily 😉
Standards solution
The more standard and clean solution is mounting the ConfigMap and reading the values from the exported files. This is possible, has the big advantage that one can change the values without restarting the containers (mounted ConfigMaps are updated when the ConfigMaps are changed – besides a few corner cases), and no nasty trickery in the initialization.
Disadvantage is that the code of the cron jobs needs to be changed to read the variables from the config files instead of the environment.
Have you considered mapping all key-value pairs from CM as environment variables in the Pod (https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#use-configmap-defined-environment-variables-in-pod-commands)?
This is already happening, of course, otherwise the script wouldn’t work. The point is that env vars are normally not accessible in cron jobs!!! I want to forward them from the docker container to the crib jobs.
Have you considered using Kubernetes CronJobs instead? https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
Good point I have to write about, too. Yes I have, yes I had all the jobs converted to Kubernetes CronJobs. And yes, it killed Ranger and Kubernetes, left many containers having around, there is no proper error reporting, … Been there, tried it, given up on it.