Create jobs on a time-based schedule on Swarm

CrazyMax
3 min readJan 26, 2019

swarm-cronjob creates jobs on a time-based schedule on Swarm with a dedicated service in a distributed manner that configures itself automatically and dynamically through labels and Docker API.

Features

  • Continuously updates its configuration (no restart)
  • Cron implementation through go routines
  • Allow to skip a job if the service is currently running
  • Timezone can be changed for the scheduler

Quickstart

Deploy swarm-cronjob

Create a service that uses the swarm-cronjob image :

version: "3.2"

services:
swarm-cronjob:
image: crazymax/swarm-cronjob
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
- "TZ=Europe/Paris"
- "LOG_LEVEL=info"
- "LOG_JSON=false"
deploy:
placement:
constraints:
- node.role == manager

Edit this example with your preferences and deploy the stack:

docker stack deploy -c swarm_cronjob.yml swarm_cronjob

Or use the following command:

$ docker service create --name swarm_cronjob \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
--env "LOG_LEVEL=info" \
--env "LOG_JSON=false" \
--constraint "node.role == manager" \
crazymax/swarm-cronjob

Deploy a stack

When swarm-cronjob is ready, create a new stack to be scheduled like this one:

version: "3.2"

services:
test:
image: busybox
command: date
deploy:
mode: replicated
replicas: 0
labels:
- "swarm.cronjob.enable=true"
- "swarm.cronjob.schedule=* * * * *"
- "swarm.cronjob.skip-running=false"
restart_policy:
condition: none

You can include any configuration as long as you abide with the following conditions:

  • Set command to run the task command
  • Set mode to replicated (default)
  • Set replicas to 0 to avoid running task as soon as the service is deployed
  • Set restart_policy.condition to none. This is needed for a cronjob, otherwise the task will restart automatically
  • Add Docker labels to tell swarm-cronjob that your service is a cronjob

Once ready, deploy your scheduled stack on the swarm cluster:

docker stack deploy -c date.yml date

Logs

Now check the logs of your services:

$ docker service logs swarm_cronjob_app
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:04:37 UTC INF Starting swarm-cronjob v0.1.0
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:04:37 UTC INF Add cronjob for service date_test with schedule 0 * * * * *
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:05:00 UTC INF Start date_test (exit 0 ; complete)
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:06:00 UTC INF Start date_test (exit 0 ; complete)
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:07:00 UTC INF Start date_test (exit 0 ; complete)
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:08:00 UTC INF Start date_test (exit 0 ; complete)
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:09:00 UTC INF Start date_test (exit 0 ; complete)
swarm_cronjob_app.1.nvsjbhdhiagl@default | Thu, 13 Dec 2018 20:10:00 UTC INF Start date_test (exit 0 ; complete)
$ docker service logs date_test
date_test.1.o1d5mn4gjff3@default | Thu Dec 13 20:11:01 UTC 2018
date_test.1.5askx244las2@default | Thu Dec 13 20:09:00 UTC 2018
date_test.1.4lz5ez2waekk@default | Thu Dec 13 20:12:00 UTC 2018
date_test.1.135qzpxd1ui3@default | Thu Dec 13 20:13:01 UTC 2018
date_test.1.hngject056n3@default | Thu Dec 13 20:10:00 UTC 2018

You can also use global mode services with swarm-cronjob. A typical use-case would be to remove unused data on your nodes using docker system prune command periodically.

To do so, create a new global stack:

version: "3.2"

services:
prune-nodes:
image: docker
command: ["docker", "system", "prune", "-f"]
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
mode: global
labels:
- "swarm.cronjob.enable=true"
- "swarm.cronjob.schedule=0 */5 * * * *"
- "swarm.cronjob.skip-running=false"
restart_policy:
condition: none

Same conditions have to be applied as replicated mode excepted:

  • Set mode to global
  • Remove replicas field as this is only used with replicated mode

Once ready, deploy your global cron stack on the swarm cluster:

docker stack deploy -c global.yml global

More info on https://crazy-max.github.io/swarm-cronjob/

Hope it will help some of you. Your comments are welcome 🙂

Support this project by becoming a sponsor on GitHub 👏 or by making a Paypal donation to ensure this journey continues indefinitely! 🚀

Thanks again for your support, it is much appreciated! 🙏

--

--

CrazyMax

Software Engineer, DevOps, Open Source, Go, Containers @docker