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:
- Eine
.service-Unit — definiert, was ausgeführt wird (der eigentliche Befehl oder das Skript) - 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) OnCalendarverarbeitet uhrzeitbasierte Zeitpläne;OnBootSecundOnUnitActiveSecverarbeiten intervallbasierte ZeitgebungPersistent=trueholt verpasste Ausführungen nach Ausfallzeiten nachsystemd-analyze calendarermöglicht die Validierung von Zeitplanausdrücken vor der Bereitstellung- Integriertes Logging über
journalctlmacht 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-runfür schnelle einmalige geplante Aufgaben ohne Unit-Dateien
Cron-Jobs unter Linux konfigurieren | journalctl: Linux-Systemprotokolle abfragen und analysieren | Linux-Dienste mit systemctl verwalten