Cron-like scheduler for docker
I have a Telegram bot and some other scripts that need to run on a schedule.
Over the years, I’ve used various solutions for this. First, plain cron on a bare-metal server;
then cron running in the foreground inside a Docker container.
Finally, I used a container running supervisord, which in turn ran cron in the foreground
along with several other daemons that needed to run continuously rather than on a schedule.
However, I was never completely satisfied with the classic cron approach:
- First, it is very sensitive to configuration syntax and file permissions. Even a small mistake can cause it to fail silently, without giving much feedback about what went wrong.
- Second, it is not very Docker-friendly. I had to deal with passing environment variables and capturing job output logs using bash helper scripts. It worked, but it wasn’t elegant.
I was about to write my own cron-like scheduler/daemon manager for Docker when I discovered Ofelia — a tiny scheduler built specifically for Docker.
Here is how I use it; it’s fairly straightforward:
services:
ofelia:
depends_on:
- jobs
image: mcuadros/ofelia:latest
restart: unless-stopped
environment:
- TZ=Europe/Helsinki
command: daemon --docker -f "name=jobs"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
jobs:
container_name: jobs
build:
context: /cron/docker
init: true
restart: unless-stopped
environment:
- SECRET=${SECRET}
volumes:
- /cron/etc/supervisord.conf:/etc/supervisor/conf.d/supervisord.conf:ro
- /cron/jobs:/jobs
labels:
ofelia.enabled: "true"
ofelia.job-exec.my-first-script.schedule: "0 55 22 * * *"
ofelia.job-exec.my-first-script.command: "/jobs/my-first-script.py"
ofelia.job-exec.my-second-script.schedule: "@every 1h"
ofelia.job-exec.my-second-script.command: "/jobs/my-other-script.py"
Quirks:
- Cron expressions are not classic — they include seconds (an extra field at the beginning).
- You need to set the
TZenvironment variable on the Ofelia container for it to use the correct timezone in your cron expressions. - Expressions in the
@everyformat are also supported, which is quite handy. However, the first run happens only after the specified interval. If you want the job to run immediately on startup, you need to work around this. - Ofelia can run jobs in any running container or start a fresh container for each execution. I prefer the former, since I mix scheduled jobs and mail filtering daemons in the same container.
- Security note: Ofelia requires access to the Docker socket. Make sure you understand the security implications.