Cron in Docker Alpine image

Explaining about setting up cron daemon in Docker Alpine image 🐳⏰

Cron in Docker Alpine image

Today I wasted hours solving this funny problem, so now I'm sharing a soulution I would have liked to find myself on Google hours earlier.

My goal was to use the node:alpine Docker image to run my Node.js app, but also run regularly another script in background using cron.


First, where are the crontabs saved in Alpine? They are saved to  /var/spool/cron/crontabs/. To figure out this yourself you can run the command crond --help, which brings up the following:

Usage: crond [-fbS] [-l N] [-d N] [-L LOGFILE] [-c DIR]
    -f      Foreground
    -b      Background (default)
    -S      Log to syslog (default)
    -l N    Set log level. Most verbose 0, default 8
    -d N    Set log level, log to stderr
    -L FILE Log to FILE
    -c DIR  Cron dir. Default:/var/spool/cron/crontabs

You can see the default location on the last line. You can append your commands for example into file at /var/spool/cron/crontabs/root. I appended mine using the Dockerfile like so:

RUN echo "* * * * * /bin/bash /usr/src/app/scripts/" >> /var/spool/cron/crontabs/root


In my case, I wanted to run cron concurrently with the Node.js app. I replaced my last Dockerfile CMD line to:

CMD crond && npm start

This will start cron daemon in background (which is the default mode) and after that run my node app.

If you want your image to run just the crond and nothing else, you may want to run the cron daemon in foreground like so:

CMD crond -f

If you want it to talk to you and show the output, check the longer command below in debugging section.

Cron daemon must run as the root user. If you have USER commands in your Dockerfile, they may be the reason your cron is failing.


Now the fun part! Doesn't work? This is how I debugged.

The logs usually tell what's wrong, therefore we have to get to the logs. Run cron daemon using:

# crond -f -l 2 -L /dev/stdout

The -f brings the cron daemon to the foreground. The -l 2 sets the log level, most verbose is 0 and the default is 8. The big -L tells where to save, and with this we have redirected the output to the stdout.

Running this we should see the d(a)emon's output right in our terminal. Keep your eye on the errors and use your Stack Overflow problem solving skills to your advantage.