Die Empfehlung für den Einsatz von Docker-Containern ist klar: Jeder Container sollte eine einzige Aufgabe erfüllen. Dennoch kann es für die Bereitstellung von benutzerfreundlichen Docker-Images sinnvoll sein, Cronjobs vorkonfiguriert und innerhalb des Containers ausführen zu lassen.
Anfangs schien mir dies eine unkomplizierte Aufgabe, da Crontab unter Unix-basierten Images leicht einzurichten und zu konfigurieren ist.
Doch sobald ein Systemadministrator den Wunsch äußert, das Image im rootless-Modus zu betreiben, wird schnell klar, dass die klassische Crontab-Anwendung ohne aufwändige Konfiguration zwingend einen root-User erfordert.
Zudem erweist sich Crontab als wenig flexibel im Kontext moderner Container-Anforderungen.
Da ich zudem eine Lösung benötigte, die es ermöglicht, automatisierte Aufgaben zur Laufzeit dynamisch anzupassen, wollte ich mich nicht mit der Verwaltung von SIGUSR1-Signalen innerhalb von Containern beschäftigen. Dies wäre kaum mit dem Cloud-Native-Gedanken vereinbar gewesen.
Fündig wurde ich mit yacron, entwickelt von Gustavo J. A. M. Carneiro.
Dieses Tool ist schlicht, aber leistungsfähig und konnte meine wichtigsten Anforderungen abdecken:
- Einfach ausführbare Datei, welche im Image hinterlegt werden kann
- Cronjob-Zeitpläne werden bei Änderungen automatisch aktualisiert
- Läuft unter jedem unix user, unabhängig von root
- Nutzt YAML für die Konfiguration
Ein Beispiel für die Konfiguration von yacron in einem Docker-Image, das für das Hosting von WordPress verwendet wird, sieht wie folgt aus.
Hierbei wird der WordPress-Cron direkt über die CLI ausgeführt:
defaults:
environment:
- key: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
shell: /bin/sh
utc: false
jobs:
- name: WP-Cron
command: cd /var/www/html/; wp cron event run --due-now
schedule:
minute: "*/10"
dayOfMonth: "*"
month: "*"
year: "*"
dayOfWeek: "*"
captureStdout: true
Code-Sprache: YAML (yaml)
Als Prozessmanager im Image nutze ich Supervisor und folgende Konfiguration von yacron (und php-fpm, nginx):
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[program:php-fpm]
command=php-fpm -F
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0
[program:nginx]
command=nginx -g 'daemon off;'
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=false
startretries=0
[program:yacron]
# We wait 30 seconds after check to allow
command=/scripts/yacron -c /var/www/crons/cronjobs.yaml
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
autorestart=true
startretries=30
Code-Sprache: PHP (php)
Die binary von yacron lege ich einfach bereits beim Bauen in das Image:
https://github.com/swarnat/wordpress-docker-composer/tree/master/scripts
Die Dokumentation von yacron gibt noch viele weitere Beispiele, wie umfangreich dieses Tool genutzt werden kann.
Evtl. hilft das ganze auch anderen Architekten von Docker Images. Viel Spaß damit!