I would like to run a python cron job inside of a docker container in detached mode. My set-up is below:
My python script is test.py
#!/usr/bin/env python import datetime print "Cron job has run at %s" %datetime.datetime.now()
My cron file is my-crontab
* * * * * /test.py > /dev/console
and my Dockerfile is
FROM ubuntu:latest RUN apt-get update && apt-get install -y software-properties-common python-software-properties && apt-get update RUN apt-get install -y python cron ADD my-crontab / ADD test.py / RUN chmod a+x test.py RUN crontab /my-crontab ENTRYPOINT cron -f
What are the potential problems with this approach? Are there other approaches and what are their pros and cons?
Several issues that I faced while trying to get a cron job running in a docker container were:
There are cron-specific issues and are docker-specific issues in the list, but in any case they have to be addressed to get cron working.
To that end, my current working solution to the problem posed in the question is as follows:
Create a docker volume to which all scripts running under cron will write:
# Dockerfile for test-logs # BUILD-USING: docker build -t test-logs . # RUN-USING: docker run -d -v /t-logs --name t-logs test-logs # INSPECT-USING: docker run -t -i --volumes-from t-logs ubuntu:latest /bin/bash FROM stackbrew/busybox:latest # Create logs volume VOLUME /var/log CMD ["true"]
The script that will run under cron is test.py
:
#!/usr/bin/env python # python script which needs an environment variable and runs as a cron job import datetime import os test_environ = os.environ["TEST_ENV"] print "Cron job has run at %s with environment variable '%s'" %(datetime.datetime.now(), test_environ)
In order to pass the environment variable to the script that I want to run under cron, follow Thomas' suggestion and put a crontab fragment for each script (or group of scripts) that has need of a docker environment variable in /etc/cron.d
with a placeholder XXXXXXX
which must be set.
# placed in /etc/cron.d # TEST_ENV is an docker environment variable that the script test.py need TEST_ENV=XXXXXXX # * * * * * root python /test.py >> /var/log/test.log
Instead of calling cron directly, wrap cron in a python script that does does things: 1. reads the environment variable from the docker environment variable and sets the environment variable in a crontab fragment.
#!/usr/bin/env python # run-cron.py # sets environment variable crontab fragments and runs cron import os from subprocess import call import fileinput # read docker environment variables and set them in the appropriate crontab fragment environment_variable = os.environ["TEST_ENV"] for line in fileinput.input("/etc/cron.d/cron-python",inplace=1): print line.replace("XXXXXXX", environment_variable) args = ["cron","-f", "-L 15"] call(args)
The Dockerfile
that for the container in which the cron jobs run is as follows:
# BUILD-USING: docker build -t test-cron . # RUN-USING docker run --detach=true --volumes-from t-logs --name t-cron test-cron FROM debian:wheezy # # Set correct environment variables. ENV HOME /root ENV TEST_ENV test-value RUN apt-get update && apt-get install -y software-properties-common python-software-properties && apt-get update # Install Python Setuptools RUN apt-get install -y python cron RUN apt-get purge -y python-software-properties software-properties-common && apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ADD cron-python /etc/cron.d/ ADD test.py / ADD run-cron.py / RUN chmod a+x test.py run-cron.py # Set the time zone to the local time zone RUN echo "America/New_York" > /etc/timezone && dpkg-reconfigure --frontend noninteractive tzdata CMD ["/run-cron.py"]
Finally, create the containers and run them:
docker build -t test-logs .
docker run -d -v /t-logs --name t-logs test-logs
docker build -t test-cron .
docker run --detach=true --volumes-from t-logs --name t-cron test-cron
docker run -t -i --volumes-from t-logs ubuntu:latest /bin/bash
. The log files are in /var/log
.Here is a complement on rosksw answer.
There is no need to do some string replacement in the crontab file in order to pass environment variables to the cron jobs.
It is simpler to store the environment variables in a file when running the contrainer, then load them from this file at each cron execution. I found the tip here.
In the dockerfile:
CMD mkdir -p /data/log && env > /root/env.txt && crond -n
In the crontab file:
* * * * * root env - `cat /root/env.txt` my-script.sh
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