مدیریت سرویس با systemd یکی از مهارت‌های پایه‌ای است که هر مدیر سرور لینوکسی باید به‌خوبی بر آن مسلط باشد. systemd سیستم مقداردهی اولیه (init system) و مدیر سرویس پیش‌فرض در تقریباً تمام توزیع‌های مدرن لینوکس از جمله Ubuntu، Debian، CentOS، AlmaLinux و Fedora است. این ابزار مسئول بوت شدن سیستم، اجرای سرویس‌ها، مدیریت وابستگی‌ها و نظارت بر فرآیندهاست. در این راهنمای کامل از رپیدو سرور، یاد می‌گیرید که چگونه سرویس‌ها را با systemd مدیریت کنید، سرویس سفارشی بسازید، لاگ‌ها را بررسی کنید و مشکلات رایج را برطرف نمایید.

systemd چیست و چه نقشی در لینوکس دارد؟

systemd مجموعه‌ای از ابزارها و کتابخانه‌هاست که فرآیند بوت و مدیریت سرویس‌ها را در لینوکس بر عهده دارد. این سیستم جایگزین روش قدیمی SysV init شد و مزایای زیادی از جمله راه‌اندازی موازی سرویس‌ها، مدیریت وابستگی‌های هوشمند و نظارت پیوسته بر فرآیندها را به ارمغان آورد. اولین فرآیندی که پس از بوت هسته لینوکس اجرا می‌شود، خود systemd است که با شناسه پردازه (PID) شماره ۱ شناخته می‌شود.

مفهوم اصلی در systemd، «واحد» یا Unit است. هر واحد یک منبع سیستمی را توصیف می‌کند و انواع مختلفی دارد:

  • service. توصیف‌کننده یک سرویس یا دیمن (daemon) که در پس‌زمینه اجرا می‌شود.
  • socket. برای فعال‌سازی سرویس بر اساس سوکت شبکه یا IPC.
  • timer. برای زمان‌بندی اجرای وظایف، جایگزین مدرن cron.
  • target. گروه‌بندی چند واحد برای رسیدن به یک حالت مشخص از سیستم.
  • mount. برای مدیریت نقاط اتصال فایل‌سیستم.
نکته: ابزار خط فرمان اصلی برای مدیریت سرویس با systemd دستور systemctl است و برای مشاهده لاگ‌ها از journalctl استفاده می‌شود.

مدیریت سرویس با systemd و دستورهای systemctl

روزمره‌ترین کاری که با systemd انجام می‌دهید، کنترل وضعیت سرویس‌هاست. تمام این کارها با دستور systemctl انجام می‌شود. برای شروع، اجرای یک سرویس مانند Nginx به این شکل است:

systemctl start nginx

برای متوقف کردن سرویس:

systemctl stop nginx

برای ری‌استارت کامل یا بارگذاری مجدد پیکربندی بدون قطع سرویس:

systemctl restart nginx
systemctl reload nginx

یکی از مهم‌ترین تمایزها در systemd، تفاوت میان start و enable است. دستور start یک سرویس را همین حالا اجرا می‌کند، اما enable آن را طوری تنظیم می‌کند که پس از هر بار بوت شدن سرور به‌طور خودکار اجرا شود. این دو مستقل از هم هستند:

systemctl enable nginx
systemctl disable nginx

اگر می‌خواهید سرویسی هم همین حالا اجرا شود و هم در بوت فعال گردد، می‌توانید هر دو را با یک دستور ترکیب کنید:

systemctl enable --now nginx

بررسی وضعیت سرویس‌ها و رفع اشکال

برای مشاهده وضعیت دقیق یک سرویس، از زیردستور status استفاده کنید. این دستور اطلاعات ارزشمندی مانند وضعیت فعلی، شناسه پردازه، مصرف حافظه و چند خط آخر لاگ را نمایش می‌دهد:

systemctl status nginx

در خروجی این دستور به دنبال دو خط مهم باشید. خط Loaded نشان می‌دهد فایل واحد بارگذاری شده و آیا سرویس enable است یا خیر. خط Active وضعیت فعلی اجرا را نشان می‌دهد. جدول زیر رایج‌ترین وضعیت‌ها را توضیح می‌دهد:

