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:
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