EQVPS

Πώς προγραμματίζετε εργασίες σε VPS με cron και timers του systemd

Τρέξτε backups, καθαρισμούς και scripts με πρόγραμμα. Το cron σε πέντε λεπτά με τις τρεις παγίδες που χαλάνε σιωπηλά τις εργασίες, και μετά οι timers του systemd για logs, αναπλήρωση μετά από διακοπή και ακριβή ώρα. Κάθε συμπεριφορά παρακάτω δοκιμάστηκε σε νέο server με Ubuntu 24.04.

Ένας server αξίζει τα λεφτά του όταν δουλεύει ενώ κοιμάστε: backups, εναλλαγή logs, ανανέωση πιστοποιητικών, μια αναφορά στις εννιά. Το Linux έχει δύο χρονοπρογραμματιστές γι' αυτό. Το cron είναι σαράντα χρονών και θέλει μία γραμμή. Οι timers του systemd θέλουν δύο μικρά αρχεία και δίνουν σε αντάλλαγμα logs, αναπλήρωση μετά από διακοπή και ακριβή ώρα. Αυτός ο οδηγός καλύπτει και τα δύο στο Ubuntu 24.04, με κάθε συμπεριφορά ελεγμένη σε νέο server από το image μας, μαζί με τα τρία λάθη που κάνουν μια εργασία cron να αποτυγχάνει χωρίς λέξη.

Χρειάζεστε χρήστη με sudo· ο οδηγός ρύθμισης Ubuntu δημιουργεί έναν.

1. Το cron σε πέντε λεπτά

Το cron είναι εγκατεστημένο και τρέχει στα images Ubuntu και Debian μας. Κάθε χρήστης έχει πίνακα εργασιών· επεξεργαστείτε τον δικό σας με:

crontab -e

Κάθε γραμμή έχει πέντε πεδία χρόνου και μια εντολή:

# 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

Δηλαδή: στις 03:30 κάθε νύχτα, κάθε 5 λεπτά, στις 09:00 τις καθημερινές και μία φορά μετά από κάθε εκκίνηση. Το */5 σημαίνει κάθε πέμπτη τιμή, το 1-5 εύρος, το 1,15 λίστα. Ισχύει η ζώνη ώρας του server, UTC στα images μας· ορίστε τη δική σας μία φορά με τον οδηγό για hostname και ζώνη ώρας και το cron ακολουθεί.

Δείτε τι έτρεξε με journalctl -u cron. Κάθε εκτέλεση καταγράφει τον χρήστη και την εντολή, και εκεί φαίνονται οι τρεις παγίδες.

Παγίδα 1: η έξοδος εξαφανίζεται. Το cron στέλνει με email την έξοδο μιας εργασίας στον χρήστη. Το image μας δεν έχει mail server, οπότε το journal έγραφε (CRON) info (No MTA installed, discarding output) και η έξοδος χάθηκε. Ανακατευθύνετέ τη μόνοι σας, όπως το πρώτο παράδειγμα με >> /var/log/backup.log 2>&1.

Παγίδα 2: το σύμβολο του ποσοστού. Σε ένα crontab το % τερματίζει την εντολή και κάνει το υπόλοιπο τυπική είσοδο. Προγραμματίσαμε date +%F > /tmp/today. Το journal δείχνει τι έτρεξε πραγματικά το cron: CMD (date +). Δεν γράφτηκε αρχείο και κανένα σφάλμα δεν έφτασε σε εμάς. Γράψτε \% ή βάλτε την εντολή σε script και προγραμματίστε το script.

Παγίδα 3: διαφορετικό περιβάλλον. Το cron τρέχει τις εργασίες με /bin/sh, όχι bash, στον προσωπικό σας φάκελο και με λιτό περιβάλλον. Στο Ubuntu 24.04 το PATH ήταν καλύτερο από τη φήμη του: η πλήρης διαδρομή συστήματος μαζί με /usr/local/bin και /snap/bin, για root και για απλό χρήστη. Αυτό που λείπει ακόμη είναι ό,τι βρίσκεται στον προσωπικό σας φάκελο: ~/.local/bin, το node του nvm, pipx, cargo. Χρησιμοποιήστε πλήρεις διαδρομές στην εργασία ή ξεκινήστε τη γραμμή με . $HOME/.profile;.

Εργασίες που ανήκουν στο σύστημα και όχι σε χρήστη μπαίνουν στο /etc/cron.d/ ως αρχείο με ένα επιπλέον πεδίο, τον χρήστη:

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

