EQVPS
PanouÎncepe

Cum programezi sarcini pe un VPS cu cron și timerele systemd

Rulează backupuri, curățări și scripturi după program. Cron în cinci minute, cu cele trei capcane care strică joburile pe tăcute, apoi timerele systemd pentru loguri, recuperare după oprire și oră exactă. Fiecare comportament de mai jos a fost testat pe un server Ubuntu 24.04 nou.

Un server își merită banii lucrând cât dormi: backupuri, rotirea logurilor, reînnoirea certificatelor, un raport la ora nouă. Linux are pentru asta două programatoare. Cron are patruzeci de ani și încape într-o linie. Timerele systemd cer două fișiere mici și oferă în schimb loguri, recuperare după oprire și oră exactă. Ghidul acesta le acoperă pe amândouă pe Ubuntu 24.04, cu fiecare comportament verificat pe un server nou din imaginea noastră, inclusiv cele trei greșeli care fac un job cron să eșueze fără niciun cuvânt.

Ai nevoie de un utilizator cu sudo; ghidul de configurare Ubuntu creează unul.

1. Cron în cinci minute

Cron e instalat și pornit pe imaginile noastre Ubuntu și Debian. Fiecare utilizator are un tabel de joburi; editează-l pe al tău cu:

crontab -e

Fiecare linie are cinci câmpuri de timp și o comandă:

# min hour day month weekday  command
  30  3    *   *     *        /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
  */5 *    *   *     *        /usr/local/bin/check.sh
  0   9    *   *     1-5      /usr/local/bin/report.sh
  @reboot                     /usr/local/bin/start-tunnel.sh

Adică: la 03:30 în fiecare noapte, la fiecare 5 minute, la 09:00 în zilele lucrătoare și o dată după fiecare pornire. */5 înseamnă fiecare a cincea valoare, 1-5 un interval, 1,15 o listă. Se aplică fusul orar al serverului, UTC pe imaginile noastre; setează-l pe al tău o dată cu ghidul despre hostname și fus orar, iar cron îl urmează.

Vezi ce a rulat cu journalctl -u cron. Fiecare rulare înregistrează utilizatorul și comanda, și acolo apar cele trei capcane.

Capcana 1: ieșirea dispare. Cron trimite pe email ieșirea unui job către utilizator. Imaginea noastră nu are server de mail, așa că jurnalul a scris (CRON) info (No MTA installed, discarding output) și ieșirea s-a pierdut. Redirecționeaz-o singur, cum face primul exemplu cu >> /var/log/backup.log 2>&1.

Capcana 2: semnul procent. Într-un crontab, % încheie comanda și transformă restul în intrare standard. Am programat date +%F > /tmp/today. Jurnalul arată ce a rulat de fapt cron: CMD (date +). Nu s-a scris niciun fișier și nicio eroare n-a ajuns la noi. Scrie \% sau pune comanda într-un script și programează scriptul.

Capcana 3: alt mediu. Cron rulează joburile cu /bin/sh, nu bash, în directorul tău home și cu un mediu restrâns. Pe Ubuntu 24.04 PATH-ul a fost mai bun decât reputația lui: calea completă de sistem, inclusiv /usr/local/bin și /snap/bin, pentru root și pentru un utilizator obișnuit. Ce lipsește în continuare e tot ce se află în home: ~/.local/bin, node-ul din nvm, pipx, cargo. Folosește căi complete în job sau începe linia cu . $HOME/.profile;.

Joburile care țin de sistem, nu de un utilizator, merg în /etc/cron.d/, ca fișier cu un câmp în plus, utilizatorul:

30 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1

Ubuntu rulează și tot ce se află în /etc/cron.hourly, cron.daily, cron.weekly și cron.monthly, la minutul 17 al fiecărei ore, la 06:25, duminica la 06:47 și pe 1 ale lunii la 06:52. Pune acolo un script executabil și va rula împreună cu celelalte.

2. Timerele systemd

Un timer înseamnă două unități: un serviciu care face treaba și un timer care spune când. Creează întâi scriptul, apoi unitățile.

sudo nano /usr/local/bin/backup.sh
sudo chmod +x /usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run the backup every night at 03:30

[Timer]
OnCalendar=*-*-* 03:30
Persistent=true
AccuracySec=1m

[Install]
WantedBy=timers.target

Activează timerul, nu serviciul:

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

list-timers arată următoarea rulare, cât mai e până la ea și ultima rulare. Logurile nu cer configurare: journalctl -u backup.service conține fiecare pornire, fiecare final și fiecare linie de ieșire, cu oră. Ca să rulezi jobul imediat, sudo systemctl start backup.service; tot așa testezi scriptul înainte să te bazezi pe program.

Sintaxa calendarului. OnCalendar se citește ziua-săptămânii an-lună-zi oră:minut:secundă, cu * pentru orice valoare. Testează o expresie înainte s-o folosești:

systemd-analyze calendar "Mon..Fri *-*-* 03:00" --iterations 2

Afișează forma normalizată și următoarele date. Câteva expresii pe care le-am verificat:

