EQVPS
DashboardInizia

Come pianificare attività su un VPS con cron e i timer di systemd

Esegui backup, pulizie e script a orario. Cron in cinque minuti con le tre trappole che rompono i job in silenzio, poi i timer di systemd per log, recupero dopo un fermo e orario esatto. Ogni comportamento qui sotto è stato testato su un server Ubuntu 24.04 appena creato.

Un server si ripaga lavorando mentre dormi: backup, rotazione dei log, rinnovo dei certificati, un report alle nove. Linux ha due pianificatori per questo. Cron ha quarant'anni e sta in una riga. I timer di systemd richiedono due piccoli file e in cambio danno log, recupero dopo un fermo e orario esatto. Questa guida li copre entrambi su Ubuntu 24.04, con ogni comportamento verificato su un server nuovo dalla nostra immagine, compresi i tre errori che fanno fallire un job di cron senza una parola.

Ti serve un utente con sudo; la guida all'installazione di Ubuntu ne crea uno.

1. Cron in cinque minuti

Cron è installato e attivo sulle nostre immagini Ubuntu e Debian. Ogni utente ha una tabella di job; modifica la tua con:

crontab -e

Ogni riga ha cinque campi di tempo e un comando:

# 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

Cioè: alle 03:30 ogni notte, ogni 5 minuti, alle 09:00 nei giorni feriali e una volta dopo ogni avvio. */5 significa un valore ogni cinque, 1-5 un intervallo, 1,15 un elenco. Vale il fuso orario del server, UTC sulle nostre immagini; imposta il tuo una volta con la guida su hostname e fuso orario e cron lo segue.

Controlla cosa è stato eseguito con journalctl -u cron. Ogni esecuzione registra utente e comando, ed è lì che emergono le tre trappole.

Trappola 1: l'output sparisce. Cron invia per email l'output di un job all'utente. La nostra immagine non ha un server di posta, quindi il journal riportava (CRON) info (No MTA installed, discarding output) e l'output era perso. Reindirizzalo tu, come nel primo esempio con >> /var/log/backup.log 2>&1.

Trappola 2: il segno di percentuale. In una crontab % chiude il comando e trasforma il resto in input standard. Abbiamo pianificato date +%F > /tmp/today. Il journal mostra cosa ha eseguito davvero cron: CMD (date +). Nessun file scritto e nessun errore arrivato a noi. Scrivi \%, oppure metti il comando in uno script e pianifica lo script.

Trappola 3: un ambiente diverso. Cron esegue i job con /bin/sh, non bash, nella tua home e con un ambiente ridotto. Su Ubuntu 24.04 il PATH si è rivelato migliore della sua fama: il percorso di sistema completo, inclusi /usr/local/bin e /snap/bin, per root e per un utente normale. Ciò che manca ancora è tutto quello sotto la tua home: ~/.local/bin, il node di nvm, pipx, cargo. Usa percorsi completi nel job o inizia la riga con . $HOME/.profile;.

I job che appartengono al sistema e non a un utente vanno in /etc/cron.d/, come file con un campo in più, l'utente:

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

Ubuntu esegue anche tutto ciò che si trova in /etc/cron.hourly, cron.daily, cron.weekly e cron.monthly, al minuto 17 di ogni ora, alle 06:25, alle 06:47 la domenica e alle 06:52 il primo del mese. Metti lì uno script eseguibile e girerà con gli altri.

2. Timer di systemd

Un timer sono due unità: un servizio che fa il lavoro e un timer che dice quando. Crea prima lo script, poi le unità.

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

Abilita il timer, non il servizio:

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

list-timers mostra la prossima esecuzione, quanto manca e l'ultima esecuzione. I log non richiedono configurazione: journalctl -u backup.service contiene ogni avvio, ogni fine e ogni riga di output, con orario. Per eseguire subito il job, sudo systemctl start backup.service; è anche così che provi lo script prima di fidarti della pianificazione.

Sintassi del calendario. OnCalendar si legge giornosettimana anno-mese-giorno ora:minuto:secondo, con * per qualsiasi valore. Prova un'espressione prima di usarla:

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

Stampa la forma normalizzata e le prossime date. Alcune espressioni che abbiamo verificato:

OnCalendarSignificato
*-*-* 03:30Ogni giorno alle 03:30
Mon..Fri *-*-* 09:00Nei giorni feriali alle 09:00
*:0/15Ogni 15 minuti
weeklyIl lunedì alle 00:00
*-*-01 04:00Il primo di ogni mese alle 04:00
*-*-* 03:00 Europe/KyivLe 03:00 ora di Kyiv; nel nostro test è partito alle 01:00 UTC

