Cronjob und Python virtualenv
Cron ist auf Unix-Betriebssystemen verfügbar und wird zur Automatisierung von Aufgaben verwendet. Anhand der Konfiguration startet cron Skripte oder Binaries in regelmäßigen Abständen bzw. zu fest geplanten Zeitpunkten.
Beliebte Aufgaben sind z.B. automatisierte Backups (von Dateien, aber auch Datenbanken), Wartungstasks, Aufräumen von Logfiles, etc.
Letztlich kann damit jede auf dem System verfügbare Anwendung/App oder Skript zu einem geplanten Zeitpunkt gestartet bzw. gestoppt werden.
Cron wird von den meisten Unix-Betriebssystemen unterstützt, darunter Linux und macOS.
In diesem Beitrag möchte ich kurz erläutern, wie Python-Skripte in einem eigenen Python-virtualenv (venv) mittels Cronjob automatisiert ausgeführt werden können.
Starten wir mit einer kurzen Einführung in die Syntax von cron, den sog. Cron Ausdrücken (Englisch: Cron Expressions)
Cron Ausdrücke
┌───────────── Minute (0....59)
│ ┌───────────── Stunde (0....23)
│ │ ┌───────────── Tag (1....31 im Monat)
│ │ │ ┌───────────── Monat (1....12)
│ │ │ │ ┌───────────── Wochentag (0....6; 0: Sonntag, 6: Samstag)
│ │ │ │ │
* * * * * /path/to/script.sh
* * * * * /path/to/binary
Wie wir im Beispiel sehen, können wir minütlich Skripte oder Anwendungen starten. Diese Cron-Konfiguration würde jede Minute das Skript /path/to/script.sh
und das Binary /path/to/binary
ausführen.
20 8 10 * * /path/to/script.sh
In dieser Beispielkonfiguration würde cron das Skript /path/to/script.sh
jeden Monat am 10. Tag ausführen, um 8:20 Uhr.
Kurzer Überblick: Konfiguration von cron via Terminal
In Abhängigkeit des Betriebssystems ist (oft) vi
der Standardeditor für das Editieren von Cronjobs. Wer zum Editieren lieber nano
verwenden möchte, kann das ändern, indem die Variable EDITOR auf nano gesetzt wird. Die Änderung ist temporär gültig, für die aktuelle Terminal-Session:
# cronjobs mit nano editieren anstatt mit vi - optional
# zuerst die Variable EDITOR setzen (persistent für die aktuelle Session)
export EDITOR=nano
Um nun aufzulisten, welche aktuellen Cronjobs aktiv sind, öffnen wir das Terminal und starten mit crontab -l
Die Auflistung bezieht sich immer auf den aktuell angemeldeten Benutzer. Jeder Benutzer hat am System seinen eigenen Crontab und kann diesen unabhängig verwalten.
Mit crontab -e
können wir die Cronjobs für den aktuell angemeldeten Benutzer bearbeiten.
In dem folgenden Beispiel führt cron jede Minute das Skript main_app.py
(mit dem systemweiten Python3 Interpreter) aus, das im Ordner /opt/my_python_app
liegt. Die Terminal-Ausgaben des Skripts auf stdout werden in die Datei /opt/my_python_app/log.txt
umgeleitet.
Kommen wir aber nun zum eigentlichen Punkt, der Ausführung eines Python-Skriptes in einer Python virtuellen Umgebung – als cronjob.
Cron-Konfiguration für Python-Skript in virtualenv
Um das Szenario zu veranschaulichen nehmen wir folgende Ausgangssituation an:
- unser Python-Skript befindet sich im Ordner
/opt/my_python_app
und hat den Dateinamenmain_app.py
- unser Python virtualenv befindet sich im Ordner
/opt/venv_my_python_app
und wurde mit dem Befehlpython3 -m venv venv_my_python_app
erstellt
Um die virtuelle Umgebung im Terminal zu aktivieren würden wir folgenden Befehl verwenden: source ./venv_my_python_app/bin/activate
Wenn wir jetzt aber diese virtuelle Umgebung in einem cronjob nutzen wollen, um /opt/my_python_app/main_app.py
minütlich auszuführen, dann sieht der Befehl für Cron folgendermaßen aus:
* * * * * cd /opt/my_python_app && /opt/venv_my_python_app/bin/python /opt/my_python_app/main_app.py
Mit cd
wechseln wir in unser Skriptverzeichnis, in dem sich main_app.py
befindet. Als Python Interpreter nehmen wir jetzt nicht den systemweiten python3
, sondern nehmen den Interpreter der sich in unserer virtuellen Python Umgebung befindet. Dieser ruft dann unser Skript minütlich auf.
Selbstverständlich ist es in diesem Fall auch möglich die Ausgaben des Skripts in eine Datei (z.B. Logdatei) umzuleiten:
* * * * * cd /opt/my_python_app && /opt/venv_my_python_app/bin/python /opt/my_python_app/main_app.py > my_app_log.txt
Der o.g. Wechsel mit cd in unser Skriptverzeichnis ist nicht immer obligatorisch. Es kommt z.B. darauf an, ob aus main_app.py
mit relativen oder absoluten Pfaden auf Ressourcen zugegriffen wird.