The purpose of this post is to help developers/sysadmins to run their programmed jobs very easily using docker. These are some examples that could be useful to have a
Docker cron image/container:
- Backup databases creating dumps weekly, every x days or even every x hours.
- Run database/OS maintenance tasks periodically.
- Retrieving data from a 3rd party making API calls periodically.
- Keeping distributed content synced using Rsync.
Before you begin
In this tutorial, we’ll learn how to run tasks periodically in a Docker Cron Alpine Linux container. A Linux/Mac OS/Windows machine with Docker installed is required to follow this tutorial.
Periodic cron jobs with crond and Alpine
By default crond installation is part of the Busybox package that comes with Alpine Linux and uses the following default folders:
$ docker run -it alpine ls /etc/periodic > 15min daily hourly monthly weekly
And the following
/ # crontab -l # do daily/weekly/monthly maintenance # min hour day month weekday command */15 * * * * run-parts /etc/periodic/15min 0 * * * * run-parts /etc/periodic/hourly 0 2 * * * run-parts /etc/periodic/daily 0 3 * * 6 run-parts /etc/periodic/weekly 0 5 1 * * run-parts /etc/periodic/monthly
Where we can choose when to run a task by placing scripts in the required folder.
Following previous definitions, we can use the following docker-compose example to run cron tasks every hour ( /etc/periodic/hourly ) and every 15 minutes ( /etc/periodic/15min ) by mounting them as a read-only volume:
version: '3' services: cron: image: alpine:3.11 command: crond -f -l 8 volumes: - ./cron_tasks_folder/15min:/etc/periodic/15min/:ro - ./cron_tasks_folder/hourly:/etc/periodic/hourly/:ro
Scripts inside of
cron_tasks_folderhave to be without extension and with +x permissions. Local folder:
$ tree cron_tasks_folder cron_tasks_folder ├── 15min │ └── script_foo └── hourly └── script_bar
script_foowill be executed every 15 and
Finally, we can run the Docker Alpine container and wait for the execution of the cron jobs:
docker-compose run -d
Adding more time periods
Following the current Alpine crontab strategy we can add a new folder that we’ll allow us to run a cron job every minute. Because we want the change to be permanent in the Docker Alpine container we are going to create a
startup.sh script and that will triggered in the runtime:
#!/bin/sh echo "Starting startup.sh.." echo "* * * * * run-parts /etc/periodic/1min" >> /etc/crontabs/root crontab -l
As we promised before, we should call startup.sh in the docker-compose
command: /usr/local/startup.sh && crond -f -l 8 and mount the cron job folder that will be triggered every minute:
version: '3' services: cron: image: alpine:3.11 command: /usr/local/startup.sh && crond -f -l 8 volumes: - ./cron_tasks_folder/15min:/etc/periodic/15min/:ro - ./cron_tasks_folder/hourly:/etc/periodic/hourly/:ro - ./cron_tasks_folder/1min:/etc/periodic/1min/:ro - ./scripts/startup.sh:/usr/local/startup.sh:ro
The final step is to recreate the container:
$ docker-compose run -d --force-recreate
Please be aware that more periods can be added by adding crontab lines in startup.sh and mounting the scripts as a volume in the docker-compose cron service.
Bonus track: How to backup a PostgreSQL daily
To backup a PostgreSQL database we can use the following docker-compose:
version: '2' services: db: image: postgres:9.6 volumes: - /var/opt:/var/lib/postgresql environment: - PGDATA=/var/lib/postgresql/pg_data cron: image: postgres:9.6-alpine command: crond -f -l 8 volumes: - ./cron_tasks_folder:/etc/periodic/daily/:ro - /host_dumps_folder/:/var/opt/ depends_on: - db
Include the following file
./cron_tasks_folder/dump (Remember to not include the file extension .sh):
#!/bin/sh pg_dump -h db -U POSTGRES_USER POSTGRES_DB >> /var/opt/$(date +"%Y%m%d%H%M%S").sql
And finally run Docker:
More information about how to backup a Postgres database using Docker here.