Tailored cloud financial management solutions.
Manage the end-to-end delivery of IT services to customers successfully.
Complete cloud migration services for the public sector.
Transforming the financial services sector with industry-leading cloud and data solutions.
Delivering compliant and secure cloud automation solutions for the Public sector.
Other sectors that we currently have clients within include insurance, media, retail, construction and automotive.
Our team of industry-leading experts deliver world-leading transformation solutions.
We would love to talk about transforming your business. Please let us know.
Our latest industry news, insights, employee stories, and upcoming events.
2021-03-18 00:00:00
On a recent project, I came across a problem where I needed to run a cron job inside a pod.
The cron job had to connect to a database to do its thing and all the information required for the script was already available in the pod’s environment variables.
Now I know there is a Kubernetes CronJob resource that can be used, but this quick blog post is based on the use case of just a normal Linux cron job, inside a Kubernetes pod, that requires access to environment variables.
All the code is available here if required:
https://github.com/vishbhalla/cron-in-a-pod
Let’s run through a simple example. Below is noddy script that echoes the contents of an environment variable imaginatively called $MY_ENV_VARIABLE:
if [[ -z $MY_ENV_VARIABLE ]]; then echo "MY_ENV_VARIABLE is empty!" else echo $MY_ENV_VARIABLE fi
Below is a cron line that can be installed in Linux in order to run that script and output the results to a log file:
* * * * * bash -c '/tmp/echo_env.sh' >> /tmp/cron.log 2>&1
Now here is a Dockerfile that runs Ubuntu, copies the above files over, installs the cron job to run the script, and then tails the log file created by the cron job:
# Use a full fat linux image: FROM ubuntu:latest # Upload our local files to /tmp in the container: COPY ./echo_env.* /tmp/ # Install cron as it's not installed by the above image as default: RUN apt-get update && apt upgrade -y && apt-get install -y cron # Make the cron script executable, and touch the log file it will be writing to: RUN chmod +x /tmp/echo_env.sh && touch /tmp/cron.log # Install our cron job in root user's crontab, using the file we copied over above: RUN crontab -u root /tmp/echo_env.cron # Start the container by starting the cron service, and spit out the logfile the cron should be writing to: ENTRYPOINT service cron start && tail -f /tmp/cron.log
I’m working locally with minikube, so I can build via:
# eval $(minikube docker-env)
# docker build . -t echo_env
Lastly, here is a Kubernetes manifest that simply starts a pod with the above docker image, setting the value of our wonderfully named environment variable:
apiVersion: v1 kind: Pod metadata: name: echo-env spec: containers: - name: echo-env image: echo_env:latest imagePullPolicy: Never env: - name: MY_ENV_VARIABLE value: "Hello from the environment"
So we can now apply the manifest via:
# kubectl apply -f ./pod.yaml
And see the the output of the cron job every minute via:
# kubectl logs echo-env -f
As you can see:
* Starting periodic command scheduler cron
…done.
MY_ENV_VARIABLE is empty!
Why? Because Cron is designed to run in its own fresh shell, with limited environment variables. So we need to find a way of grabbing them from the pod’s environment, and making them available to the cron job.
One way to achieve this is to have the pod spit out all the environment variables into a file and make them available upon start up. Take a look at the ENTRYPOINT in the below Dockerfile:
# Use a full fat linux image: FROM ubuntu:latest # Upload our local files to /tmp in the container: COPY ./echo_env.* /tmp/ # Install cron as it's not installed by the above image as default: RUN apt-get update && apt upgrade -y && apt-get install -y cron # Make the cron script executable, and touch the log file it will be writing to: RUN chmod +x /tmp/echo_env.sh && touch /tmp/cron.log # Install our cron job in root user's crontab, using the file we copied over above: RUN crontab -u root /tmp/echo_env.cron # Start the container by starting the cron service, and spit out the logfile the cron should be writing to: ENTRYPOINT export -p | grep -v LS_COLORS > /tmp/env.sh && service cron start && tail -f /tmp/cron.log
I’ve excluded the environment variable LS_COLORS above simply because there are some special characters in it, and I didn’t need access it, so safer to just remove it.
Now we can edit the cron job to execute this file before running the script:
* * * * * bash -c '. /tmp/env.sh && /tmp/echo_env.sh' >> /tmp/cron.log 2>&1
So after building our new docker image, and spinning up a new, updated pod, you should now see the variable being correctly reported in the logs:
* Starting periodic command scheduler cron
…done.
Hello from the environment
With this being a Ubuntu image, the better way to obtain the environment variables would be to stick them into /etc/environment via something like:
# env > /etc/environment
But I chose the approach I did as it should work with any Linux variant.