EQVPS

چطور کارها را روی VPS با cron و تایمرهای systemd زمان‌بندی کنیم

پشتیبان‌گیری، پاک‌سازی و اسکریپت‌ها را طبق برنامه اجرا کنید. cron در پنج دقیقه با سه تله‌ای که بی‌صدا کارها را خراب می‌کنند، سپس تایمرهای systemd برای لاگ، جبران اجراهای جامانده پس از خاموشی و زمان دقیق. همهٔ رفتارهای زیر روی یک سرور تازهٔ Ubuntu 24.04 آزموده شده‌اند.

سرور وقتی ارزشش را نشان می‌دهد که در خواب شما کار کند: پشتیبان‌گیری، چرخش لاگ‌ها، تمدید گواهی‌ها، گزارشی در ساعت نه. لینوکس برای این کار دو زمان‌بند دارد. 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. یک اسکریپت اجرایی آنجا بگذارید تا همراه بقیه اجرا شود.

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روز اول هر ماه ساعت 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
راه‌اندازی1 خط2 فایل
لاگفقط اگر خروجی را هدایت کنید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 تایمری که روی سرور تازه اجرا می‌شوند.

پرسش‌های متداول

چرا کارم در ترمینال اجرا می‌شود ولی در cron نه؟

سه دلیل رایج. cron کار را با sh اجرا می‌کند نه bash، پس نحو مخصوص bash شکست می‌خورد. ابزارهایی که در پوشهٔ خانه نصب شده‌اند، مثل nvm، pipx یا cargo، در PATH مربوط به cron نیستند، پس مسیر کامل بدهید. و هر % در خط فرمان دستور را تمام می‌کند: روی سرور ما date +%F به date + تبدیل شد. آن را به‌صورت \% بنویسید یا دستور را به یک اسکریپت ببرید.

خروجی cron کجا می‌رود؟

به‌طور پیش‌فرض به ایمیل. ایمیج ما سرور ایمیل ندارد، پس cron عبارت 'No MTA installed, discarding output' را ثبت می‌کند و خروجی گم می‌شود. به کار >> /var/log/myjob.log 2>&1 اضافه کنید یا به تایمر systemd بروید که خروجی‌اش خودبه‌خود به journal می‌رسد.

مزیت تایمر systemd بر cron چیست؟

لاگ در journalctl، اجرا نشدن نسخهٔ دوم کاری که هنوز در حال اجراست، جبران اجراهای جامانده در زمان خاموشی سرور با Persistent=true، و خط وضعیتی که اجرای بعدی و آخرین اجرا را نشان می‌دهد. cron در کوتاهی برنده است: یک خط به‌جای دو فایل.

تایمرم 18 ثانیه دیر اجرا شد. چرا؟

systemd به‌طور پیش‌فرض تایمرها را در پنجره‌ای یک‌دقیقه‌ای دسته‌بندی می‌کند تا سیستم کمتر بیدار شود؛ این همان تنظیم AccuracySec است. تایمر دودقیقه‌ای ما به‌جای 07:42:00 در 07:42:18 اجرا شد. با AccuracySec=1s دقیقاً در 07:46:00 اجرا شد. وقتی دقیقهٔ دقیق مهم است تنظیمش کنید.

cron و تایمرها از کدام منطقهٔ زمانی استفاده می‌کنند؟

منطقهٔ زمانی سرور، که در ایمیج‌های ما UTC است. یک بار با timedatectl تنظیمش کنید، راهنمای ما دربارهٔ نام میزبان و منطقهٔ زمانی را ببینید، و cron و تایمرها از آن پیروی می‌کنند. تایمر می‌تواند منطقهٔ خودش را هم داشته باشد: OnCalendar=*-*-* 03:00 Europe/Kyiv در آزمایش ما در 01:00 UTC اجرا شد.

نظرات

هنوز نظری نیست. اولین نفر باشید.

یک نظر بگذارید

نظرات پیش از نمایش بررسی می‌شوند.