Cron-Jobs in Docker - der richtige Ansatz
Cron-Jobs in Docker - der richtige Ansatz
Wiederkehrende Aufgaben in Docker-Umgebungen lösen viele falsch – ein Cron-Daemon im App-Container ist fast immer die schlechteste Wahl.
Anti-Pattern: Cron im App-Container
Ein Container soll einen Prozess ausführen. Zwei Prozesse (App + crond) in einem Container zu betreiben erzeugt Probleme: Logs werden gemischt, Signals werden nicht sauber weitergeleitet, Restarts betreffen immer beide Prozesse.
# SCHLECHT – nicht so machen
FROM python:3.12
RUN apt-get install -y cron
COPY mycron /etc/cron.d/mycron
CMD service cron start && python app.py # Zwei Prozesse, keine saubere Trennung
Option 1: Host-Cron (einfach und zuverlässig)
Der Host-Cron ruft docker exec oder docker run auf. Keine zusätzlichen Container, funktioniert immer.
# crontab -e auf dem Host
# Täglich um 2 Uhr: Datenbankbackup im laufenden Container
0 2 * * * docker exec mydb mysqldump -u root -psecret mydb > /backups/db-$(date +\%Y\%m\%d).sql
# Alle 5 Minuten: einmaliger Task-Container
*/5 * * * * docker run --rm --network myapp_default myimage python /app/tasks/cleanup.py
Vorteile: Einfach, direkte Logs per syslog, kein weiterer Container.
Option 2: Supercronic
Supercronic ist ein cron-Ersatz der speziell für Container entwickelt wurde – ein einzelner Prozess, saubere Logs zu stdout/stderr, keine root-Rechte nötig.
FROM alpine:3.19
RUN wget -O /usr/local/bin/supercronic \
https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64 && \
chmod +x /usr/local/bin/supercronic
COPY crontab /crontab
CMD ["/usr/local/bin/supercronic", "/crontab"]
# /crontab
*/5 * * * * python /app/tasks/cleanup.py
0 3 * * * python /app/tasks/backup.py
Supercronic ist die beste Wahl wenn der Container selbst der Cron-Container sein soll.
Option 3: Ofelia
Ofelia ist ein dedizierten Docker-Cron-Manager der andere Container via Labels steuert:
services:
ofelia:
image: mcuadros/ofelia:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
- app
app:
image: myapp
labels:
ofelia.enabled: "true"
ofelia.job-exec.cleanup.schedule: "@every 5m"
ofelia.job-exec.cleanup.command: "python /app/tasks/cleanup.py"
ofelia.job-exec.backup.schedule: "0 3 * * *"
ofelia.job-exec.backup.command: "python /app/tasks/backup.py"
Ofelia liest die Labels und führt die Befehle im App-Container aus. Logs landen im Ofelia-Container, übersichtlich getrennt.
Option 4: Compose mit restart: on-failure
Für einfache einmalige Tasks die regelmäßig als neuer Container gestartet werden – kombiniert mit einem externen Trigger:
services:
backup-job:
image: myimage
command: python /app/tasks/backup.py
restart: "no"
profiles:
- jobs
# Vom Host aus starten
docker compose run --rm backup-job
Empfehlung
| Szenario | Lösung |
|---|---|
| Einfache Tasks auf einem Server | Host-Cron |
| Container der nur Cron-Tasks ausführt | Supercronic |
| Mehrere Services mit verschiedenen Tasks | Ofelia |
| Einmalige parametrisierbare Jobs | docker compose run |
Auf dem eigenen Server ist Host-Cron die unkomplizierteste Wahl. Für containerisierte Umgebungen ohne Host-Zugriff (managed Platforms) ist Supercronic ideal.