وضعیتمعنی
active (running)سرویس در حال اجرای پیوسته است
active (exited)سرویس اجرا شد و با موفقیت پایان یافت
inactive (dead)سرویس اجرا نمی‌شود
failedسرویس با خطا متوقف شده است
activatingسرویس در حال راه‌اندازی است

برای دیدن فهرست همه سرویس‌های در حال اجرا و بررسی سلامت کلی سیستم:

systemctl list-units --type=service --state=running

و برای مشاهده سرویس‌هایی که به حالت failed رفته‌اند:

systemctl --failed

ساخت یک سرویس سفارشی با systemd

یکی از قدرتمندترین قابلیت‌های systemd، امکان تبدیل هر برنامه‌ای به یک سرویس مدیریت‌شده است. فرض کنید یک اپلیکیشن Node.js دارید که می‌خواهید همیشه در پس‌زمینه اجرا شود و در صورت خرابی به‌طور خودکار ری‌استارت گردد. برای این کار یک فایل واحد در مسیر /etc/systemd/system/ می‌سازیم:

nano /etc/systemd/system/myapp.service

محتوای زیر را در آن قرار دهید:

[Unit]
Description=My Node.js Application
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

هر بخش این فایل نقش مشخصی دارد. بخش [Unit] توضیحات و وابستگی‌ها را تعریف می‌کند؛ عبارت After=network.target یعنی سرویس پس از آماده شدن شبکه اجرا شود. بخش [Service] نحوه اجرا را مشخص می‌کند: ExecStart دستور اجرا، Restart=on-failure ری‌استارت خودکار در صورت خطا و User کاربری که سرویس با آن اجرا می‌شود. بخش [Install] تعیین می‌کند سرویس در کدام هدف فعال شود.

پس از ساخت فایل، باید systemd را از تغییرات مطلع کنید و سپس سرویس را فعال نمایید:

systemctl daemon-reload
systemctl enable --now myapp.service
هشدار: هر بار که فایل واحدی را ویرایش می‌کنید، حتماً دستور systemctl daemon-reload را اجرا کنید تا systemd تغییرات را بخواند، در غیر این صورت پیکربندی قدیمی همچنان اعمال می‌شود.

مدیریت لاگ‌ها با journalctl

systemd یک سیستم لاگ متمرکز به نام journal دارد که تمام پیام‌های سرویس‌ها را جمع‌آوری می‌کند. ابزار journalctl برای مشاهده و جستجوی این لاگ‌ها استفاده می‌شود. برای دیدن لاگ‌های یک سرویس خاص:

journalctl -u myapp.service

برای دنبال کردن لاگ‌ها به‌صورت زنده (مانند tail):

journalctl -u myapp.service -f

برای محدود کردن لاگ‌ها به بازه زمانی مشخص، مثلاً یک ساعت گذشته یا از زمان آخرین بوت:

journalctl -u nginx --since "1 hour ago"
journalctl -b

گاهی اوقات لاگ‌ها فضای زیادی اشغال می‌کنند. برای مدیریت حجم آن‌ها می‌توانید لاگ‌های قدیمی را حذف کنید. مثلاً برای نگه داشتن تنها ۵۰۰ مگابایت اخیر:

journalctl --vacuum-size=500M

زمان‌بندی وظایف با Timer به‌جای Cron

علاوه بر مدیریت سرویس‌ها، systemd می‌تواند جایگزین کاملی برای cron باشد. با استفاده از واحدهای timer می‌توانید وظایف را زمان‌بندی کنید و مزیت آن نسبت به cron، یکپارچگی با journal برای لاگ‌گیری و مدیریت بهتر وابستگی‌هاست. برای ساخت یک تایمر، به دو فایل نیاز دارید: یک فایل service که کار را انجام می‌دهد و یک فایل timer که زمان اجرا را تعیین می‌کند. نمونه فایل timer برای اجرای روزانه:

[Unit]
Description=Run backup daily

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

گزینه Persistent=true تضمین می‌کند که اگر سرور در زمان اجرای برنامه‌ریزی‌شده خاموش بوده، کار در اولین فرصت پس از روشن شدن انجام شود. برای مشاهده همه تایمرهای فعال:

systemctl list-timers

اگر می‌خواهید مهارت‌های خود در مدیریت سرور را گسترش دهید، مجموعه مقالات رپیدو سرور راهنماهای عملی فراوانی در این زمینه دارد. همچنین برای اجرای این آموزش‌ها به یک سرور نیاز دارید که می‌توانید از صفحه خرید سرور مجازی تهیه کنید.

