SecOps Toolkit

Bidirektionaler Konverter: Crontab zu systemd-Timer

Die Migration von Cron-Jobs zu systemd-Timern verbessert Protokollierung, Kontrolle und das Nachholen verpasster Läufe, doch die manuelle Umsetzung der Syntax ist fehleranfällig. Dieses Werkzeug validiert Ihren Cron-Ausdruck, erklärt ihn in einfachen Worten, berechnet die nächsten fünf Ausführungen und erzeugt die Dateien .service und .timer zum direkten Kopieren.

Es funktioniert auch in die Gegenrichtung: Fügen Sie einen OnCalendar-Ausdruck ein und erhalten Sie, wo möglich, den passenden Cron-Ausdruck.

Warum von Cron auf systemd-Timer umsteigen

Cron plant seit Jahrzehnten Aufgaben unter Linux, doch systemd bietet klare betriebliche Vorteile: Jede Ausführung wird mit ihrem Exit-Code im Journal protokolliert, Units können Abhängigkeiten und Ressourcenlimits deklarieren, der Status lässt sich mit systemctl list-timers abfragen, und mit Persistent=true werden verpasste Läufe nachgeholt, wenn das System ausgeschaltet war. Dieses Werkzeug wandelt in beide Richtungen zwischen einem Cron-Ausdruck und den entsprechenden Dateien .service und .timer um.

Aufbau eines Cron-Ausdrucks

Eine Crontab-Zeile besteht aus fünf Feldern, die von links nach rechts gelesen werden:

  • Minute (0-59), Stunde (0-23), Tag des Monats (1-31), Monat (1-12 oder Namen) und Wochentag (0-7 oder Namen, wobei 0 und 7 Sonntag sind).
  • Operatoren: * (alle), , (Liste), - (Bereich) und / (Schrittweite). */15 bei den Minuten entspricht beispielsweise 0, 15, 30 und 45.
  • Makros: @hourly, @daily, @weekly, @monthly und @yearly.

Es gibt eine wenig bekannte Regel: Sind sowohl der Tag des Monats als auch der Wochentag eingeschränkt, führt Cron die Aufgabe aus, wenn eines von beiden zutrifft (ODER-Verknüpfung). systemd verlangt dagegen, dass beide zutreffen. Deshalb erzeugt das Werkzeug in diesem Fall zwei OnCalendar-Zeilen.

Aufbau von OnCalendar

Das systemd-Format lautet Wochentag JJJJ-MM-TT HH:MM:SS, wobei jede Komponente *, Listen mit Komma, Bereiche mit .. und Wiederholungen mit / zulässt. Die Sekunden werden mit :00 ergänzt, um die Minutengranularität von Cron nachzubilden.

  • 30 2 * * * wird zu *-*-* 02:30:00.
  • */15 * * * * wird zu *-*-* *:00/15:00.
  • 0 9 * * 1-5 wird zu Mon..Fri *-*-* 09:00:00.
  • 0 4 1 * * wird zu *-*-1 04:00:00.

Die zwei Dateien: Service und Timer

Die .service-Datei beschreibt, was ausgeführt wird. Sie wird als Type=oneshot deklariert, weil die Aufgabe startet, endet und sich beendet. Sie unterstützt User=, WorkingDirectory= und ExecStart= mit dem absoluten Pfad der ausführbaren Datei. Die .timer-Datei beschreibt, wann ausgeführt wird:

  • OnCalendar=: der Kalenderausdruck, der dem Cron-Ausdruck entspricht.
  • Persistent=true: speichert den Zeitpunkt der letzten Aktivierung auf der Festplatte und holt verpasste Läufe beim Systemstart nach.
  • AccuracySec=: Toleranzfenster, um Aktivierungen zusammenzufassen und Energie zu sparen. Der Standardwert beträgt 1 Minute; mit 1s erfolgt die Ausführung nahezu exakt.
  • Unit= und der Abschnitt [Install] mit WantedBy=timers.target, damit der Timer beim Systemstart aktiviert wird.

Unterschiede in der Umgebung, die zu Fehlern führen

  • Minimaler PATH: systemd übernimmt nicht die Umgebung Ihrer Shell. Verwenden Sie in ExecStart absolute Pfade.
  • Standardmäßig keine Shell: Pipes, Umleitungen und Variablen erfordern /bin/sh -c '...', was das Werkzeug automatisch ergänzt.
  • Sonderzeichen: In einer Unit-Datei haben % und $ eine eigene Bedeutung und werden als %% und $$ maskiert. In der Crontab entspricht ein nicht maskiertes % einem Zeilenumbruch.
  • Keine E-Mail: Cron sendet die Ausgabe per E-Mail (MAILTO); systemd legt sie im Journal ab, das Sie mit journalctl -u name.service abfragen.

