Fehlerbehebung · Docker

Cron im Docker-Container läuft nicht? Lösungen, die wirklich funktionieren

Warum Cron in einem Docker-Container still ausfällt — PID 1, fehlende Env-Variablen, kein Mailserver — und wie Sie jedes Problem beheben.

Cron in einem Container laufen zu lassen, bringt Leute aus dem Tritt, weil ein Container keine normale VM ist. Hier die üblichen Ursachen, lösungsorientiert.

1. Cron läuft nicht als PID 1

Ein Container führt einen Vordergrundprozess aus. Startet Ihr CMD Ihre App, wird cron nie gestartet — und ist Ihr CMD cron, beendet es sich womöglich sofort, weil es sich daemonisiert. Führen Sie es im Vordergrund aus:

# Debian/Ubuntu-Basis
CMD ["cron", "-f"]

Um Cron und Ihre App auszuführen, nutzen Sie einen kleinen Supervisor (supervisord, s6) oder einen Prozessmanager — verlassen Sie sich nicht auf Backgrounding in einem Shell-CMD.

2. Umgebungsvariablen verschwinden unter Cron

Das ist das große Problem. Docker injiziert Env-Variablen in PID 1, aber Cron startet Jobs mit einer sauberen Umgebung, sodass Ihre DATABASE_URL und API-Schlüssel weg sind. Schreiben Sie die Container-Umgebung beim Start in eine Datei und laden Sie sie im Job:

CMD printenv | sed 's/^\(.*\)$/export \1/' > /etc/container.env && cron -f
# in der Crontab
0 * * * * . /etc/container.env && /app/run.sh

3. Die Crontab braucht das richtige Format und eine Leerzeile am Ende

Eine System-Crontab-Zeile braucht eine Benutzer-Spalte, und die Datei muss mit einer Newline enden, sonst wird der letzte Job ignoriert:

# /etc/cron.d/app  — beachten Sie das Benutzerfeld "root"
0 2 * * * root /app/run.sh >> /var/log/cron.log 2>&1
COPY app-cron /etc/cron.d/app
RUN chmod 0644 /etc/cron.d/app && crontab /etc/cron.d/app

4. „Cron kann keine E-Mail senden“ — es gibt keinen Mailserver

Ein Klassiker: Eine Container-Crontab versucht, die Ausgabe zu mailen, aber es gibt keinen MTA, sodass Jobs scheinbar „fehlschlagen“. Verlassen Sie sich nicht auf lokale Mail. Leiten Sie die Ausgabe nach stdout, damit sie in docker logs landet:

0 2 * * * root /app/run.sh > /proc/1/fd/1 2>/proc/1/fd/2

5. Sehen Sie sich die Ausgabe an

docker logs -f <container>
docker exec -it <container> sh -c "crontab -l"

Das tiefere Problem: Container starten neu, und Cron vergisst

Ein Redeploy, ein OOM-Kill, eine Crash-Loop — jedes davon kann Ihren Container-Cron stoppen, und nichts sagt es Ihnen. Monitoring von außerhalb des Containers ist das einzig zuverlässige Signal.

Lassen Sie den Job bei Erfolg eine Heartbeat-URL anpingen. Ist der Container down oder der Job gestoppt, bleibt der Ping aus und Sie werden alarmiert:

HEALTHCHECK --interval=5m --timeout=10s \
  CMD curl -fsS https://ping.steadycron.com/<ihr-ping-token> || exit 1