مدیریت وابستگی‌ها و ترتیب اجرای سرویس‌ها

یکی از مزیت‌های مهم systemd نسبت به سیستم‌های قدیمی، مدیریت هوشمند وابستگی‌ها و ترتیب اجراست. در بخش [Unit] فایل سرویس، چند دستورالعمل کلیدی برای این منظور وجود دارد که تفاوت آن‌ها را باید به‌خوبی درک کنید:

  • After و Before. ترتیب اجرا را تعیین می‌کنند اما وابستگی سخت ایجاد نمی‌کنند. After=network.target یعنی این سرویس پس از آماده شدن شبکه اجرا شود.
  • Requires. یک وابستگی سخت است؛ اگر سرویس مورد نیاز اجرا نشود، این سرویس هم اجرا نمی‌شود.
  • Wants. یک وابستگی نرم است؛ سرویس مورد نیاز اجرا می‌شود اما اگر شکست بخورد، سرویس اصلی همچنان اجرا می‌شود.

برای مثال، فرض کنید یک اپلیکیشن دارید که به پایگاه داده نیاز دارد. می‌توانید در فایل سرویس آن بنویسید:

[Unit]
Description=My Web App
Requires=postgresql.service
After=postgresql.service network.target

با این تنظیم، systemd تضمین می‌کند که ابتدا پایگاه داده و شبکه آماده شوند و سپس اپلیکیشن شما اجرا گردد. درک تفاوت میان After (که فقط ترتیب را مشخص می‌کند) و Requires (که وابستگی واقعی می‌سازد) برای طراحی سرویس‌های قابل‌اعتماد بسیار مهم است.

محدودسازی منابع و افزایش امنیت سرویس‌ها

systemd ابزارهای قدرتمندی برای کنترل مصرف منابع و ایمن‌سازی سرویس‌ها فراهم می‌کند که از طریق فناوری cgroups در هسته لینوکس پیاده‌سازی شده‌اند. با افزودن این گزینه‌ها به بخش [Service] می‌توانید از اینکه یک سرویس تمام منابع سرور را ببلعد جلوگیری کنید:

[Service]
MemoryMax=512M
CPUQuota=50%
TasksMax=100

در این مثال، سرویس حداکثر ۵۱۲ مگابایت حافظه و ۵۰ درصد از یک هسته پردازنده مصرف می‌کند. علاوه بر منابع، systemd گزینه‌های امنیتی متعددی برای محدود کردن دسترسی سرویس به سیستم دارد. برخی از مهم‌ترین آن‌ها عبارت‌اند از:

گزینهاثر امنیتی
NoNewPrivileges=trueجلوگیری از افزایش سطح دسترسی
PrivateTmp=trueپوشه tmp ایزوله و اختصاصی برای سرویس
ProtectSystem=strictفقط‌خواندنی کردن بخش بزرگی از فایل‌سیستم
ProtectHome=trueمسدود کردن دسترسی به پوشه‌های خانگی کاربران

این گزینه‌ها به شما اجازه می‌دهند حتی سرویس‌هایی را که با دسترسی بالا اجرا می‌شوند، در یک محیط محدود و ایمن قرار دهید تا در صورت نفوذ، خسارت به حداقل برسد. برای بررسی میزان مصرف منابع یک سرویس نیز می‌توانید از دستور زیر استفاده کنید:

systemd-cgtop

درک هدف‌ها و سطوح اجرا

در سیستم‌های قدیمی مفهومی به نام runlevel وجود داشت که حالت‌های مختلف سیستم را مشخص می‌کرد. در systemd این مفهوم با «هدف» یا target جایگزین شده که انعطاف‌پذیرتر است. مهم‌ترین هدف‌ها عبارت‌اند از multi-user.target برای حالت متنی چند کاربره (رایج در سرورها) و graphical.target برای حالت گرافیکی. برای دیدن هدف پیش‌فرض فعلی سیستم:

systemctl get-default

روی یک سرور معمولاً هدف پیش‌فرض روی multi-user تنظیم است تا منابع صرف رابط گرافیکی نشود. برای تغییر هدف پیش‌فرض:

systemctl set-default multi-user.target

