Featured image of post How to run cron jobs in a container for easy portability

How to run cron jobs in a container for easy portability

Creating a container to run cron jobs

Follow me

Introduction Link to this section

I wanted a container to run my cron jobs in a way that I could easily migrate them to a new server just running a docker compose and that I didn’t have to rebuild the image every time I needed to create a new cron job. I didn’t found the solution the way I wanted, so I built it myself and, in this post, I will share how to do it.

Creating the docker image Link to this section

The container uses Alpine (you may use another, but Alpine is only 5MB in size), expects a /etc/cron/crontab file that should be mapped in a volume, and runs the start.sh script at startup:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
FROM alpine:3.14

RUN mkdir /etc/cron
RUN touch /etc/cron/crontab

ADD start.sh /
RUN chmod +x /start.sh

VOLUME /etc/cron

ENTRYPOINT ["sh", "/start.sh"]

⚠️ As the scripts run in the container, you may need to install their dependencies in the container by changing the Dockerfile file. For example:

1
RUN apk add openssh

💡 We can also use Docker-in-Docker or Docker-out-of-Docker to spin up a container for jobs that need specific dependencies that we don’t want to install:

1
docker run --rm busybox echo "Hello World"

The start.sh script adds the /etc/cron/crontab file to cron and start the cron daemon with crond -f command, which instructs it to run in foreground, printing the output to stdout:

1
2
3
4
#!/bin/bash

crontab /etc/cron/crontab
crond -f

Running the container Link to this section

First we have to create the crontab file (Details on file format here).

In this example, there are two tasks:

1
2
3
# min   hour    day     month   weekday command
0       *       *       *       *       /bin/sh /etc/cron/task1.sh
0       0       *       *       *       /bin/sh /etc/cron/task2.sh

If the tasks run scripts, they should be mapped to the container in a volume. The easiest way is to put them in the same directory as the crontab file. In this example, crontab and scripts are in the ./cronjobs directory:

1
2
3
4
5
6
7
8
.
├── Dockerfile
├── docker-compose.yml
├── start.sh
└── cronjobs
    ├── crontab
    ├── task1.sh
    └── task2.sh

Then, in the docker-compose.yaml file, just map the volume for the /etc/cron/ directory:

1
2
3
4
5
6
7
services:
  cronjobs:
    build: .
    container_name: cronjobs
    volumes:
      - ./cronjobs/:/etc/cron/
    restart: unless-stopped

💡 The stdout/stderr can be read using the docker logs cronjobs command.

References Link to this section

💬 Like or have something to add? Leave a comment below.
Ko-fi
GitHub Sponsor
Licensed under CC BY-NC-SA 4.0
Built with Hugo
Theme Stack designed by Jimmy