CronJobs for Docker Compose
Oftentimes, your applications have periodic tasks which need to be ran in order to do some async / batch processing. Usually, these are modelled as Cron Jobs.
Bunnyshell supports running multiple CronJobs for each of your Applications, Services and Databases.
If you want to learn why Docker Compose is unsuitable for production and how Bunnyshell can help you transition from docker-compose to Kubernetes, read this article.
Defining a CronJob
CronJobs are defined in Bunnyshell by configuring a cronJobs
attribute for any Docker Compose component.
The best way to demonstrate how CronJobs can be configured, we'll take some examples. For simplicity's sake, git*
attributes, as well as the hosts
attribute were omitted, so component configuration is kept to a minimum.
Let's assume we have an Application
named webapp
and we add some CronJobs to it.
Let's also say you have a bin/console send:emails
command which can send emails, and you want to trigger it to run every 5 minutes.
Basic example
The most simple example for adding a CronJob looks like this, and involves only adding the cronJobs
attribute on the Component, only with name
, schedule
and command
attributes.
components:
-
kind: Application
name: webapp
...
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
cronJobs:
- name: send-emails
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
Volumes
If your Application also has Volumes attached, you can choose whether or not these will be attached to the Pod running the CronJob as well.
Two volumes are mounted in the main component, webapp
and below some CronJob examples are provided, which demonstrate how you can:
- omit the volumes altogether
- include only some volumes, or
- include all volumes (default behaviour)
using the volumes
attribute on the CronJob.
components:
-
kind: Application
name: webapp
...
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
volumes:
-
name: media
mount: /var/media
-
name: artefacts
mount: /var/artefacts
cronJobs:
- name: send-emails-no-volumes
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
volumes: false # no volume included
- name: send-emails-all-volumes
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
volumes: true # all volumes included; default value, can be ommitted
- name: send-emails-some-volumes
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
containers:
- nginx
volumes:
- artefacts # only "artefacts" volume included, "media" not attached
volumes:
-
name: artefacts
type: network
size: 1Gi
-
name: media
type: network
size: 1Gi
Note
Because a volume can be simultaneously mounted in a running Pod of a Deployment and in a Pod of a CronJob, and these can be scheduled on different cluster nodes, we limit the usage of cronJobs only with volumes of type
network
Kubernetes Resources
Usually, running separate dedicated commands require significantly less resources to run than the container running the web app - so, in order to be mindful of utilizing resources, these can be specified on a per-CronJob basis, using the resources
attribute. Its syntax is Docker compose compatible, and the same as when defining the main component resources.
components:
-
kind: Application
name: webapp
...
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
cronJobs:
- name: send-emails-low-resources
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
resources:
limits:
cpus: '2'
memory: '256M'
reservations:
cpus: '0.50'
memory: '128M'
Execution Timeout
Sometimes it's important to make sure the cronJob does not run more than a maximum time, or if the Pod it's not even scheduled in that time, to cancel the run entirely. This can be accomplished by setting the executionTimeout
seconds on the cronJob, by default there is no timeout.
Sidecar containers
You may have the need to initialize your application by performing some tasks before your application (container) actually starts. For this, you would use InitContainers.
Other times, besides your main application, you may have additional containers which need to run alongside your main application's container - take for example, sending logs and the other for pushing metrics. These would be implemented using SidecarContainers.
Let's take an example which provides one InitContainer
for building the application (eg: running npm run build
) and two SidecarContainers
, one for logging and the other for pushing metrics.
The InitContainer
and SidecarContainer
components are defined first; these are similar to Application
components, except they are not deployed directly, but their configuration is used only when attached to another Application
(or Service
/ Database
) Component, using the pod
attribute.
Using the containers
attribute, you can control which containers will be included in the CronJob's Pod, but please keep in mind that the bare minimum, the main container must be included, in this case webapp
- it bears the name of the components itself.
components:
-
kind: InitContainer
name: build-app-init
...
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
-
kind: SidecarContainer
name: logging-sidecar
...
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
-
kind: SidecarContainer
name: metrics-sidecar
...
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
-
kind: Application
name: webapp
...
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
pod:
init_containers:
-
from: build-app-init
name: build-app
sidecar_containers:
-
from: logging-sidecar
name: logging
-
from: metrics-sidecar
name: metrics
cronJobs:
- name: send-emails-no-containers
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
containers:
- webapp
- name: send-emails-all-containers
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
# not specifying the "containers" attribute will include all of them
- name: send-emails-some-containers
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
containers:
- webapp
- build
- logging
Rich configuration example
A very complex configuration example is presented below, combining all options into a single example.
components:
-
kind: InitContainer
name: build-app-init
gitRepo: git@...
gitBranch: master
gitApplicationPath: /
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
-
kind: SidecarContainer
name: logging-sidecar
gitRepo: git@...
gitBranch: master
gitApplicationPath: /
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
-
kind: SidecarContainer
name: metrics-sidecar
gitRepo: git@...
gitBranch: master
gitApplicationPath: /
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
-
kind: Application
name: webapp
gitRepo: git@...
gitBranch: master
gitApplicationPath: /
dockerCompose:
build:
context: .docker
dockerfile: Dockerfile
volumes:
-
name: media
mount: /var/media
-
name: artefacts
mount: /var/artefacts
pod:
init_containers:
-
from: build-app-init
name: build-app
sidecar_containers:
-
from: logging-sidecar
name: logging
-
from: metrics-sidecar
name: metrics
hosts:
- hostname: 'app-{{ env.base_domain }}'
path: /
servicePort: 8080
cronJobs:
- name: webapp-rich
schedule: '*/5 * * * *'
command:
- /bin/sh
- '-c'
- 'bin/console send:emails'
containers:
- webapp
- build
- logging
volumes:
- artefacts
resources:
limits:
cpus: '2'
memory: '10000M'
reservations:
cpus: '0.50'
memory: '5000M'
executionTimeout: 180
volumes:
-
name: artefacts
type: network
size: 1Gi
-
name: media
type: network
size: 1Gi
Updated 3 months ago