Blog članak

Pouzdani systemd timeri: zamjena za cron bez iznenađenja

Praktičan vodič za migraciju s crona na systemd timere: pisanje pouzdanog para .timer/.service, prevođenje rasporeda i njihovih zamki, sužavanje ovlasti, provjera izvršavanja i siguran povratak.

Budilica na stalku poslužitelja uz papirnati raspored i terminal s popisom zakazanih poslova

Cron radi. Jedan redak u crontabu zakazuje naredbu i stroj je izvršava godinu za godinom bez ikakvog daemona koji bi ga čuvao. Nevolje se pojavljuju na rubovima te jednostavnosti. Posao još traje kad stigne njegov sljedeći termin, ponovno pokretanje tiho preskoči noćnu sigurnosnu kopiju, skripta padne, a jedini trag je e-mail koji nitko ne čita. systemd timeri zamjenjuju cron, a pritom te rubove pretvaraju u izričitu konfiguraciju: ovisnosti, preklapanje, propuštena izvršavanja, ograničenja trajanja i zapisi u journalu dobivaju svaki svoju direktivu umjesto pretpostavke.

Ovo je vodič za migraciju, a ne još jedan pregled systemd značajki. Za širu sliku izdanja iz 2025.–2026. — uklanjanje cgroup v1, ukidanje SysV init skripti, trajno zapisivanje journala — pročitajte prateći članak systemd u 2026.: Što se promijenilo. Sve što slijedi pretpostavlja par datoteka jedinica koje možete napisati, validirati i isprobati na pripremnom hostu prije nego što zakazuje bilo što važno.

Što vam timer daje, a crontab ne može izraziti

Cron redak opisuje što pokrenuti i kada. Ne govori ništa o redoslijedu, istovremenosti, vremenskim ograničenjima ni resursima, pa operateri to dodaju shell omotima i flock pozivima. systemd model jedinica svaku od tih briga čini direktivom prvog reda, dokumentiranom u systemd.timer(5):

  • Redoslijed. After=network-online.target uz Wants=network-online.target osigurava da posao krene kad je mreža upotrebljiva, bez sleep 30 trika na vrhu skripte.
  • Zaštita od preklapanja. systemd odbija pokrenuti jedinicu koja se već aktivira ili izvršava. Spori posao jednostavno preskoči preklapajući okidač umjesto da naslaže drugu kopiju koja se otima o iste datoteke.
  • Nadoknada propuštenog izvršavanja. Persistent=true pamti vrijeme posljednjeg okidanja i pokreće posao jednom nakon zastoja, pa ponovno pokretanje više ne briše noćno izvršavanje.
  • Ograničeno trajanje. TimeoutStartSec= zaustavlja posao koji se zaglavio, zamjenjujući misterij “ipak je završio prošli mjesec”.
  • Gornje granice resursa. CPUQuota= i MemoryMax= sprječavaju da jedan odbjegli batch posao izgladni usluge na istom hostu.
  • Zapisivanje u journal. Standardni izlaz i pogreške svakog izvršavanja završavaju u journalu pod imenom jedinice, što je znatno pouzdanije od MAILTO i ručno napisanog >> preusmjeravanja.

Cron i dalje zaslužuje svoje mjesto za trivijalno održavanje u jednom retku kojem ne trebaju ni redoslijed, ni zaštita od preklapanja, ni putanja za slučaj greške. Migracija se isplati za poslove o kojima ovisi sustav, a ne za svaki redak u datoteci.

Par jedinica, ispisan

systemd timer su uvijek dvije jedinice: .timer koji nosi raspored i istoimeni .service koji nosi sam posao. Ta veza u imenu omogućuje da systemctl enable --now backup-job.timer aktivira cijeli sklop. Evo noćnog posla sigurnosne kopije migriranog iz cron retka, s timerom na prvom mjestu:

# /etc/systemd/system/backup-job.timer
[Unit]
Description=Nightly backup timer

[Timer]
# Recurring calendar form = "every day at 02:30:00 server time"
OnCalendar=*-*-* 02:30:00
# Fire once shortly after boot if a scheduled run was missed while powered off
Persistent=true
# Spread start times so many hosts do not hit the storage backend together
RandomizedDelaySec=15min

[Install]
# Enable THIS unit, never the .service
WantedBy=timers.target

Dva su detalja važnija od ostalih. WantedBy=timers.target pripada timeru: omogućavanje .service jedinice pokrenulo bi posao pri svakom podizanju sustava umjesto po rasporedu. Persistent=true nadoknađuje jedno propušteno izvršavanje — ne ponavlja svaki preskočeni interval, pa posao koji nije radio tri dana okine jednom, a ne tri puta.

Pridružena usluga nosi politiku izvršavanja. Za sam posao sigurnosne kopije, vodič Strategije sigurnosnog kopiranja 2026. pokriva alat i stranu zadržavanja kopija:

# /etc/systemd/system/backup-job.service
[Unit]
Description=Nightly backup job (migrated from cron)
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
User=backup
WorkingDirectory=/opt/app
# systemd starts with a minimal environment and sources no shell profile
Environment=PATH=/usr/local/bin:/usr/bin:/bin
# "-" makes a missing environment file non-fatal
EnvironmentFile=-/etc/default/backup
ExecStart=/usr/local/bin/backup.sh
TimeoutStartSec=3600

Type=oneshot pravi je izbor za batch posao: jedinica se smatra aktivnom dok ExecStart ne završi, što je upravo gore opisana zaštita od preklapanja. TimeoutStartSec=3600 ograničava zaglavljeno izvršavanje na jedan sat. Jedna je suptilnost preciznost tempiranja — systemd ne obećava točnu minutu iz OnCalendar. AccuracySec= zadano iznosi jednu minutu, pa timer u 02:30 može krenuti unutar tog prozora, a RandomizedDelaySec ga namjerno proširuje.

Prevođenje cron rasporeda bez iznenađenja

Većina cron izraza čisto se preslikava na OnCalendar, ali nekoliko ih se prevede u drugačije ponašanje ako ne pazite. Pravila sintakse nalaze se u systemd.time(7). Validirajte svaki izraz s systemd-analyze calendar prije nego što bilo što omogućite:

systemd-analyze calendar '*-*-* 02:30:00'
systemd-analyze calendar 'Mon *-*-* 03:00:00'

Uobičajene pretvorbe:

Cronsystemd OnCalendarNa što pripaziti
0 2 * * **-*-* 02:00:00Jednostavno
*/15 * * * **-*-* *:00/15:00Prefiks datuma je obavezan
0 3 * * 1Mon *-*-* 03:00:00Naziv dana zamjenjuje broj
@daily*-*-* 00:00:00Ekvivalentno
@weeklySun *-*-* 00:00:00systemdova kratica weekly znači ponedjeljak, a cronov @weekly znači nedjelju
@rebootOnBootSec=5minUopće nije kalendarski izraz

Zamka koja najjače ugrize jest cronovo pravilo dana u mjesecu / dana u tjednu. U cronu se 0 0 1 * 1 izvršava kad je dan 1. ili kad je dan ponedjeljak — to je OR, što iznenadi gotovo svakoga. systemd nema OR operator, pa tu namjeru razdvojite na dva timera, jedan za 1. i jedan za ponedjeljke. Druga je zamka @reboot: za nju ne postoji kalendarski ekvivalent, a OnBootSec=5min u odjeljku [Timer] ispravna je zamjena.

Naposljetku, semantika vremenske zone razlikuje se. OnCalendar se procjenjuje u vremenskoj zoni timera, pa se poslužitelj vezan na UTC ponaša drugačije od onoga na lokalnom vremenu kad se pomakne ljetno računanje vremena. Na hostovima koji su važni izričito postavite željenu vremensku zonu i provjerite granicu ljetnog računanja vremena jednako kao što provjeravate i sam raspored.

Najmanje ovlasti bez lomljenja posla

Prvi je korak u očvršćivanju okruženje, jer migrirani posao koji ne može pronaći svoje binarne datoteke pada na zbunjujuće načine. Postavite User= i Group= na račun pod kojim se cron posao doista izvršavao — česta je greška pri migraciji pustiti posao koji je radio pod servisnim računom da tiho radi kao root. Postavite WorkingDirectory= ako skripta pretpostavlja radni direktorij i izričito postavite PATH jer systemd ne učitava ni jedan shell profil. Ako poslu trebaju tajne ili podesive vrijednosti, čitajte ih iz EnvironmentFile=-/etc/default/<name> umjesto da ih izvozite u omotnoj skripti. Priručnik systemd.exec(5) navodi cijeli skup direktiva.

Zatvaranje u pješčanik dolazi drugo, dodavano postupno kako se ispravan posao ne bi pokvario preko noći:

ProtectSystem=strict
ProtectHome=read-only
PrivateTmp=true
ReadWritePaths=/var/lib/backup
CPUQuota=50%
MemoryMax=2G

ProtectSystem=strict većinu datotečnog sustava čini samo za čitanje, pa ga uparite s ReadWritePaths= za svaki direktorij u koji posao legitimno piše. PrivateTmp=true daje poslu vlastiti /tmp, što kvari alate koji putem te putanje dijele datoteke s drugim procesima. Gornje granice resursa najvažnije su na dijeljenim hostovima — vodič za podešavanje performansi Linux poslužitelja pokriva kako te granice djeluju na ostatak opterećenja. Reproducirajte točno okruženje s systemd-run prije nego što uredite aktivnu jedinicu i potvrdite da posao i dalje uspijeva:

sudo systemd-run --property=User=backup --property=ProtectSystem=strict \
  --property=ReadWritePaths=/var/lib/backup --property=CPUQuota=50% \
  /usr/local/bin/backup.sh

Provjerite kao operater

Povjerenje dolazi iz promatranih izvršavanja, a ne iz uspješnog enable. Prođite ovim slijedom za svaki migrirani posao.

Najprije validirajte datoteke jedinica na sintaksu i nedostajuće binarne datoteke. systemd-analyze verify učitava jedinice i prijavljuje nepoznate direktive i nerazriješene putanje u ExecStart, kako je opisano u systemd-analyze(1):