Το Ubuntu τρέχει επίσης ό,τι υπάρχει στα /etc/cron.hourly, cron.daily, cron.weekly και cron.monthly, στο 17ο λεπτό κάθε ώρας, στις 06:25, στις 06:47 την Κυριακή και στις 06:52 την 1η του μήνα. Βάλτε εκεί ένα εκτελέσιμο script και θα τρέχει μαζί με τα υπόλοιπα.

2. Timers του systemd

Ένας timer είναι δύο units: μια υπηρεσία που κάνει τη δουλειά και ένας timer που λέει πότε. Δημιουργήστε πρώτα το script, μετά τα units.

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

Ενεργοποιήστε τον timer, όχι την υπηρεσία:

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

Το list-timers δείχνει την επόμενη εκτέλεση, πόσος χρόνος μένει και την τελευταία εκτέλεση. Τα logs δεν θέλουν ρύθμιση: το journalctl -u backup.service έχει κάθε έναρξη, κάθε τέλος και κάθε γραμμή εξόδου με χρονοσφραγίδα. Για να τρέξετε την εργασία αμέσως, sudo systemctl start backup.service· έτσι δοκιμάζετε και το script πριν εμπιστευτείτε το πρόγραμμα.

Σύνταξη ημερολογίου. Το OnCalendar διαβάζεται ημέρα-εβδομάδας έτος-μήνας-ημέρα ώρα:λεπτό:δευτερόλεπτο, με * για οποιαδήποτε τιμή. Δοκιμάστε μια έκφραση πριν τη χρησιμοποιήσετε:

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

Τυπώνει την κανονικοποιημένη μορφή και τις επόμενες ημερομηνίες. Μερικές εκφράσεις που ελέγξαμε:

OnCalendarΣημασία
*-*-* 03:30Κάθε μέρα στις 03:30
Mon..Fri *-*-* 09:00Καθημερινές στις 09:00
*:0/15Κάθε 15 λεπτά
weeklyΔευτέρα στις 00:00
*-*-01 04:00Την 1η κάθε μήνα στις 04:00
*-*-* 03:00 Europe/Kyiv03:00 ώρα Κιέβου· έτρεξε στις 01:00 UTC στη δοκιμή μας

Οι τρεις ρυθμίσεις που αξίζει να ξέρετε. Το Persistent=true αποθηκεύει την τελευταία εκτέλεση στον δίσκο και αναπληρώνει μια εκτέλεση που χάθηκε όσο ο server ήταν κλειστός ή ο timer σταματημένος. Σταματήσαμε τον timer μας ανά δύο λεπτά, περιμέναμε να περάσει μια προγραμματισμένη εκτέλεση και τον ξεκινήσαμε ξανά: η χαμένη εκτέλεση ξεκίνησε μέσα στο ίδιο δευτερόλεπτο. Χωρίς Persistent, απλώς περιμένει την επόμενη ευκαιρία.

Το AccuracySec είναι η έκπληξη. Από προεπιλογή το systemd ομαδοποιεί τους timers σε παράθυρο ενός λεπτού για να γλιτώνει αφυπνίσεις, γι' αυτό η πρώτη μας εκτέλεση ήρθε στις 07:42:18 και όχι στις 07:42:00. Με AccuracySec=1s οι επόμενες έπεσαν ακριβώς στο δευτερόλεπτο, 07:46:00 και 07:48:00. Ορίστε το όταν μετράει το λεπτό· αφήστε την προεπιλογή για ένα νυχτερινό backup.

Το RandomizedDelaySec=10m κάνει σκόπιμα το αντίθετο: απλώνει την εκκίνηση σε ένα παράθυρο ώστε δέκα servers να μη χτυπήσουν τον ίδιο χώρο backup το ίδιο δευτερόλεπτο.

Για μια εργασία μίας φοράς, κανένα αρχείο:

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

Δημιουργεί έναν προσωρινό timer που ενεργοποιείται μία φορά και εξαφανίζεται· μέχρι τότε τον δείχνει το systemctl list-timers.

3. Ποιο να χρησιμοποιήσετε

CronTimer του systemd
Ρύθμιση1 γραμμή2 αρχεία
LogsΜόνο αν ανακατευθύνετε την έξοδοjournalctl -u name.service
Χαμένη εκτέλεση όσο ο server ήταν κλειστόςΧάνεταιΤρέχει στην εκκίνηση με Persistent=true
Η εργασία τρέχει ακόμη στο επόμενο χτύπημαΞεκινά δεύτερο αντίγραφοΠαραλείπεται μέχρι να τελειώσει το πρώτο
Ακριβής ώραΣτο λεπτόΣτο δευτερόλεπτο με AccuracySec=1s
ΚατάστασηΚαμίαlist-timers, systemctl status

