שרת מצדיק את מחירו כשהוא עובד בזמן שאתם ישנים: גיבויים, סבב לוגים, חידוש תעודות, דוח בתשע. ללינוקס יש שני מתזמנים לזה. cron בן ארבעים ומסתפק בשורה אחת. טיימרים של systemd דורשים שני קבצים קטנים ונותנים בתמורה לוגים, השלמה אחרי השבתה וזמן מדויק. המדריך הזה עוסק בשניהם על Ubuntu 24.04, וכל התנהגות נבדקה על שרת חדש מהאימג' שלנו, כולל שלוש הטעויות שגורמות למשימת cron להיכשל בלי מילה.
צריך משתמש עם sudo; מדריך ההקמה של Ubuntu יוצר אחד.
1. cron בחמש דקות
cron מותקן ופועל באימג'ים של 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 רשימה. חל אזור הזמן של השרת, UTC באימג'ים שלנו; הגדירו את שלכם פעם אחת עם המדריך לשם מארח ואזור זמן ו-cron יעקוב.
בדקו מה רץ עם journalctl -u cron. כל הרצה רושמת את המשתמש ואת הפקודה, ושם מופיעות שלוש המלכודות.
מלכודת 1: הפלט נעלם. cron שולח את פלט המשימה למשתמש באימייל. באימג' שלנו אין שרת דואר, ולכן ה-journal הראה (CRON) info (No MTA installed, discarding output) והפלט אבד. הפנו אותו בעצמכם, כמו בדוגמה הראשונה עם >> /var/log/backup.log 2>&1.
מלכודת 2: סימן האחוז. ב-crontab הסימן % מסיים את הפקודה והופך את השאר לקלט סטנדרטי. תזמנו date +%F > /tmp/today. ה-journal מראה מה cron הריץ באמת: CMD (date +). שום קובץ לא נכתב ושום שגיאה לא הגיעה אלינו. כתבו \%, או שימו את הפקודה בסקריפט ותזמנו את הסקריפט.
מלכודת 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 בחודש. שימו שם סקריפט בר-הרצה והוא ירוץ יחד עם השאר.
2. טיימרים של systemd
טיימר הוא שתי יחידות: שירות שעושה את העבודה וטיימר שאומר מתי. צרו קודם את הסקריפט, ואחר כך את היחידות.
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
הפעילו את הטיימר, לא את השירות:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
list-timers מראה את ההרצה הבאה, כמה זמן נשאר עד אליה ואת ההרצה האחרונה. לוגים לא דורשים הגדרה: ב-journalctl -u backup.service יש כל התחלה, כל סיום וכל שורת פלט עם חותמת זמן. כדי להריץ את המשימה מיד, sudo systemctl start backup.service; כך גם בודקים את הסקריפט לפני שסומכים על לוח הזמנים.
תחביר לוח השנה. 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/Kyiv | 03:00 שעון קייב; אצלנו רץ ב-01:00 UTC |
שלוש הגדרות שכדאי להכיר. Persistent=true שומר את ההרצה האחרונה בדיסק ומשלים הרצה שהוחמצה כשהשרת היה כבוי או הטיימר עצור. עצרנו את הטיימר שלנו שרץ כל שתי דקות, חיכינו שהרצה מתוזמנת תעבור והפעלנו אותו שוב: ההרצה שהוחמצה התחילה באותה שנייה. בלי Persistent הוא פשוט מחכה למועד הבא.
AccuracySec היא ההפתעה. כברירת מחדל systemd מקבץ טיימרים בחלון של דקה כדי לחסוך השכמות, ולכן ההרצה הראשונה שלנו הגיעה ב-07:42:18 ולא ב-07:42:00. עם AccuracySec=1s ההרצות הבאות נפלו בדיוק על השנייה, ב-07:46:00 וב-07:48:00. הגדירו אותה כשהדקה חשובה; לגיבוי לילי השאירו את ברירת המחדל.
RandomizedDelaySec=10m עושה את ההפך בכוונה: הוא מפזר את ההתחלה על פני חלון, כדי שעשרה שרתים לא יפגעו באותו אחסון גיבוי באותה שנייה.
למשימה חד-פעמית לא צריך שום קובץ:
sudo systemd-run --on-active=30m --unit=cleanup-once /usr/local/bin/cleanup.sh
היא יוצרת טיימר זמני שמופעל פעם אחת ונעלם; עד אז systemctl list-timers מציג אותו.
3. במה להשתמש
| cron | טיימר systemd | |
|---|---|---|
| הגדרה | שורה אחת | שני קבצים |
| לוגים | רק אם מפנים את הפלט | journalctl -u name.service |
| הרצה שהוחמצה כשהשרת היה כבוי | אובדת | רצה באתחול עם Persistent=true |
| המשימה עדיין רצה במועד הבא | עותק שני מתחיל | מדולגת עד שהראשונה מסתיימת |
| זמן מדויק | עד הדקה | עד השנייה עם AccuracySec=1s |
| מצב | אין | list-timers ו-systemctl status |
השתמשו ב-cron לשורה מהירה שתזהו גם בעוד שנה. השתמשו בטיימר לכל דבר שצריך לראות כשהוא נכשל, שאסור לו לחפוף או שחייב לרוץ אחרי אתחול שהחמיץ אותו: גיבויים, חידוש תעודות, ניקוי מסדי נתונים. אם משימת cron עלולה לחפוף, עטפו אותה: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, והעותק השני יוצא מיד.
שני המתזמנים מריצים משימה ועוצרים. תוכנה שצריכה לרוץ מסביב לשעון ולחזור אחרי קריסה צריכה שירות ולא לוח זמנים; ראו איך יוצרים שירות systemd ול-Windows איך מריצים סקריפט 24/7 ב-Windows Server. טיימר ראשון טוב הוא זה ממדריך הגיבוי עם restic שלנו; עדכוני האבטחה האוטומטיים הם טיימר ש-Ubuntu כבר מביא, apt-daily-upgrade.timer, אחד מ-17 שרצים על שרת חדש.
תגובות
אין עדיין תגובות. היו הראשונים.