While is perfectly possible to use cron inside a container, I strongly advise you to don’t do it. Some of the most important points on why is a bad practice to run cron inside a container:
Your tasks need to be ephemeral as your containers
We live in the immutable infrastructure era, there is no need to worry about
cleaning up everything before or after your tasks run. Make your scheduled tasks
ephemeral as your containers, if something goes wrong, you can inspect the
precise state that the container was left. Even with Tasker supporting reusing
the container(reuse: true
) this is not recommended.
Let your tasks be ephemeral as possible, you can always count on a clean environment for every execution.
Maintain custom images is time consuming
This is the main point of using Tasker, imagine that you have 3 tasks to run, one in Python, one in Javascript (nodejs) and the other is a backup tasks that need the MongoDB command line tools. Using cron would be needed to build 3 images, one for each task, adding the cron daemon to the base image, then configuring your task and adding your scripts. After it is done, you need to publish it, because your servers will need to pull this image to be able to run it, so another step is giving access to it.
With Tasker, you simply use the images that are already available, no more extra work required.
No alerts when tasks fail
Cron doesn’t provide anything out of the box to alert about your tasks execution status. Tasker in the other hand come with batteries included and ships alerting out of the box, here the official docs.
Is hard to keep everything as code
Considering the first scenario, with 3 tasks each one with a image for each. If you keep the good practices, you will create a git repository for each one, with their own build. It means that you have 3 additional repositories to keep track of.
With Tasker you can simply have one configuration file and replace all those repositories with one repository.
Introduction to Tasker
Tasker
is a task scheduler and runner, it works by creating containers on demand
to run your task.
Let’s use a practical example, considering the docker-compose.yml
file bellow:
version: "3"
services:
tasker:
image: strm/tasker
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
configuration: |
schedule:
- every: minute
task: hello
tasks:
docker:
- name: hello
image: debian:jessie
script:
- echo Hello world from Tasker
Tasker
can be configured in several ways, one way is setting the environment
variable configuration
and set it to your yml configuration. As you can notice,
it goes really well with the docker-compose file.
Let’s break down the configuration to explain what is going on. We can break it
in two main sections, schedule
and `tasks**.
Schedules are the triggers to our tasks, they are defined as an array of
schedule
. These schedules are defined by two main properties, when they will
trigger the task, and what tasks they will trigger.
Another good point of Tasker is that you don’t have to memorize some abstract
cron syntax, it uses a more human language, like in this example every: minute
,
it means every 1 minute this task will run. Test it, change to every: 10 minutes
and observe the results. You can also set it as a default cron syntax.
More about scheduling can be found on the official docs
The second element of the configuration (and the most important) are the tasks,
tasks defined under the docker
property represent a docker container
definitions, they reflect the container that will be created when triggered and
will execute your commands. You can use any docker image to run your commands
into.
Here a more elaborate example to illustrate how you can use several images on the same configuration
version: "3"
services:
tasker:
image: strm/tasker
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
configuration: |
logging:
level:
ROOT: WARN
org.springframework.web: WARN
sh.strm: DEBUG
schedule:
- every: minute
task: hello
- every: minute
task: helloFromPython
- every: minute
task: helloFromNode
tasks:
docker:
- name: hello
image: debian:jessie
script:
- echo Hello world from Tasker
- name: helloFromPython
image: python:3-slim
script:
- python -c 'print("Hello world from python")'
- name: helloFromNode
image: node:8
script:
- node -e 'console.log("Hello from node")'
Note that in this example, we have only one source file, but if you had to replicate it using cron you would had to create 3 images, one for each base image + the cron daemon, and, or map your scripts to it, or copy it on the build. After a while the maintenance required to keep everything updated will consume a significant amount of time. This is one of the main scenarios where Tasker simplifies a lot the work required.
Basically everything that you need to configure in a container, from networking, volumes, and everything else can be done using this configuration section, for more info see the official docs.