TL;DR — Kurzzusammenfassung

Erfahren Sie, wie Sie wiederkehrende Aufgaben unter Linux mit systemd-Timern planen. Ersetzen Sie Cron-Jobs durch persistente, protokollierte Planung.

systemd-Timer sind der moderne Ersatz für Cron auf Linux-Systemen. Sie bieten alles, was Cron kann — wiederkehrende und einmalige Zeitplanung — plus integriertes Logging, Abhängigkeitsverwaltung, Ressourcenkontrolle und die Möglichkeit, verpasste Ausführungen nachzuholen. Wenn Sie Linux-Server verwalten, bedeutet der Umstieg von Cron auf systemd-Timer weniger stille Fehler und deutlich bessere Transparenz darüber, was Ihre geplanten Aufgaben tun.

Diese Anleitung führt Sie durch das Erstellen von Timern von Grund auf, das Umwandeln bestehender Cron-Jobs und die Nutzung fortgeschrittener Funktionen wie zufällige Verzögerungen und persistente Zeitplanung.

Voraussetzungen

  • Ein Linux-System mit systemd (Ubuntu 16.04+, CentOS 7+, Debian 8+ oder jede moderne Distribution)
  • Root- oder sudo-Zugang
  • Grundlegende Vertrautheit mit systemctl und Unit-Dateien

Wie systemd-Timer funktionieren

Ein systemd-Timer besteht aus zwei Unit-Dateien:

  1. Eine .service-Unit — definiert, was ausgeführt wird (der eigentliche Befehl oder das Skript)
  2. Eine .timer-Unit — definiert, wann es ausgeführt wird (der Zeitplan)

Die Timer-Unit aktiviert die zugehörige Service-Unit nach Zeitplan. Beide Dateien müssen denselben Basisnamen haben (z. B. backup.service und backup.timer), es sei denn, Sie geben explizit eine andere Unit mit Unit= an.

Diese Trennung ist ein entscheidender Vorteil gegenüber Cron: Die Service-Unit kann unabhängig getestet, bei Fehlern neu gestartet und mit Standard-systemd-Werkzeugen inspiziert werden.

Ihren ersten Timer erstellen

Erstellen wir einen Timer, der ein Bereinigungsskript täglich um 2:00 Uhr morgens ausführt.

Schritt 1: Service-Unit erstellen

sudo nano /etc/systemd/system/daily-cleanup.service
[Unit]
Description=Daily temporary file cleanup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup.sh

Type=oneshot teilt systemd mit, dass dieser Prozess bis zum Abschluss läuft und sich dann beendet — es ist kein dauerhaft laufender Daemon. Dies ist der richtige Typ für geplante Aufgaben.

Erstellen Sie das referenzierte Skript:

sudo tee /usr/local/bin/cleanup.sh > /dev/null << 'EOF'
#!/bin/bash
find /tmp -type f -mtime +7 -delete
find /var/log -name "*.gz" -mtime +30 -delete
echo "Cleanup completed at $(date)"
EOF
sudo chmod +x /usr/local/bin/cleanup.sh

Schritt 2: Timer-Unit erstellen

sudo nano /etc/systemd/system/daily-cleanup.timer
[Unit]
Description=Run daily cleanup at 2:00 AM

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Wichtige Direktiven:

Direktive Zweck
OnCalendar Kalenderbasierter Zeitplan (wie Cron)
Persistent=true Sofortige Ausführung, falls ein geplanter Lauf verpasst wurde (z. B. System war ausgeschaltet)
WantedBy=timers.target Erforderlich, damit systemctl enable funktioniert

Schritt 3: Aktivieren und starten

sudo systemctl daemon-reload
sudo systemctl enable --now daily-cleanup.timer

Schritt 4: Überprüfen

systemctl list-timers daily-cleanup.timer

Ausgabe:

NEXT                        LEFT          LAST PASSED UNIT                  ACTIVATES
Wed 2025-12-24 02:00:00 UTC 10h left      n/a  n/a   daily-cleanup.timer   daily-cleanup.service

Testen Sie den Service manuell, um zu bestätigen, dass er funktioniert:

