Igor's Techno Club

Minimal Dockerized Cron Template

While Docker is mainly used to containerize stateless applications, there might be cases where you need scheduled tasks inside your container. For example, quite often I use it for small automated tasks, such as site updates, database cleanups, and so on. The main reason I prefer this approach is that it becomes really easy to move it to another hosting provider whenever you find a cheaper one.

Implementation notes

Dockerfile

  1. Base Image and Updates:

    FROM ruby:3.1
    RUN apt-get update
    RUN apt-get install -y cron
    

    Since for my tasks I use Ruby, I use here Ruby Docker image where I install the Cron daemon in a separate step.

  2. Setting Up the Working Directory and Files:

    WORKDIR /app
    COPY run.sh /app/
    COPY run-cron /app/run-cron
    

    This sets /app as the working directory. The files run.sh and run-cron are copied into /app. run.sh contains the script to be executed by Cron, and run-cron is the crontab file which schedules when run.sh will be run.

  3. Configuring Cron:

    RUN cp /app/run-cron /etc/cron.d/run-cron
    RUN chmod 0644 /etc/cron.d/run-cron
    RUN crontab /etc/cron.d/run-cron
    

    The Cron configuration file is moved to /etc/cron.d and set with the correct permissions. The crontab command adds the schedule from run-cron into the Crontab.

  4. Logging Setup:

    RUN touch /var/log/cron.log
    CMD cron && tail -f /var/log/cron.log
    

    An empty log file is created and the CMD command starts the Cron daemon along with tailing the log file. This enables the logs to be streamed to the Docker container logs, which can be very useful for debugging.

Logs redirections

Debugging failing cron jobs could be a burden, so I redirect the output and errors from the Cron job are sent to the standard output and error streams of the container by doing:

0 0 * * * /app/run.sh > /proc/1/fd/1 2>/proc/1/fd/2

Running

All you left to do is to build an image and run it in detached mode

The Full Template

Dockerfile

FROM ruby:3.1

RUN apt-get update
RUN apt-get install -y cron


WORKDIR /app

COPY run.sh /app/
COPY run-cron /app/run-cron

RUN cp /app/run-cron /etc/cron.d/run-cron
RUN chmod 0644 /etc/cron.d/run-cron
RUN crontab /etc/cron.d/run-cron

RUN touch /var/log/cron.log

CMD cron && tail -f /var/log/cron.log

run-cron

0 0 * * * /app/run.sh > /proc/1/fd/1 2>/proc/1/fd/2

run.sh

echo "Hello cron!"

#bash #docker #show