Empfohlene Prüfung

Bevor Sie den Timer aktivieren, validieren Sie den Kalender mit systemd-analyze calendar "*-*-* 02:30:00", das die normalisierte Form und die nächste Ausführung anzeigt, und prüfen Sie die Syntax der Units mit systemd-analyze verify. Nach der Aktivierung bestätigt systemctl list-timers, wann die nächste Ausführung ansteht.

Praxisbeispiele

  • Nächtliche Backups mit Persistent=true, damit sie nicht verloren gehen, wenn der Server ausgeschaltet war.
  • Log-Rotation und Bereinigung mit niedrig priorisierten Läufen und großzügigem AccuracySec.
  • Zertifikatserneuerung und Synchronisation mit auditierbarer Protokollierung im Journal.
  • Migrationsprüfungen: eine geerbte Crontab gesammelt umwandeln und prüfen, welche Aufgaben von Umgebungsvariablen abhängen.

Zeitzone

Cron und systemd führen Aufgaben nach der Zeitzone des Servers aus, sofern keine andere angegeben ist. Das Werkzeug zeigt die nächsten fünf Ausführungen in der lokalen Zeit Ihres Browsers oder in UTC an, damit Sie prüfen können, ob der Kalender Ihren Erwartungen entspricht.

Häufig gestellte Fragen

Was bewirkt Persistent=true bei einem systemd-Timer genau?
Mit Persistent=true speichert systemd den Zeitpunkt der letzten Aktivierung des Timers auf der Festplatte. War das System zum geplanten Zeitpunkt ausgeschaltet oder im Ruhezustand, wird die Aufgabe beim nächsten Start sofort nachgeholt. Das Verhalten entspricht dem von anacron und wirkt nur bei kalenderbasierten Timern (OnCalendar). Besonders nützlich ist es bei Notebooks, virtuellen Maschinen, die heruntergefahren werden, und Servern mit Wartungsfenstern.
Warum erzeugt ein Cron-Ausdruck mit Tag des Monats und Wochentag zwei OnCalendar-Zeilen?
Weil Cron und systemd diese Kombination unterschiedlich auslegen. In Cron wird die Aufgabe ausgeführt, wenn eines der beiden eingeschränkten Felder zutrifft (ODER). Bei OnCalendar müssen Tag des Monats und Wochentag gleichzeitig zutreffen (UND). Um das Verhalten von Cron nachzubilden, erzeugt das Werkzeug eine Zeile für den Tag des Monats und eine für den Wochentag; systemd aktiviert den Timer dann, sobald eine der beiden Zeilen passt.
Welchen Wert sollte ich für AccuracySec wählen?
Der systemd-Standard beträgt 1 Minute, wodurch nahe beieinander liegende Aktivierungen zusammengefasst und CPU-Aufweckvorgänge reduziert werden. Soll die Aufgabe nahezu sekundengenau starten, verwenden Sie 1s, die im Werkzeug voreingestellte Option. Für wenig zeitkritische Jobs wie Bereinigungen oder Berichte sparen 1min oder sogar 1h Energie. Wenn Sie die Last vieler Server verteilen möchten, kombinieren Sie ein großzügiges AccuracySec mit RandomizedDelaySec.
Warum funktioniert mein Befehl in Cron, schlägt im systemd-Service aber fehl?
Die häufigsten Ursachen sind ein abweichender PATH, fehlende Umgebungsvariablen, die Verwendung von Shell-Funktionen ohne Aufruf einer Shell und Sonderzeichen. systemd führt den Befehl nicht in einer Shell aus, daher erfordern Pipes, Umleitungen und Variablenexpansion /bin/sh -c. Außerdem müssen % und $ in der Unit-Datei als %% und $$ maskiert werden. Verwenden Sie absolute Pfade, prüfen Sie den Fehler mit journalctl -u name.service und testen Sie den Service mit systemctl start, bevor Sie den Timer aktivieren.
Kann ich Aufgaben als normaler Benutzer ohne root planen?
Ja. Legen Sie die Units unter ~/.config/systemd/user/ ab und verwalten Sie sie mit systemctl --user, zum Beispiel systemctl --user enable --now name.timer. Damit sie auch ohne offene Sitzung laufen, muss ein Administrator die Persistenz Ihres Benutzers mit loginctl enable-linger aktivieren. In diesem Fall wird die Direktive User= im Service nicht verwendet, da die Unit bereits unter Ihrem eigenen Benutzer läuft. Das Werkzeug erzeugt System-Dateien, die sich leicht für diese Variante anpassen lassen.