This project has the following major goals:

  • Provide an lean implementation of a job scheduling functionality
  • The jobs will be defined with docker labels.
  • The scheduling intervals are specified using CRON syntax
  • The job can be specified as shell command, as scripting command (e.g. javascript) or as java main programs which is located in a maven repository
  • It should support both central scheduling affecting multiple containers and decentralised scheduling for a single container only
  • Provide a simple GUI to
    • visualize the scheduled future jobs
    • access the Docker logs of historic jobs

The solution is available on the Docker Hub.

Starting the Container

Docker Execute

Just start the scheduler with

  • docker run –name docker-cron -p 8080:8080 -v /var/run/docker.sock:/var/run/docker.sock pschatzmann/docker-cron

and we will pick up all scheduling information which is defined in any of your containers.

Docker Compose

Or just start the scheduler with docker-compose up with the following docker-compose.yml file.

version: '3'
    image: pschatzmann/docker-cron
        - /var/run/docker.sock:/var/run/docker.sock
       - TZ=Europe/Zurich
       - maxLogSize=100000
       - xmx=600m
       - "8080:8080"
    restart: always


We provide a simple GUI which shows the scheduled jobs and the job logs. The application can be accessed on port 8080.


Cron Syntax

A UNIX crontab-like pattern is a string split in five space separated parts. Each part is intended as:

  • Minutes sub-pattern. During which minutes of the hour should the task been launched? The values range is from 0 to 59.
  • Hours sub-pattern. During which hours of the day should the task been launched? The values range is from 0 to 23.
  • Days of month sub-pattern. During which days of the month should the task been launched? The values range is from 1 to 31. The special value “L” can be used to recognise the last day of month.
  • Months sub-pattern. During which months of the year should the task been launched? The values range is from 1 (January) to 12 (December), otherwise this sub-pattern allows the aliases “jan”, “feb”, “mar”, “apr”, “may”, “jun”, “jul”, “aug”, “sep”, “oct”, “nov” and “dec”.
    Days of week sub-pattern. During which days of the week should the task been launched? The values range is from 0 (Sunday) to 6 (Saturday), otherwise this sub-pattern allows the aliases “sun”, “mon”, “tue”, “wed”, “thu”, “fri” and “sat”.

The star wildcard character is also admitted, indicating “every minute of the hour”, “every hour of the day”, “every day of the month”, “every month of the year” and “every day of the week”, according to the sub-pattern in which it is used.

Once the scheduler is started, a task will be launched when the five parts in its scheduling pattern will be true at the same time.

LabelsThe job information is defined with the help of the Docker Labels of the containers. Only the schedule and the command information is mandatory. If the job should only consist of one step, the step information can be skipped.

job.<jobname>.condition = <condition>  (e.g true)
job.<jobname>.schedule = <cron expression> (e.g.", "* * * * *")
job.<jobname>.command.<stepName> = <command template> (e.g. echo test)
job.<jobname>.condition.<stepName>.condition = <condition>  (e.g. false)
job.<jobname>.scenario = "Local | Central |  Maven"
job.<jobname>.scriptengine = <scripting engine>  (javascript | groovy)


The following example is just printing the string “test” every minute to the console

        - job.echo.schedule=* * * * *
        - job.echo.command=echo test


The indicated <command template> is used to build the command which needs to be executed. The standard template engine is simply replacing the expressions in curly braces {fieldname} with the corresponding label values.

It is possible to use the scripting engine instead of this default templating engine with the label “job.<jobname>.isScriptingAsTemplate=true”. In this case you need to provide the command as a valid expression in the scripting language. E.g ‘echo name=’+name+’ volume=’+volume


All container labels are available as variables. In addition we support the following additional variables

  • name: container name
  • id: container id
  • host: host of the current container
  • docker-cron-host: host of the container which is running docker-cron
  • image: the image id
  • volume: internal volume name


This is an expression formulated in a scripting language which resolved to true or false. The default scripting engine is using javascript. e.g. name == ‘test’ is evaluating true only if the container name is ‘test’


This is mainly relevant to support extended scenarios:

  • Maven‘: a java main program which is located in a maven repository is executed in the docker-cron container. The command needs to have the syntax <repository>;<maven string>;<java class>;<parameters>
  • Central‘ (for labels in the docker-cron container itself only): The job is executed only once
  • Local‘ (for labels in the docker-cron container  itself only):  The job is executed for each container

Scripting EnginesWe are supporting any scripting engine which implements JSR223. As default we use the standard implementation which comes with java. If you want to extend the scripting functionality you just need to copy the implementation jars to the mapped volume /usr/local/bin/docker-cron/lib/.

Then you can select in your job the scripting language with the label corresponding label: e.g. job.echo.scriptengine = javascript


Central Backup of Postgres

Every day at midnight, we dumb all postgres containers and copy the dump into the /backup directory of the host. Then we user the docker cp to copy the file out of the container to the host

version: '3'
      image: pschatzmann/docker-cron
      container_name: docker-cron

        - job.scenario=Local
        - job.condition=container.matches("postgres.*")
        - job.postgres-backup.command.1=docker exec -t {name} pg_dumpall -c -U postgres -f /var/lib/postgresql/data/dump-{name}.sql
        - job.postgres-backup.command.2=docker cp {name}:/var/lib/postgresql/data/dump-{name}.sql /backup 
        - /var/run/docker.sock:/var/run/docker.sock
      restart: always

Decentral Backup of MySQL

Here is an example of a scheduled decentral backup of a wordpress MySQL database. The scheduling is defined in the MySQL docker-compose file.

 image: mariadb
 - /srv/wordpress-mysql:/var/lib/mysql
 - /backup:/backup
 - "job.backup.schedule=30 * * * *"
 - "job.backup.command=mysqldump -uroot -pPWD wordpress -r/backup/wordpress.sql"
 restart: always


Environment Variables

Environment Variable Default Value Description
maxLogSize 100000 Maximum number of log entries which will be selected. If the limit is exceeded we cut off the oldest values.
xmx 600m Java maximum heap setting
TZ Standard Linux Time Zone setting