Docker, cron, mail and logs

If one searches for “docker cron“, there are a lot of hits but not really good solutions or explanations how to get a running system. In particular, what I needed/wanted was (i) stdout/stderr of the cron script is sent to some user, and (ii) that in case of errors the error output also appears in the docker logs. Well, that was not that easy …

There are three components here that need to be tuned:

  • getting cron running
  • getting mail delivery running
  • redirecting some error message to docker

Let us go through the list. The full Dockerfile and support scripts can be found below.

Getting cron running

Many of the lean images do not contain cron, even less run it (this is due to the philosophy of one process per container). So the usual incantation to install cron are necessary:

RUN apt-get install -y cron

After that, one can use as entry point the cron daemon running in foreground:

CMD cron -f

Of course you have to install a crontab file somehow, in my case I did:

ADD crontab /etc/cron.d/mypackage
RUN chmod 0644 /etc/cron.d/mypackage

This works all nice and well, but if there are errors, or problems with the crontab file, you will not see any error message, because (at least on Debian and Ubuntu) cron logs to syslog, but there is no syslog daemon available to show you the output, and cron has no option to log to a file (how stupid!). Furthermore, other cron daemon options (bcron, cronie) are not available in Debian/stable for example 🙁

In my case the crontab file had a syntax error, and thus no actual program was ever run.

Getting mail delivery running

Assuming you have these hurdles settled one would like to get the output of the cron scripts mailed. For this, a sendmail compliant program needs to be available. One could set up a full blown system (exim, postfix), but this is overkill as one only wants to send out message. I opted for ssmtp which is a single program with straight-forward configuration and operation, and it provides a sendmail program.

RUN apt-get install -y ssmtp
ADD ssmtp.conf /etc/ssmtp/ssmtp.conf
RUN chown root.mail /etc/ssmtp/ssmtp.conf
RUN chmod 0640 /etc/ssmtp/ssmtp.conf

The configuration file can be rather minimal, here is an example:

Root=destuser@destination
mailhub=mail-server-name-ip

Of course, the mail-server-name-ip must accepts emails for destuser@destination. There are several more options for ssl support, rewriting of domains etc, see for example here.

Having this in place, cron will now duly send emails with the output of the cron jobs.

Redirecting some error message to docker

This leaves us with the last task, namely getting error messages into the docker logs. Since cron does capture the stdout and stderr of the cronjobs for mail sending, one can either redirect these outputs to docker, but then one will not get emails, or wrap the cron jobs up. I used the following wrapper to output a warning to the docker logs:

#!/bin/bash
#
if [ -z "$1" ] ; then
  echo "need name of cron job as first argument" >&2
  exit 1
fi

if [ ! -x "$1" ] ; then
  echo "cron job file $1 not executable, exiting" >&2
  exit 1
fi

if "$1"
then
  exit 0
else
  echo "cron job $1 failed!" 2>/proc/1/fd/2 >&2
  exit 1
fi

together with entries in the crontab like:

m h d m w root /app/run-cronjob /app/your-script

The magic trick here is the 2>/proc/1/fd/2 >&2 which first redirects the stderr to the stderr of the process with the id 1, which is the entry point of the container and watched by docker, and then echo the message to stderr. One could also redirect stdout in the same way to /proc/1/fd/1 if necessary or preferred.


The above thing combined gives a nice combination of emails with the output of the cron jobs, as well as entries in the docker logs if something broke and for example no output was created.

Let us finish with a minimal Dockerfile doing these kind of things:

from debian:stretch-slim
RUN apt-get -y update
RUN apt-get install -y cron ssmtp
ADD . /app
ADD crontab /etc/cron.d/mypackage
RUN chmod 0644 /etc/cron.d/mypackage
ADD ssmtp.conf /etc/ssmtp/ssmtp.conf
RUN chown root.mail /etc/ssmtp/ssmtp.conf
RUN chmod 0640 /etc/ssmtp/ssmtp.conf
CMD cron -f

3 Responses

  1. We managed to get cron’s errors in docker logs via busybox-syslogd. The entry point is a shell script that does

    #!/bin/sh
    syslogd -O /proc/1/fd/1 -S
    exec cron -f -L 15

    and now problems with crontab permissions/syntax no longer go unnoticed.

Leave a Reply

Your email address will not be published. Required fields are marked *