Le tre impostazioni da conoscere. Persistent=true salva l'ultima esecuzione su disco e recupera un'esecuzione persa mentre il server era spento o il timer fermo. Abbiamo fermato il nostro timer ogni due minuti, atteso che passasse un'esecuzione prevista e lo abbiamo riavviato: l'esecuzione persa è partita nello stesso secondo. Senza Persistent, aspetta semplicemente lo slot successivo.

AccuracySec è la sorpresa. Di default systemd raggruppa i timer in una finestra di un minuto per risparmiare risvegli, così la nostra prima esecuzione è arrivata alle 07:42:18, non alle 07:42:00. Con AccuracySec=1s le successive sono cadute alle 07:46:00 e 07:48:00 al secondo. Impostalo quando conta il minuto; lascia il default per un backup notturno.

RandomizedDelaySec=10m fa il contrario, di proposito: distribuisce l'avvio su una finestra perché dieci server non colpiscano lo stesso storage di backup nello stesso secondo.

Per un job una tantum, nessun file:

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

Crea un timer transitorio che scatta una volta e sparisce; fino ad allora lo mostra systemctl list-timers.

3. Quale usare

CronTimer systemd
Configurazione1 riga2 file
LogSolo se reindirizzi l'outputjournalctl -u name.service
Esecuzione persa a server spentoPersaEseguita all'avvio con Persistent=true
Job ancora in corso al tick successivoParte una seconda copiaSaltato finché la prima non finisce
Orario esattoAl minutoAl secondo con AccuracySec=1s
StatoNessunolist-timers, systemctl status

Usa cron per una riga veloce che riconoscerai tra un anno. Usa un timer per tutto ciò di cui devi vedere il fallimento, che non deve sovrapporsi o che deve girare dopo un riavvio mancato: backup, rinnovo dei certificati, pulizia dei database. Se un job cron può sovrapporsi, avvolgilo: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, e la seconda copia esce subito.

Entrambi i pianificatori avviano un job e si fermano. Per un programma che deve girare sempre e ripartire dopo un crash serve un servizio, non una pianificazione; vedi come creare un servizio systemd e, per Windows, come eseguire uno script 24/7 su Windows Server. Un buon primo timer è quello della nostra guida al backup con restic; gli aggiornamenti di sicurezza automatici sono un timer che Ubuntu fornisce già, apt-daily-upgrade.timer, uno dei 17 attivi su un server nuovo.

FAQ

Perché il mio job funziona nel terminale ma non in cron?

Tre motivi tipici. Cron esegue il job con sh, non con bash, quindi la sintassi solo bash fallisce. Gli strumenti installati nella tua home, come nvm, pipx o cargo, non sono nel PATH di cron: usa percorsi completi. E ogni % nella riga di comando chiude il comando: sul nostro server date +%F è diventato date +. Scrivilo come \% o sposta il comando in uno script.

Dove finisce l'output di cron?

Per email, di default. La nostra immagine non ha un server di posta, quindi cron scrive nel journal 'No MTA installed, discarding output' e l'output va perso. Aggiungi >> /var/log/myjob.log 2>&1 al job, oppure passa a un timer systemd, il cui output finisce da solo nel journal.

Che vantaggio ha un timer systemd rispetto a cron?

Log in journalctl, nessuna seconda copia di un job ancora in corso, recupero con Persistent=true delle esecuzioni perse mentre il server era spento, e una riga di stato con la prossima e l'ultima esecuzione. Cron vince sulla brevità: una riga invece di due file.

Il mio timer è partito con 18 secondi di ritardo. Perché?

Di default systemd raggruppa i timer in una finestra di un minuto per risparmiare risvegli: è l'impostazione AccuracySec. Il nostro timer ogni due minuti è partito alle 07:42:18 invece che alle 07:42:00. Con AccuracySec=1s è partito alle 07:46:00 esatte. Impostala quando conta il minuto esatto.

Quale fuso orario usano cron e i timer?

Quello del server, UTC sulle nostre immagini. Impostalo una volta con timedatectl, vedi la nostra guida su hostname e fuso orario, e cron e timer lo seguono. Un timer può anche avere un fuso proprio: OnCalendar=*-*-* 03:00 Europe/Kyiv è partito alle 01:00 UTC nel nostro test.

Commenti

Ancora nessun commento. Sii il primo.

Lascia un commento

I commenti sono moderati prima di comparire.