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:

  1. Source your image from a container which has cron installed.
  2. 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
Blog Logo

Mario Loria


Published

Image

./scriptthe.net

Because 127.0.0.1 gets old after a while.

Back to Overview