sudo systemd-analyze verify /etc/systemd/system/backup-job.service /etc/systemd/system/backup-job.timer

Zatim omogućite timer i pregledajte raspored koji je systemd doista izračunao:

sudo systemctl daemon-reload
sudo systemctl enable --now backup-job.timer
systemctl list-timers --all

systemctl list-timers --all prikazuje sljedeće i posljednje vrijeme okidanja za svaki timer, što je najbrži način da uhvatite raspored koji ne znači ono što ste mislili. Prisilite jedno ručno izvršavanje kako bi se greške pokazale dok gledate, umjesto da čekate na sat:

sudo systemctl start backup-job.service
journalctl -u backup-job.service --since today

Zapis u journalu za uslugu zamjena je za cronove e-mail obavijesti i preusmjeravanja zapisa — standardni izlaz, pogreške i izlazni status izvršavanja svi se nalaze pod journalctl -u. Završite s systemctl --failed kako biste potvrdili da ništa na hostu ne stoji u stanju greške nakon promjene.

Runbook migracije

Najprije pretvorite poslove o kojima ovisi sustav, jedan po jedan, i nikada ne pretvarajte cijeli crontab u jednom prolazu. Započnite potpunim popisom, jer cron rasporedi žive na više mjesta nego što se većina administratora sjeća:

cat /etc/crontab
ls -la /etc/cron.d/
ls -la /etc/cron.{daily,weekly,monthly}/
for u in $(cut -f1 -d: /etc/passwd); do crontab -l -u "$u" 2>/dev/null; done

Za svaki zapis zakomentirajte cron redak umjesto da ga izbrišete, napišite par jedinica, omogućite timer i potvrdite jedno uspješno izvršavanje u journalu. Usporedite systemctl list-timers --all s popisom dok se brojevi ne poklope. Zakomentirane cron zapise uklonite tek nakon što svaki migrirani posao ima zabilježeno uspješno izvršavanje. Poslovi po korisniku slijede isti oblik pod ~/.config/systemd/user/, kojima se upravlja s systemctl --user; korisnički timer koji mora raditi dok je korisnik odjavljen treba loginctl enable-linger <user>. Čitatelji koji pokreću kontejnerska opterećenja dobivaju isti model jedinica za usluge u Deklarativni kontejneri sa systemdom i Podman Quadletom.

Opasnosti i povratak

Najopasniji je trenutak istovremeno pokretanje oba zakazivača za isti posao. systemdova zaštita od preklapanja ne čini ništa protiv cron posla koji okine pokraj timera, a neidempotentan posao koji kopira ili prenosi podatke pokvarit će vlastito odredište kad se dvije kopije otimaju. Zakomentirajte cron redak u istoj promjeni kojom omogućujete timer i nikada ne ostavljajte posao zakazan na oba mjesta.

Ostale opasnosti koje vrijedi planirati:

  • Stanje Persistent=true. Oznaka posljednjeg okidanja živi pod /var/lib/systemd/timers. Očistite je s systemctl clean --what=state <name>.timer prije uklanjanja timera, inače kasnija ponovna instalacija može izazvati neočekivano nadoknadno izvršavanje.
  • Obavijest o grešci. MAILTO ima izravnu zamjenu — pridružite jedinicu OnFailure= usluzi koja podiže uzbunu, pa neuspjelo izvršavanje neće proći tiho.
  • Pomak vremenske zone. Vezite željenu vremensku zonu na poslužiteljima koji prelaze granice ljetnog računanja vremena i postavite Persistent=true samo za poslove kod kojih je zakašnjelo nadoknadno izvršavanje prihvatljivo. Posao koji mora ostati unutar prozora za održavanje trebao bi izostaviti Persistent=true umjesto da se bori s logikom nadoknade.

Povratak je namjerno dosadan, što je i smisao ostavljanja cron zapisa na mjestu:

sudo systemctl disable --now backup-job.timer
# then uncomment the original crontab line and confirm it still runs

Onemogućavanje timera zaustavlja buduće zakazivanje, a jedinice ostaju na disku za pregled. Ukidanje komentara na cron zapisu odmah vraća prethodno ponašanje, pa se migracija koja se u produkciji ne ponaša kako treba može poništiti jednim korakom bez ponovnog sastavljanja izvorne naredbe.

Nagrada je raspored o kojem možete razmišljati: korisnik posla, okruženje, vremensko ograničenje, gornja granica resursa i mjesto zapisa svi su deklarirani u datotekama jedinica umjesto da ih podrazumijeva ljuska koju je posao slučajno naslijedio. Migrirajte jedan posao, promatrajte njegov journal i model s timerima prestaje se doimati kao dodatna ceremonija te počinje djelovati kao sigurnosna mreža koju cron nikada nije imao.

Povezana područja

Ova su područja rada usklađena s temom članka i daju čišći prijelaz od edukativnog sadržaja do konkretne implementacije.

Nastavite čitati

Prvo po zajedničkim kategorijama, a zatim po najjačem preklapanju u tagovima.