Χρησιμοποιήστε cron για μια γρήγορη γραμμή που θα αναγνωρίζετε και σε έναν χρόνο. Χρησιμοποιήστε timer για ό,τι πρέπει να βλέπετε όταν αποτυγχάνει, δεν πρέπει να επικαλύπτεται ή πρέπει να τρέξει μετά από χαμένη επανεκκίνηση: backups, ανανέωση πιστοποιητικών, καθαρισμός βάσεων δεδομένων. Αν μια εργασία cron μπορεί να επικαλυφθεί, τυλίξτε τη: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, και το δεύτερο αντίγραφο τερματίζει αμέσως.

Και οι δύο χρονοπρογραμματιστές ξεκινούν μια εργασία και σταματούν. Για πρόγραμμα που πρέπει να τρέχει όλο το εικοσιτετράωρο και να επανέρχεται μετά από κατάρρευση, χρειάζεστε υπηρεσία, όχι πρόγραμμα· δείτε πώς δημιουργείτε υπηρεσία systemd και, για Windows, πώς τρέχετε script 24/7 σε Windows Server. Ένας καλός πρώτος timer είναι αυτός από τον οδηγό μας για backup με restic· οι αυτόματες ενημερώσεις ασφαλείας είναι ένας timer που το Ubuntu ήδη έχει, το apt-daily-upgrade.timer, ένας από τους 17 που τρέχουν σε νέο server.

Συχνές ερωτήσεις

Γιατί η εργασία μου δουλεύει στο τερματικό αλλά όχι στο cron;

Τρεις συνήθεις λόγοι. Το cron τρέχει την εργασία με sh, όχι bash, οπότε η σύνταξη που υπάρχει μόνο στο bash αποτυγχάνει. Εργαλεία στον προσωπικό σας φάκελο, όπως nvm, pipx ή cargo, δεν είναι στο PATH του cron, οπότε χρησιμοποιήστε πλήρεις διαδρομές. Και κάθε % στη γραμμή εντολής τερματίζει την εντολή: το date +%F έγινε date + στον server μας. Γράψτε το \% ή μεταφέρετε την εντολή σε script.

Πού πηγαίνει η έξοδος του cron;

Στο email, από προεπιλογή. Το image μας δεν έχει mail server, οπότε το cron καταγράφει 'No MTA installed, discarding output' και η έξοδος χάνεται. Προσθέστε >> /var/log/myjob.log 2>&1 στην εργασία ή περάστε σε timer του systemd, του οποίου η έξοδος πηγαίνει μόνη της στο journal.

Τι πλεονέκτημα έχει ένας timer του systemd έναντι του cron;

Logs στο journalctl, κανένα δεύτερο αντίγραφο εργασίας που ακόμη τρέχει, αναπλήρωση με Persistent=true των εκτελέσεων που χάθηκαν όσο ο server ήταν κλειστός, και γραμμή κατάστασης με την επόμενη και την τελευταία εκτέλεση. Το cron κερδίζει στη συντομία: μία γραμμή αντί για δύο αρχεία.

Ο timer μου έτρεξε 18 δευτερόλεπτα αργότερα. Γιατί;

Από προεπιλογή το systemd ομαδοποιεί τους timers σε παράθυρο ενός λεπτού για να γλιτώνει αφυπνίσεις, αυτή είναι η ρύθμιση AccuracySec. Ο timer μας ανά δύο λεπτά έτρεξε στις 07:42:18 αντί για 07:42:00. Με AccuracySec=1s έτρεξε ακριβώς στις 07:46:00. Ορίστε τη όταν μετράει το ακριβές λεπτό.

Ποια ζώνη ώρας χρησιμοποιούν το cron και οι timers;

Του server, που είναι UTC στα images μας. Ορίστε τη μία φορά με timedatectl, δείτε τον οδηγό μας για hostname και ζώνη ώρας, και cron και timers την ακολουθούν. Ένας timer μπορεί να έχει και δική του ζώνη: το OnCalendar=*-*-* 03:00 Europe/Kyiv έτρεξε στις 01:00 UTC στη δοκιμή μας.

Σχόλια

Δεν υπάρχουν ακόμη σχόλια. Γίνετε ο πρώτος.

Αφήστε ένα σχόλιο

Τα σχόλια ελέγχονται πριν εμφανιστούν.