Recently we have moved our Laravel application's infrastructure to kubernetes. Everything went well except for scheduling jobs.
Laravel scheduler should be called every minute by running artisan scheduler:run
command. Then by simply writing a php code you can schedule more jobs from the application code. That is a cool thing since you don't have to update the image in case you need a new job to be run.
What to use?
- kubernetes CronJob
- single pod with cron and run the
scheduler:run
command
The decision was to use the second option with a single instance.
The problem
Then there was a lot of problems with setting cron to read environment variables. Compared to other images that were responsible for serving requests, for example, it required some ugly hacks. There are some suggestions online but everything looks messy: like passing a list of environments and inject them in the beginning of the crontab file, echoing environment variables and then read them by the script... Some of these things didn't even work. Also one of the constraints was that we didn't want to run it as a root user.
Alternatives
So the next step was to find some alternatives:
Jobber is an alternative to cron written in go. It was hard for me to integrate it into the existing docker image. I had problems with installation on Ubuntu.
Another one is yacron but after so many difficulties with the first one (and it has fewer stars on Github if that means anything) I gave up.
Some articles discouraged me even more to use those alternatives.
Custom script (current solution)
After lots of problems with getting cron to work and it's alternatives, I decided to write a custom bash script that will just sleep for one minute and run the command.
while true
do
php /app/artisan schedule:run &
sleep 60
done
My concern here was the cumulative error that could happen when the scheduler works for long period of time. Following script is more complicated but it contains error correction logic.
Other working solutions
In the end, I was satisfied with the solution. It is even possible to get all the logs with kubectl logs
.
But still, I'm unsure is a Kubernetes CronJob a better solution, or there is some third option?