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
Mario Loria is a builder of diverse infrastructure with modern workloads on both bare-metal and cloud platforms. He's traversed roles in system administration, network engineering, and DevOps. You can learn more about him here.