sudo systemctl start daily-cleanup.service
journalctl -u daily-cleanup.service --no-pager -n 20

Die OnCalendar-Syntax verstehen

Die OnCalendar-Direktive verwendet ein flexibles Kalenderausdrucksformat:

Wochentag Jahr-Monat-Tag Stunde:Minute:Sekunde

Hier sind die gebräuchlichsten Muster:

Zeitplan OnCalendar-Ausdruck
Täglich um Mitternacht *-*-* 00:00:00
Jeden Montag um 9 Uhr Mon *-*-* 09:00:00
Erster jedes Monats *-*-01 00:00:00
Alle 15 Minuten *-*-* *:00/15:00
Werktags um 18 Uhr Mon..Fri *-*-* 18:00:00
Jeden 1. Jan und Jul *-01,07-01 00:00:00
Alle 2 Stunden *-*-* 00/2:00:00

Sie können Ausdrücke mit systemd-analyze calendar validieren:

systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
  Original form: Mon..Fri *-*-* 09:00:00
Normalized form: Mon..Fri *-*-* 09:00:00
    Next elapse: Mon 2025-12-29 09:00:00 UTC
       (in UTC): Mon 2025-12-29 09:00:00 UTC
       From now: 5 days left

Dies ist einer der größten Vorteile gegenüber Cron — Sie können Ihren Zeitplanausdruck überprüfen, bevor Sie ihn einsetzen.

Monotone Timer: Intervalle nach Ereignissen

Nicht alle Zeitpläne sind uhrzeitbasiert. Monotone Timer lösen relativ zu einem Ereignis aus:

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
Direktive Auslöser
OnBootSec X Zeit nach dem Booten
OnStartupSec X Zeit nach dem Start von systemd
OnUnitActiveSec X Zeit nach der letzten Aktivierung des Timers
OnUnitInactiveSec X Zeit nach dem letzten Abschluss des Services

Dies ist nützlich für Zustandsprüfungen, Metrik-Erfassung oder jede Aufgabe, die in festen Intervallen laufen soll, unabhängig von der Uhrzeit.

Beispiel — Zustandsprüfung alle 5 Minuten, beginnend 1 Minute nach dem Booten:

[Unit]
Description=Periodic health check

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
AccuracySec=10s

[Install]
WantedBy=timers.target

AccuracySec=10s verkleinert das standardmäßige 1-Minuten-Zusammenfassungsfenster, sodass Ihr Timer näher an genau alle 5 Minuten auslöst.

Fortgeschrittene Funktionen

Zufällige Verzögerung

Verhindern Sie, dass mehrere Server gleichzeitig auf dieselbe Ressource zugreifen:

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=900

Dies plant die Aufgabe zwischen 3:00 und 3:15 Uhr, wobei systemd für jeden Boot-Zyklus einen zufälligen Versatz wählt.

Ressourcenkontrolle

Da die Aufgabe als systemd-Service läuft, können Sie Ressourcenlimits anwenden:

[Service]
Type=oneshot
ExecStart=/usr/local/bin/heavy-report.sh
CPUQuota=50%
MemoryMax=512M
IOWeight=50
Nice=15

Cron hat kein Äquivalent dazu — Sie müssten nice, ionice und ulimit-Aufrufe in jedes Skript einfügen.

Fehlerbenachrichtigung

Lösen Sie eine Warnung aus, wenn eine geplante Aufgabe fehlschlägt:

[Unit]
Description=Database backup
OnFailure=notify-admin@%n.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh

Erstellen Sie die Benachrichtigungsvorlage unter /etc/systemd/system/notify-admin@.service:

[Unit]
Description=Send failure alert for %i

[Service]
Type=oneshot
ExecStart=/usr/local/bin/send-alert.sh "Unit %i failed on %H"

Cron-Jobs in systemd-Timer umwandeln

Hier ist ein systematischer Ansatz zur Migration bestehender Cron-Jobs.

Beispiel-Cron-Eintrag:

30 2 * * 1-5 /usr/local/bin/db-backup.sh

Dies führt das Backup um 2:30 Uhr an Werktagen aus. Die entsprechenden systemd-Units:

# /etc/systemd/system/db-backup.service
[Unit]
Description=Database backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh
# /etc/systemd/system/db-backup.timer
[Unit]
Description=Database backup on weekday nights

[Timer]
OnCalendar=Mon..Fri *-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

Cron-zu-OnCalendar-Kurzreferenz:

Cron OnCalendar
0 * * * * (stündlich) *-*-* *:00:00
*/5 * * * * (alle 5 Min) *-*-* *:00/5:00
0 0 * * 0 (wöchentlich So) Sun *-*-* 00:00:00
0 0 1 * * (monatlich) *-*-01 00:00:00
@reboot Verwenden Sie OnBootSec=0

Nach dem Erstellen der Units:

sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer

# Überprüfen
systemctl list-timers db-backup.timer

# Alten Cron-Eintrag auskommentieren
sudo crontab -e

Überwachung und Debugging von Timern

Alle aktiven Timer auflisten

systemctl list-timers --all

Timer-Logs prüfen

journalctl -u daily-cleanup.service --since today
journalctl -u daily-cleanup.service --since "2025-12-20" --until "2025-12-23"

Einen Timer debuggen, der nicht auslöst

# Timer-Status prüfen
systemctl status daily-cleanup.timer

# Kalenderausdruck überprüfen
systemd-analyze calendar "*-*-* 02:00:00"

# Unit-Datei auf Fehler prüfen
systemd-analyze verify /etc/systemd/system/daily-cleanup.*

# Alle Timer anzeigen, einschließlich inaktiver
systemctl list-timers --all --no-pager

Transiente Timer für einmalige Aufgaben

Müssen Sie etwas in 30 Minuten ausführen, ohne Unit-Dateien zu erstellen?

systemd-run --on-active=30min /usr/local/bin/one-time-task.sh

Oder zu einem bestimmten Zeitpunkt:

systemd-run --on-calendar="2025-12-24 15:00:00" /usr/local/bin/holiday-report.sh

Fehlerbehebung

Timer zeigt “n/a” bei NEXT: Der Timer ist geladen, aber nicht aktiviert. Führen Sie systemctl enable --now <name>.timer aus.

Service läuft, aber Timer löst ihn nicht aus: Stellen Sie sicher, dass die Dateinamen von .timer und .service exakt übereinstimmen. Prüfen Sie mit systemctl cat <name>.timer auf Tippfehler.

“Failed to parse calendar specification”: Ihre OnCalendar-Syntax ist fehlerhaft. Validieren Sie mit systemd-analyze calendar "Ihr Ausdruck".

Timer löst verspätet aus: Der Standard-AccuracySec-Wert beträgt 1 Minute. systemd fasst Aufweckvorgänge zusammen, um Energie zu sparen. Setzen Sie AccuracySec=1s, wenn Sie Präzision benötigen.

Verpasste Ausführungen werden nicht nachgeholt: Sie haben Persistent=true im Abschnitt [Timer] vergessen.

Zusammenfassung

  • systemd-Timer ersetzen Cron durch zwei Unit-Dateien: eine .service (was ausgeführt wird) und eine .timer (wann es ausgeführt wird)
  • OnCalendar verarbeitet uhrzeitbasierte Zeitpläne; OnBootSec und OnUnitActiveSec verarbeiten intervallbasierte Zeitgebung
  • Persistent=true holt verpasste Ausführungen nach Ausfallzeiten nach
  • systemd-analyze calendar ermöglicht die Validierung von Zeitplanausdrücken vor der Bereitstellung
  • Integriertes Logging über journalctl macht benutzerdefinierte Log-Umleitungen überflüssig
  • Ressourcenkontrollen (CPUQuota, MemoryMax) und Fehlerbenachrichtigungen bieten produktionsreife Zuverlässigkeit
  • Jeder Cron-Job kann mit unkomplizierter Syntax-Zuordnung auf einen systemd-Timer migriert werden
  • Verwenden Sie systemd-run für schnelle einmalige geplante Aufgaben ohne Unit-Dateien

Cron-Jobs unter Linux konfigurieren | journalctl: Linux-Systemprotokolle abfragen und analysieren | Linux-Dienste mit systemctl verwalten

Verwandte Artikel