Sometimes, you need an application to run at a scheduled time. Ideally, it would be a really cool feature if you could merely tell the docker daemon to do this via some sort of schedule: * 1 * * *
in your docker-compose.yml
. Sadly this isn’t really possible. So you have two options:
- Source your image from a container which has cron installed.
- Merely install cron yourself.
Either way, there are a few things you need to watch out for. Here, I will provide some examples of the way I take to setting up a scheduled task for a particular service.
Installing cron
On most ubuntu based images, you can just do an apt-get install cron
. phusion-baseimage goes the extra mile and removes unnecessary files:
RUN apt-get -y install cron
RUN rm -f /etc/cron.daily/standard \
rm -f /etc/cron.daily/upstart \
rm -f /etc/cron.daily/dpkg \
rm -f /etc/cron.daily/password \
rm -f /etc/cron.weekly/fstrim
Setting a workdir for your cronjob
I recommend offering a variable that looks like this:
WORKDIR=${WORKDIR:-`pwd`}
That allows someone to change the workdir at runtime but also assumes the default workdir defined in the dockerfile by default.
Defining the Schedule
I like to simply provide the ability to define the scheduling at runtime via a variable:
CRON_SCHEDULE=${CRON_SCHEDULE:-0 1 * * *}
Here, we set a default of 1am nightly.
Application Logging
Wouldn’t it be really nice if the application cron executes could just log to stdout/stderr of the container?
STDOUT_LOC=${STDOUT_LOC:-/proc/1/fd/1}
STDERR_LOC=${STDERR_LOC:-/proc/1/fd/2}
We are basically able to redirect output to the stdout/stderr of the init process (pid 1) pipe!
Bringing it all together
Most of the above is contained in a run/start.sh file that I call via the CMD declaration in my Dockerfile. Putting this all together sees a result similar to the following:
#!/bin/bash
set -e
WORKDIR=${WORKDIR:-`pwd`}
CRON_SCHEDULE=${CRON_SCHEDULE:-0 1 * * *}
STDOUT_LOC=${STDOUT_LOC:-/proc/1/fd/1}
STDERR_LOC=${STDERR_LOC:-/proc/1/fd/2}
echo "${CRON_SCHEDULE} cd ${WORKDIR} && ./awesomescript.py > ${STDOUT_LOC} 2> ${STDERR_LOC}" | crontab -
exec cron -f
Final Notes
For anyone wondering if they could just ADD
a file to /etc/cron.d
? The answer is absolutely! Keep in mind the following:
- The file you add must have
644
permissions. - It doesn’t have to be executable because it isn’t actually a script.
- You can name it whatever you want i.e.
timely_script
- You can, and are encouraged, to define a
PATH
variable for crons in this file.
Here is an example:
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
*/5 * * * * root if [ -d /etc/backup.d ]; then chmod 700 /etc/backup.d && chown -R root:root /etc/backup.d && chmod 600 /etc/backup.d/*; fi
*/5 * * * * root /usr/sbin/awesomescript.py