Docker and cron jobs
One of the problems that I’ve seen clients frequently encounter when using docker is how to “dockerize” their crons. Fortunately there is an easy solution to that.
As an example, I’ll use a TLS dashboard. The idea is that there is a dashboard of certificates for which you’d like to see more detailed information. A cron job should update information about certificates every so often. This information is very useful in case you’re using a certificate with short “lifespan” (e.g. Let’s encrypt).
TLDR;
For the lazy ones — create following docker-compose file:
version: '2'
services:
"tls-dashboard":
image: markovuksanovic/tls-dashboard
ports:
- "8080:8080"
volumes:
- /root/tls-dashboard/web_service "tls-dashboard-cron":
image: markovuksanovic/tls-dashboard-cron
volumes_from:
- "tls-dashboard"
environment:
- TLS_DASHBOARD_HOSTS=${TLS_DASHBOARD_HOSTS}
Now run:
TLS_DASHBOARD_HOSTS=google.com,baidu.com,bing.com docker-compose up
And you should have your dashboard running. You can access it using http://localhost:8080 (assuming you’re testing on localhost).
In more details:
To get this working, we’ll have two containers. One container will host a small web server which will surface information about of certificates. The other container will run a script which updates information about those certificates.
Source code is available at https://github.com/markovuksanovic/tls-dashboard. Feel free to reference it, especially if you’d like to know how the containers are built and how they are achieving the tasks.
This setup allows us to have two processes — presenting information and getting/updating information — separated. Unfortunately, they are still tightly coupled as they need to know about each other (I’ll address this issue at some point in the future).
To get our web server (the first container) working we will start a docker container using the following command:
docker run --rm -it -v /root/tls-dashboard/web_service -expose 8080 -p 8080:8080 tls-dashboard
This will expose and publish port 8080 and create an anonymous volume.
If you view the website you will see a dashboard with some prefetched results:
Now we need to start the other container which will actually update the information about certificates (make sure to replace OTHER_CONTAINER_ID with CONTAINER_ID of the container we just started):
docker run --rm -it -volumes-from=OTHER_CONTAINER_ID -e TLS_DASHBOARD_HOSTS=google.com,baidu.com,bing.com tls-dashboard-cron
This container will update information about certificates immediately as well as start a cron process which will do the same thing every 15 mins. To achieve this container uses crond. The tasks to be run can be found in ‘tasks’ folder. During container build process they are put into ‘/etc/periodic/15mins/’ folder. If you need to run tasks at some other frequency you can put them into either ‘hourly’, ‘daily’, ‘weekly’ or ‘yearly’ folder. (More information about crond on Apline linux can be found here: https://wiki.alpinelinux.org/wiki/Alpine_Linux:FAQ)
And that’s it — we have a dashboard with information about our TLS certificates and it is updated every so often.
There is one more thing we could improve. We can start this thing with only one command. To do that we’ll need help of docker-compose. Following is the docker-compose file which will help us do that.
This file builds two container, exposes correct ports, mounts/exposes volumes and sets correct environment variable values.
If we now run the following command we will get our tls-dashboard service, which comprises of two container, running.
TLS_DASHBOARD_HOSTS=google.com,baidu.com,bing.com docker-compose up
Conclusion
I hope this example show’s you that running cron jobs with docker is actually easy. This solution is not ideal. As I already mentioned, the main issue is that cron container must know about the other one. A better solution would be to store information into some external storage (which both containers would know about) and use the two containers to read/update information in that datastore. I’ll tackle this issue some other time…