Cron nadal działa i w wielu miejscach jest wystarczający. Problem zaczyna się wtedy, gdy po kilku miesiącach trzeba ustalić, czy zadanie wykonało się poprawnie, gdzie są logi, dlaczego nie ruszyło po restarcie albo kto dopisał przekierowanie do pliku w katalogu, którego już nie ma.
W takich przypadkach warto użyć systemd timer. Nie dlatego, że cron jest zły, tylko dlatego, że timer systemd lepiej pasuje do serwerów, na których i tak diagnozujemy usługi przez systemctl oraz journalctl.
Poniżej praktyczny przykład: prosty backup katalogu /etc uruchamiany codziennie o 02:30.
Kiedy systemd timer ma sens
Timer systemd warto rozważyć, gdy chcesz:
- mieć status zadania w
systemctl, - widzieć logi w
journalctl, - uruchomić zadanie po starcie systemu albo po określonym czasie,
- nadrobić pominięte wykonanie po wyłączonym serwerze,
- łatwo powiązać harmonogram z usługą,
- mieć osobny unit
.servicei osobny unit.timer, - użyć opcji takich jak
RandomizedDelaySecalboPersistent.
Cron jest prostszy do jednowierszowych zadań. Timer systemd jest wygodniejszy, gdy zadanie jest ważne i chcesz je normalnie monitorować jak usługę.
1. Skrypt backupu
Najpierw prosty skrypt:
sudo mkdir -p /usr/local/sbin /backup/system
sudo nano /usr/local/sbin/backup-etc.sh
Zawartość:
#!/usr/bin/env bash
set -euo pipefail
BACKUP_DIR="/backup/system"
DATE="$(date +%F-%H%M)"
mkdir -p "$BACKUP_DIR"
tar -czf "$BACKUP_DIR/etc-$DATE.tar.gz" /etc
find "$BACKUP_DIR" -type f -name "etc-*.tar.gz" -mtime +14 -delete
Uprawnienia:
sudo chmod 750 /usr/local/sbin/backup-etc.sh
sudo /usr/local/sbin/backup-etc.sh
ls -lh /backup/system
Najpierw uruchom skrypt ręcznie. Timer nie powinien być pierwszym testem działania skryptu.
2. Unit service
Tworzymy usługę, która wykona skrypt:
sudo nano /etc/systemd/system/backup-etc.service
Zawartość:
[Unit]
Description=Backup katalogu /etc
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup-etc.sh
To nie jest usługa działająca cały czas. Type=oneshot oznacza zadanie jednorazowe: uruchom skrypt i zakończ.
Test:
sudo systemctl daemon-reload
sudo systemctl start backup-etc.service
sudo systemctl status backup-etc.service --no-pager
journalctl -u backup-etc.service --no-pager
Jeżeli tutaj jest błąd, nie twórz jeszcze timera. Najpierw napraw usługę.
3. Unit timer
Teraz harmonogram:
sudo nano /etc/systemd/system/backup-etc.timer
Zawartość:
[Unit]
Description=Codzienny backup katalogu /etc
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=10min
Unit=backup-etc.service
[Install]
WantedBy=timers.target
Co tu się dzieje:
OnCalendar=*-*-* 02:30:00uruchamia zadanie codziennie o 02:30,Persistent=truepowoduje, że jeżeli serwer był wyłączony w czasie planowanego wykonania, zadanie zostanie nadrobione po uruchomieniu,RandomizedDelaySec=10minrozrzuca start w zakresie do 10 minut,Unit=backup-etc.servicewskazuje usługę, która ma zostać uruchomiona.
Manpage systemd.timer opisuje, że timer domyślnie aktywuje usługę o tej samej nazwie. Tu wpis Unit= jest jawny, żeby było czytelnie.
4. Włączenie timera
sudo systemctl daemon-reload
sudo systemctl enable --now backup-etc.timer
Sprawdzenie:
systemctl list-timers --all | grep backup-etc
systemctl status backup-etc.timer --no-pager
W list-timers zobaczysz między innymi następne planowane uruchomienie i ostatnie wykonanie. To jedna z największych przewag nad prostym wpisem w cronie.
5. Logi i diagnostyka
Logi usługi:
journalctl -u backup-etc.service --since "today" --no-pager
Logi timera:
journalctl -u backup-etc.timer --no-pager
Status usługi:
systemctl status backup-etc.service --no-pager
Jeżeli skrypt zakończy się kodem błędu, zobaczysz to w statusie usługi. Przy cronie często trzeba najpierw znaleźć, gdzie ktoś przekierował stdout i stderr.
6. Test harmonogramu bez czekania do nocy
Na czas testu możesz zmienić OnCalendar na coś krótkiego:
OnCalendar=*:0/5
To uruchamia timer co 5 minut. Po teście wróć do docelowej wartości i wykonaj:
sudo systemctl daemon-reload
sudo systemctl restart backup-etc.timer
systemctl list-timers --all | grep backup-etc
Nie zostawiaj testowego harmonogramu na produkcji. Backup co 5 minut szybko zrobi bałagan.
7. Różnica między OnCalendar i OnBootSec
OnCalendar działa według zegara kalendarzowego: konkretna godzina, dzień, tydzień, miesiąc.
Przykłady:
OnCalendar=daily
OnCalendar=Mon *-*-* 03:00:00
OnCalendar=*-*-01 04:00:00
OnBootSec albo OnUnitActiveSec są timerami monotonicznymi, liczonymi od startu systemu albo od ostatniej aktywacji.
Przykład:
OnBootSec=15min
OnUnitActiveSec=1h
To ma sens przy zadaniach technicznych, które mają ruszyć np. 15 minut po starcie i potem co godzinę. Do backupu o konkretnej godzinie zwykle lepszy jest OnCalendar.
8. Typowe błędy
Najczęstsze problemy:
- plik
.timeristnieje, ale nie ma odpowiadającego.service, - po edycji unitów nie wykonano
systemctl daemon-reload, - timer został włączony, ale usługa nie działa przy ręcznym
systemctl start, - skrypt nie ma uprawnień wykonywania,
- ścieżki w skrypcie są względne zamiast absolutnych,
- backup zapisuje się na tym samym dysku, który ma być ratowany,
Persistent=trueuruchamia zaległy backup w nieoczekiwanym momencie,RandomizedDelaySecpowoduje, że zadanie nie startuje dokładnie o wskazanej godzinie,- po zmianie harmonogramu nie zrestartowano timera.
Przy zadaniach produkcyjnych używaj pełnych ścieżek i zaczynaj skrypty od:
set -euo pipefail
To nie rozwiąże wszystkich problemów, ale ogranicza ciche błędy.
9. Jak usunąć timer
Wyłączenie:
sudo systemctl disable --now backup-etc.timer
Usunięcie plików:
sudo rm /etc/systemd/system/backup-etc.timer
sudo rm /etc/systemd/system/backup-etc.service
sudo systemctl daemon-reload
Jeżeli używasz Persistent=true, manpage systemd.timer wskazuje też możliwość czyszczenia stanu timera:
sudo systemctl clean --what=state backup-etc.timer
To przydaje się przy usuwaniu albo przebudowie timera, żeby nie został stary znacznik ostatniego wykonania.
Podsumowanie
Cron jest prosty i nadal ma swoje miejsce. Jeżeli jednak zadanie jest ważne, systemd timer daje wygodniejszą diagnostykę: systemctl status, journalctl, list-timers, osobny plik usługi i kontrolę nad zachowaniem po restarcie.
Dla backupów, rotacji plików, cyklicznych kontroli systemu i zadań administracyjnych na Ubuntu Server timer systemd często jest czytelniejszy niż wpis w cronie. Najważniejsze: najpierw sprawdź skrypt ręcznie, potem service, a dopiero na końcu timer.
Źródła
- systemd.timer manpage: https://man7.org/linux/man-pages/man5/systemd.timer.5.html
- systemd.service manpage: https://man7.org/linux/man-pages/man5/systemd.service.5.html
- systemctl manpage: https://man7.org/linux/man-pages/man1/systemctl.1.html