OnCalendarÎnseamnă
*-*-* 03:30Zilnic la 03:30
Mon..Fri *-*-* 09:00În zilele lucrătoare la 09:00
*:0/15La fiecare 15 minute
weeklyLunea la 00:00
*-*-01 04:00Pe 1 ale fiecărei luni la 04:00
*-*-* 03:00 Europe/Kyiv03:00 ora Kievului; la noi a rulat la 01:00 UTC

Cele trei setări de știut. Persistent=true salvează ultima rulare pe disc și recuperează o rulare ratată cât serverul a fost oprit sau timerul oprit. Am oprit timerul nostru de la două minute, am așteptat să treacă o rulare programată și l-am pornit din nou: rularea ratată a pornit în aceeași secundă. Fără Persistent, așteaptă pur și simplu următorul interval.

AccuracySec e surpriza. Implicit, systemd grupează timerele într-o fereastră de un minut ca să economisească treziri, așa că prima noastră rulare a venit la 07:42:18, nu la 07:42:00. Cu AccuracySec=1s, următoarele au căzut la secundă pe 07:46:00 și 07:48:00. Setează-l când contează minutul; lasă valoarea implicită pentru un backup de noapte.

RandomizedDelaySec=10m face intenționat invers: împrăștie pornirea într-o fereastră ca zece servere să nu lovească același spațiu de backup în aceeași secundă.

Pentru un job unic, nu trebuie niciun fișier:

sudo systemd-run --on-active=30m --unit=cleanup-once /usr/local/bin/cleanup.sh

Creează un timer temporar care pornește o dată și dispare; până atunci îl arată systemctl list-timers.

3. Pe care să-l alegi

CronTimer systemd
Configurare1 linie2 fișiere
LoguriDoar dacă redirecționezi ieșireajournalctl -u name.service
Rulare ratată cât serverul era opritPierdutăRulează la pornire cu Persistent=true
Jobul încă rulează la următorul ticPornește a doua copieSărit până termină prima
Oră exactăLa minutLa secundă cu AccuracySec=1s
StareNiciunalist-timers, systemctl status

Folosește cron pentru o linie rapidă pe care o recunoști și peste un an. Folosește un timer pentru tot ce trebuie să vezi când eșuează, ce nu are voie să se suprapună sau ce trebuie să ruleze după un restart ratat: backupuri, reînnoirea certificatelor, curățarea bazelor de date. Dacă un job cron se poate suprapune, înfășoară-l: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, iar a doua copie iese imediat.

Ambele programatoare pornesc un job și se opresc. Pentru un program care trebuie să meargă non-stop și să revină după o cădere ai nevoie de un serviciu, nu de un program orar; vezi cum creezi un serviciu systemd și, pentru Windows, cum rulezi un script 24/7 pe Windows Server. Un prim timer bun este cel din ghidul nostru de backup cu restic; actualizările automate de securitate sunt un timer pe care Ubuntu îl are deja, apt-daily-upgrade.timer, unul dintre cele 17 care rulează pe un server nou.

Întrebări frecvente

De ce jobul meu merge în terminal, dar nu în cron?

Trei motive obișnuite. Cron rulează jobul cu sh, nu cu bash, deci sintaxa specifică bash eșuează. Uneltele instalate în directorul tău home, ca nvm, pipx sau cargo, nu sunt în PATH-ul lui cron, așa că folosește căi complete. Și orice % din linia de comandă încheie comanda: pe serverul nostru date +%F a devenit date +. Scrie-l ca \% sau mută comanda într-un script.

Unde ajunge ieșirea lui cron?

Implicit, pe email. Imaginea noastră nu are server de mail, așa că cron scrie 'No MTA installed, discarding output' și ieșirea se pierde. Adaugă >> /var/log/myjob.log 2>&1 la job sau treci la un timer systemd, a cărui ieșire ajunge singură în jurnal.

Ce avantaj are un timer systemd față de cron?

Loguri în journalctl, nicio a doua copie a unui job încă în execuție, recuperarea cu Persistent=true a rulărilor ratate cât serverul a fost oprit și o linie de stare cu următoarea și ultima rulare. Cron câștigă la concizie: o linie în loc de două fișiere.

Timerul meu a pornit cu 18 secunde întârziere. De ce?

Implicit, systemd grupează timerele într-o fereastră de un minut ca să economisească treziri; asta e setarea AccuracySec. Timerul nostru de la două minute a pornit la 07:42:18 în loc de 07:42:00. Cu AccuracySec=1s a pornit fix la 07:46:00. Setează-l când contează minutul exact.

Ce fus orar folosesc cron și timerele?

Pe cel al serverului, UTC pe imaginile noastre. Setează-l o dată cu timedatectl, vezi ghidul nostru despre hostname și fus orar, iar cron și timerele îl urmează. Un timer poate avea și propriul fus: OnCalendar=*-*-* 03:00 Europe/Kyiv a rulat la 01:00 UTC în testul nostru.

Comentarii

Încă nu există comentarii. Fii primul.

Lasă un comentariu

Comentariile sunt moderate înainte să apară.