همچنین در مواقع اضطراری می‌توانید سیستم را به حالت‌های خاصی مانند rescue یا emergency ببرید که برای عیب‌یابی مشکلات جدی بوت بسیار مفید هستند. درک این هدف‌ها به شما کمک می‌کند رفتار سیستم را در شرایط مختلف کنترل کنید.

عیب‌یابی سرویس‌های failed

وقتی سرویسی به وضعیت failed می‌رود، systemd ابزارهای خوبی برای یافتن علت در اختیار شما می‌گذارد. نخستین گام همیشه بررسی وضعیت و لاگ‌هاست:

systemctl status myapp.service
journalctl -u myapp.service -n 50 --no-pager

علت‌های رایج شکست سرویس عبارت‌اند از: مسیر اشتباه در ExecStart، نداشتن مجوز کافی برای کاربر تعیین‌شده، اشغال بودن پورت توسط فرآیند دیگر، یا خطای نحوی در خود اپلیکیشن. با خواندن دقیق پیام‌های لاگ معمولاً می‌توان علت را به‌سرعت پیدا کرد. پس از رفع مشکل و در صورت ویرایش فایل واحد، فراموش نکنید که daemon-reload را اجرا و سپس سرویس را ری‌استارت کنید تا تغییرات اعمال شوند.

گاهی سرویس بارها ری‌استارت می‌شود و به وضعیت پایدار نمی‌رسد. در این حالت، بررسی کنید که آیا محدودیت تعداد تلاش‌های ری‌استارت فعال است یا خیر. systemd به‌طور پیش‌فرض اگر یک سرویس در بازه زمانی کوتاه چند بار پشت سر هم شکست بخورد، تلاش برای اجرای آن را متوقف می‌کند تا از حلقه بی‌پایان جلوگیری شود. با گزینه‌های StartLimitIntervalSec و StartLimitBurst می‌توانید این رفتار را تنظیم کنید. برای بازنشانی وضعیت failed یک سرویس و امکان تلاش دوباره از دستور زیر استفاده کنید:

systemctl reset-failed myapp.service

در نهایت، یک روش بسیار مفید برای عیب‌یابی این است که دستور ExecStart را به‌صورت دستی و مستقیم در ترمینال اجرا کنید. اگر برنامه در اجرای مستقیم کار کند اما به‌عنوان سرویس شکست بخورد، مشکل معمولاً به متغیرهای محیطی، کاربر اجراکننده یا مسیر کاری بازمی‌گردد. این مقایسه ساده اغلب سریع‌ترین راه برای یافتن ریشه مشکل است و به شما کمک می‌کند تفاوت میان محیط اجرای شخصی و محیط ایزوله systemd را درک کنید.

سوالات متداول

تفاوت start و enable در systemd چیست؟

دستور start یک سرویس را بلافاصله اجرا می‌کند اما این اجرا موقتی است و پس از ری‌استارت سرور از بین می‌رود. دستور enable سرویس را طوری تنظیم می‌کند که با هر بار بوت شدن سیستم به‌طور خودکار اجرا شود. برای اطمینان از اجرای دائمی باید هر دو را انجام دهید یا از enable --now استفاده کنید.

چرا پس از ویرایش فایل سرویس باید daemon-reload اجرا کنم؟

systemd فایل‌های واحد را در حافظه بارگذاری می‌کند و از نسخه کش‌شده استفاده می‌نماید. دستور daemon-reload به systemd می‌گوید که فایل‌های پیکربندی را دوباره از دیسک بخواند. بدون این کار، تغییرات جدید شما اعمال نمی‌شوند و سرویس با تنظیمات قدیمی اجرا می‌شود.

آیا systemd می‌تواند جایگزین cron شود؟

بله. واحدهای timer در systemd قابلیت‌های cron را پوشش می‌دهند و مزایای بیشتری مانند یکپارچگی با journal برای لاگ‌گیری، مدیریت وابستگی و اجرای معوق کارهای از دست رفته با گزینه Persistent دارند. با این حال cron همچنان برای کارهای ساده و سریع محبوب است.

چطور بفهمم یک سرویس چرا از کار افتاده است؟

ابتدا با systemctl status وضعیت کلی و چند خط آخر لاگ را ببینید، سپس با journalctl -u نام سرویس، لاگ‌های کامل را بررسی کنید. پیام‌های خطا معمولاً علت دقیق را مانند مسیر اشتباه، کمبود مجوز یا اشغال بودن پورت مشخص می‌کنند.