اجرای دائمی برنامه روی سرور مجازی با systemd؛ ری‌استارت خودکار و بررسی لاگ

برای اجرای دائمی برنامه روی سرور مجازی، برنامه را با حساب محدود در یک واحد systemd ثبت کنید، بعد از آزمون آن را برای بوت فعال کنید و رفتار خطا و بازیابی آن را جداگانه بسنجید. این راهنما از نمونه واحد تا تحلیل لاگ و انتخاب سرور مناسب پیش می‌رود. فهرست مطالب مسئلهٔ اجرای دائمی آماده‌سازی محی...

۲۳ آبان ۱۴۰۵ 1 دقیقه 0 دیدگاه
اجرای دائمی برنامه روی سرور مجازی با systemd؛ ری‌استارت خودکار و بررسی لاگ

برای اجرای دائمی برنامه روی سرور مجازی، برنامه را با حساب محدود در یک واحد systemd ثبت کنید، بعد از آزمون آن را برای بوت فعال کنید و رفتار خطا و بازیابی آن را جداگانه بسنجید. این راهنما از نمونه واحد تا تحلیل لاگ و انتخاب سرور مناسب پیش می‌رود.

فهرست مطالب

اجرای دائمی دقیقاً چه مسئله‌ای را حل می‌کند؟

اگر امروز یک برنامه را از ترمینال اجرا کرده‌اید و فردا با قطع ارتباط یا راه‌اندازی دوباره ماشین از کار افتاده است، مشکل اصلی معمولاً این نیست که دستور اجرا غلط بوده؛ برنامه در محیطی شروع شده که برای اداره یک سرویس طراحی نشده است. راه قابل نگهداری روی توزیعی که از systemd استفاده می‌کند این است که دستور اجرا، کاربر سیستم، مسیر پروژه و رفتار توقف و بازیابی را در یک واحد سرویس بنویسید. بعد سرویس را جداگانه شروع کنید، رفتار آن را بخوانید، و فقط پس از آزمون، آن را برای راه‌اندازی در بوت فعال کنید. این الگو برای API، پردازشگر صف و برنامه‌ای که باید مدت زیادی در پیش‌زمینه بماند مناسب است. برای یک وظیفه کوتاه که باید مثلاً هر شب اجرا و سپس بسته شود، واحد سرویس یک‌بارمصرف همراه تایمر یا زمان‌بندی موجود پروژه معمولاً انتخاب روشن‌تری است.

پیش از هر تغییر، سه سؤال را جواب دهید: چه چیزی باید روشن بماند، از کجا می‌فهمیم درست کار می‌کند، و در صورت خرابی چه کسی یا چه چیزی باید اقدام کند؟ پاسخ اول ممکن است اجرای فرایند HTTP باشد؛ پاسخ دوم بهتر است یک درخواست آزمایشی به API و بررسی نتیجه کاربردی آن باشد؛ پاسخ سوم ترکیبی از تلاش محدود برای شروع مجدد و هشدار به مسئول سرویس است. اگر فقط فرایند را زیر نظر بگیرید، احتمال دارد برنامه همچنان زنده باشد ولی به پایگاه داده وصل نشود و همه درخواست‌ها خطا بدهند. اگر فقط نشانی HTTP را بررسی کنید، احتمال دارد وب‌سرور صفحه عمومی را از کش برگرداند و خرابی عملیات اصلی پنهان بماند. معیار سلامت را با رفتار واقعی محصول تعریف کنید.

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

اگر فقط می‌دانید برنامه چگونه شروع می‌شود، هنوز نمی‌دانید چگونه اداره می‌شود. معیار استقرار این است که آغاز، توقف، خرابی و برگشت آن را آزموده باشید.

سرپرست فرایند، زمان‌بند و اجرای دستی چه تفاوتی دارند؟

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

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

قبل از ساخت واحد سرویس چه چیزهایی را آماده کنیم؟

محیط اجرا و دامنه مسئولیت را مشخص کنید

اول بررسی کنید سیستم موردنظر با systemd بوت شده و نسخه و رفتار واقعی آن را ثبت کنید. در بعضی کانتینرها یا محیط‌های میزبانی محدود، systemd مدیر اصلی فرایندها نیست یا حساب شما اجازه مدیریت واحد سیستمی ندارد. آنجا باید از ابزار تعریف‌شده توسط همان محیط یا از سرپرست خود سکوی اجرا استفاده کرد. وجود فرمان systemctl در محیط به تنهایی نشان نمی‌دهد که ارتباط با مدیر سیستمی برقرار است. اگر یک واحد کاربری گزینه شماست، جداگانه مشخص کنید چه زمانی مدیر کاربر شروع می‌شود و پس از خروج جلسه چه رفتاری دارد؛ با یک واحد سیستمی یکسان نیست. برای تصمیم خرید، چیزی را که به هماهنگی با ارائه‌دهنده نیاز دارد قبل از سفارش بپرسید.

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

قرارداد اجرایی برنامه را روی کاغذ بیاورید

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

در مثال این مقاله اسم برنامه example-api است. قرار است کاربر نمونه بتواند برنامه و تنظیمات لازم را بخواند، اما نتواند فایل واحد یا برنامه منتشرشده را تغییر دهد. برنامه در پیش‌زمینه می‌ماند تا مدیر سرویس فرایند اصلی را دنبال کند. روند پذیرش نمونه ساده است: درخواست آزمایشی باید پاسخ موردانتظار بدهد، توقف باید محترمانه انجام شود، و پس از شروع دوباره نباید داده‌ای دوبار پردازش شود. اگر برنامه فعلی شما خودش به پس‌زمینه می‌رود، به مستندات آن مراجعه کنید و از گزینه اجرای پیش‌زمینه یا نوع واحد سازگار با معماری همان برنامه استفاده کنید.

وابستگی سرویس را با آمادگی وابستگی اشتباه نگیرید

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

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

ماژول اجرایی در کنار رک سرور
فرمان، کاربر و پوشه کاری در یک واحد سرویس ثبت می‌شوند.

واحد systemd را چگونه بنویسیم و آزمایش کنیم؟

نمونه واحد برای یک API در پیش‌زمینه

در نمونه زیر فرض این است که مدیر سیستم حساب example-api را ساخته، نسخه برنامه را در پوشه مشخص قرار داده و فایل تنظیمات را با مجوز محدود آماده کرده است. این مقادیر واقعی سرویس وطن هاست نیستند و نباید بی‌تغییر کپی شوند. برای آزمایش روی ماشینی که سرویس دیگری روی آن فعال است، پیش از اجرا مطمئن شوید برنامه نمونه به همان پورت یا همان صف عملیاتی وصل نمی‌شود. اگر واقعاً مجبورید روی ماشین اصلی آزمایش کنید، از حساب جداگانه، سرویس نام‌گذاری‌شده و داده‌ای که برای آزمون ساخته شده استفاده کنید؛ کار کردن با داده عملیاتی برای یک آزمایش ساده ضرورت ندارد.

[Unit]
Description=Example API
StartLimitIntervalSec=60
StartLimitBurst=5

[Service]
Type=simple
User=example-api
Group=example-api
WorkingDirectory=/opt/example-api
EnvironmentFile=/etc/example-api/runtime.env
ExecStart=/opt/example-api/.venv/bin/python -m example_api
Restart=on-failure
RestartSec=5s
TimeoutStopSec=25s

[Install]
WantedBy=multi-user.target

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

Type=simple برای فرایندی که در پیش‌زمینه باقی می‌ماند نمونه ساده‌ای است. به‌محض شروع فرایند، گزارش فعال بودن واحد را برابر با آماده شدن API نگیرید. اگر سرویس از راه‌اندازی پیچیده برخوردار است یا لازم است مدیر سیستم فقط پس از آمادگی واقعی به سرویس وابسته اجازه کار بدهد، نوع واحد و قرارداد اعلام آمادگی را مطابق قابلیت همان نرم‌افزار بررسی کنید. در عیب‌یابی روزمره کافی است وضعیت پردازش و پاسخ واقعی برنامه را جداگانه ببینید: ممکن است اولی سبز باشد و دومی، برای نمونه هنگام اجرای بررسی اولیه پایگاه داده، هنوز آماده نباشد.

مسیرهای نوشتن و تنظیمات محرمانه

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

چرا فرمان در SSH کار می‌کند ولی سرویس بالا نمی‌آید؟

در یک نشست تعاملی، فایل‌های آغازین پوسته ممکن است مسیرها، نسخه زبان یا نام‌های جایگزین را آماده کنند. مدیر سرویس برای اجرای مستقیم دستور به چنین فرض‌هایی تکیه نمی‌کند. تفاوت کاربر، پوشه کاری، متغیرهای محیطی و دسترسی به فایل‌ها را پیش از نسبت دادن خطا به خود systemd مقایسه کنید. یک نشانه رایج این است که برنامه فقط وقتی از پوشه پروژه شروع می‌شود فایل تنظیمات نسبی را پیدا می‌کند. در مثال، WorkingDirectory روشن است؛ اگر برنامه هم برای داده‌های حیاتی مسیر مطلق یا مسیری مشتق از تنظیمات پایدار داشته باشد، تشخیص اشتباه ریشه آسان‌تر خواهد بود.

نمونه بررسی یک اختلاف محیطی واقعی

فرض کنید اجرای دستی جواب می‌دهد اما سرویس پیام پیدا نشدن ماژول می‌دهد. ابتدا مسیر مفسری را که واقعاً در ExecStart ثبت شده بررسی کنید و آن را با مسیری که در آزمایش دستی استفاده شد مقایسه کنید. سپس تأیید کنید همان محیط دارای وابستگی موردنیاز است. در آخر با کاربر سرویس و پوشه کاری مشخص، فقط یک آزمون کم‌اثر انجام دهید. افزودن مجوز گسترده یا قرار دادن دستور در پوسته ورود، اختلاف را موقتاً پنهان می‌کند و ممکن است میزبان بعدی دوباره آن را نشان دهد. ثبت مسیر واقعی مفسر، نسخه انتشار و وابستگی دقیق به تیم بعدی هم امکان بازتولید می‌دهد.

ترتیب اعمال تنظیمات و سنجش نتیجه

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

sudo systemd-analyze verify /etc/systemd/system/example-api.service
sudo systemctl daemon-reload
sudo systemctl start example-api.service
systemctl status example-api.service --no-pager
sudo journalctl -u example-api.service -n 50 --no-pager
sudo systemctl enable example-api.service
systemctl is-enabled example-api.service

تفاوت start، enable و daemon-reload را برای کل تیم بنویسید. شروع واحد، وضعیت جاری را تغییر می‌دهد؛ فعال کردن آن، وابستگی لازم برای بوت بعد را می‌سازد؛ بازخوانی تعریف واحد، فرایند فعلی را به‌خودی‌خود با تنظیم جدید جایگزین نمی‌کند. اگر فقط فایل برنامه تغییر کرده، بسته به معماری استقرار باید همان سرویس با نسخه جدید راه بیفتد؛ اگر فایل واحد تغییر کرده، مدیر نیز باید تعریف جدید را بخواند. اگر خود نرم‌افزار بازخوانی پیکربندی درجا ندارد، انجام reload به‌جای restart نباید پیش‌فرض تیم باشد. هر فرمان را براساس وضعیت هدف و اثر آن بر درخواست‌های جاری انتخاب کنید.

جدول انتخاب برای کارهای متداول

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

سیاست تلاش مجدد: بازگشت خودکار بدون حلقه بی‌پایان

تفاوت خرابی، توقف عمدی و فرایند زنده ولی ناسالم

Restart=on-failure برای برنامه‌ای که معمولاً نباید خودبه‌خود تمام شود انتخاب مناسبی برای شروع بررسی است. در حالت‌های متداول، خروج با خطا برنامه را نامزد شروع دوباره می‌کند، اما توقفی که مدیر عمداً به واحد دستور داده رفتار یک خرابی خودکار را ندارد. همچنین خروج عادی و رخدادهای خاص باید طبق نوع واحد و تنظیمات همان نسخه تفسیر شوند. به همین دلیل در برنامه‌ای که فرایند را هنگام اختلال متوقف می‌کند، قرارداد موفقیت و خطا مهم است. اگر برنامه پس از ناتوانی در باز کردن فایل ضروری با نتیجه موفق خارج شود، سیاست مبتنی بر خرابی شاید هیچ اقدامی نکند. اصلاح معنای خروج در برنامه معمولاً از تغییر کورکورانه سیاست به تلاش دائمی قابل نگهداری‌تر است.

سرویس زنده ولی ناسالم مسئله دیگری است. برای مثال ممکن است رشته دریافت درخواست‌ها هنوز فعال باشد، ولی اتصال‌های پایگاه داده به‌تدریج از کار بیفتند؛ یا پردازشگر موجود باشد، ولی مدت زیادی هیچ پیام تازه‌ای را تکمیل نکرده باشد. Restart به‌خودی خود این وضعیت را تشخیص نمی‌دهد. برای API، هم وضعیت اجرای واحد و هم موفقیت یک مسیر نماینده را بسنجید. برای صف، زمان آخرین پیام تکمیل‌شده، سن قدیمی‌ترین کار و حجم خطا را زیر نظر بگیرید. در هر دو حالت مشخص کنید کدام آستانه فقط هشدار می‌دهد و کدام رخداد نیازمند اقدام انسانی است. شروع مجدد خودکار بر مبنای یک آزمایش وابسته به سرویس بیرونی، اگر بدون قید انجام شود، گاهی خرابی کوچک بیرونی را به نوسان داخلی تبدیل می‌کند.

محدودیت دفعات شروع را متناسب با نوع خطا انتخاب کنید

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

وقتی محدودیت فعال شد، پیش از پاک کردن وضعیت شکست دلیل آن را ثبت و رفع کنید. دستور reset-failed وضعیت شکست و شمارنده محدودیت شروع مربوط به واحد را بازنشانی می‌کند، اما یک فایل از دست‌رفته یا رمز اشتباه را درست نمی‌کند. پاک کردن مکرر وضعیت می‌تواند باعث از بین رفتن ترتیب قابل فهم رخدادها شود و مانع مشاهده شود که مشکل از کدام استقرار آغاز شده است. برای همین رویه عملی مناسب این است: علت نخست را پیدا کنید، نسخه یا تنظیم را تصحیح کنید، در صورت نیاز شمارنده را پس از اصلاح بازنشانی کنید، شروع تازه را اجرا کنید و پاسخ بیرونی برنامه را دوباره بسنجید. حالا می‌توانید درباره پایان رخداد تصمیم بگیرید.

مثال عددی: یک اختلال اتصال در زمان استقرار

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

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

کارشناس در حال بررسی نمایشگر لاگ کنار رک
زمان خطا و نخستین پیام مرتبط را ثبت کنید.

خواندن لاگ و تشخیص محل خطا

ابتدا زمان، واحد و بوت را محدود کنید

دیدن آخرین چند خط برای شروع خوب است، ولی لزوماً علت اول را نشان نمی‌دهد. خطای اصلی ممکن است هنگام اولین خروج ثبت شده و ده تلاش بعد آن را از صفحه وضعیت بیرون برده باشند. در journal واحد را جدا کنید و زمان را نزدیک به تغییر اخیر قرار دهید. اگر ماشین دوباره روشن شده، گزارش بوت جاری و قبلی را از هم جدا کنید؛ دسترسی به بوت قبلی به باقی ماندن لاگ‌ها و پیکربندی ثبت آنها بستگی دارد. اگر اطلاعات برای گزارش لازم است، آن را در مسیر مجاز سازمان ذخیره کنید تا با گردش یا حذف دوره‌ای لاگ از دست نرود. برای اشتراک با پشتیبانی، خطوط نامرتبط و داده حساس را پاک‌سازی کنید.

sudo journalctl -u example-api.service -b --no-pager
sudo journalctl -u example-api.service --since '20 minutes ago' --no-pager
sudo journalctl -u example-api.service -f

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

از روی الگوی خطا، قدم بعدی را انتخاب کنید

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

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

گزارش رخداد را قابل پیگیری بنویسید

گزارش خوب تکیه بر عبارت «سرور قطع شد» ندارد. زمان و منطقه زمانی، نام واحد، آخرین نسخه‌ای که سالم بوده، رفتار دیده‌شده از بیرون و پیام اصلی از داخل را کوتاه کنار هم بگذارید. برای نمونه بنویسید «در بوت تازه، واحد فعال شد، ولی اولین آزمون مسیر وضعیت به دلیل دسترس نبودن سرویس داده نتیجه ناموفق داد؛ پس از دقیقه دوم همان آزمون موفق شد». سپس معلوم کنید این یک سناریوی موقتی معین است یا تکرار می‌شود. اگر خروجی مصرف شبکه بخشی از رخداد است، از روش پایش ترافیک سرور مجازی برای تعریف بازه و جداسازی ترافیک عادی استفاده کنید. از ارسال فایل تنظیمات کامل برای اثبات رخداد خودداری کنید.

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

آزمون بازیابی و بهره‌برداری بدون غافلگیری

آزمون توقف، خرابی و بوت را از هم جدا کنید

در یک محیط آزمایشی ابتدا رفتار توقف کنترل‌شده را مشاهده کنید. اگر API درخواست بلندمدت دارد یا کارگر صف هنوز کاری را به پایان نرسانده، معلوم کنید هنگام دریافت سیگنال توقف چه اتفاقی می‌افتد. برنامه‌ای که پیش از ثبت نتیجه پیام را تأیید می‌کند ممکن است در خاموشی کار را از دست بدهد؛ برنامه‌ای که در هر تلاش بدون بررسی دوباره نتیجه را می‌نویسد ممکن است اثر کار را دو بار به جا بگذارد. برای یک آزمون کم‌خطر از داده ساختگی و مقصد غیرعملیاتی استفاده کنید. اگر پیام آزمون به ثبت سفارش، ارسال ایمیل یا فراخوانی پرداخت وصل است، بهتر است از امکان جایگزین آزمایشی استفاده کنید و صرفاً به نام «محیط تست» اعتماد نکنید.

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

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

طرح بازگشت برای استقرار نسخه تازه

یک نسخه قبلی شناخته‌شده را پیش از انتشار نسخه بعدی مشخص کنید. ثبت شناسه انتشار، نسخه محیط اجرا و وابستگی‌های پروژه، باعث می‌شود عبارت «برگرداندن نسخه» ملموس باشد. اگر همه فایل‌ها در همان پوشه درجا عوض می‌شوند، معلوم کنید کدام نسخه در لحظه شروع واقعاً اجرا شده است. اگر پروژه از مسیرهای نسخه‌دار استفاده می‌کند، مقصد مسیر فعال باید در رویه استقرار و بازگشت روشن باشد. تغییر کد، تغییر فایل واحد و تغییر نسخه پایگاه داده کارهای متمایزند؛ بازگشت کد لزوماً داده را به وضعیت سازگار برنمی‌گرداند. برای تغییرات ناسازگار داده، جداگانه وضعیت سازگاری و روش بازیابی را قبل از انتشار بررسی کنید.

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

سه سناریوی عملی: API، کارگر صف و خدمت زمان‌دار

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

برای کارگر صف، ممکن است هیچ نشانی HTTP برای تست وجود نداشته باشد و همین طبیعی است. یک پیام با شناسه شناخته‌شده و محتوای بی‌اثر بسازید؛ زمان دریافت و پایان کار را بسنجید و ثبت کنید که بیش از یک بار پردازش اثرگذار نشده است. پیش از خاموشی کنترل‌شده، رفتار دریافت کار تازه زیر بار را بررسی کنید: برنامه باید طبق قرارداد خود یا کار جاری را جمع کند یا امکان تلاش دوباره بدون خراب کردن داده را بدهد. سرور و سرپرست فقط محیط اجرای این قراردادند؛ فهم زمان تأیید پیام و مسئولیت idempotency در خود معماری برنامه باقی می‌ماند.

برای تولید گزارش شبانه، پرسیدن «آیا فرایند همیشه روشن است؟» معیار درستی نیست. باید بدانید خروجی در موعد مقرر ساخته شده و کار بدون خطا تمام شده است. اجرای یک برنامه کوتاه به شکل سرویس دائمی می‌تواند توقف موفق را غلط تعبیر کند. اگر زمان‌بندی با تایمر انجام می‌شود، ثبت کنید اگر ماشین هنگام موعد خاموش بود چه رفتار موردانتظاری دارید؛ ممکن است نخواهید یک گزارش قدیمی با گزارش امروز هم‌زمان شروع شود. همچنین روشن کنید کار زمان‌دار با کار روز قبل هم‌پوشانی دارد یا خیر. انتخاب میان واحد دائمی و کار زمان‌دار از روی کاربرد پروژه بهتر از انتخاب براساس آشنایی با یک ابزار است.

چه سرور مجازی برای اجرای سرویس مناسب است؟

معیار را از رفتار برنامه استخراج کنید

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

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

چک‌لیست پیش از خرید و تحویل سرویس

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

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

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

آیا systemd با قطع SSH برنامه را متوقف می‌کند؟

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

آیا فعال کردن سرویس یعنی پس از بوت حتماً سالم است؟

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

چرا به‌رغم Restart برنامه دوباره شروع نمی‌شود؟

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

آیا systemd جای مانیتورینگ را می‌گیرد؟

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

آیا اجرای برنامه با دسترسی root برای رفع مشکل مجوز درست است؟

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

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

وقتی کار شروع و پایان تعریف‌شده دارد و در موعد مشخص باید تکرار شود، زمان‌بندی را بررسی کنید. وقتی برنامه دائماً منتظر درخواست یا پیام می‌ماند، مدیریت چرخه عمر یک سرویس مستقل مناسب‌تر است. برخی پروژه‌ها به هر دو نیاز دارند: یک API همیشه اجرا می‌شود و یک کار گزارش‌گیری فقط شب‌ها. بهتر است هرکدام تعریف و گزارش مستقل داشته باشند.

جمع‌بندی

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

نظرت راجب این مطلب ؟

امتیاز خودت رو ثبت کن

میانگین نظرات : 0 / 5. تعداد نظرات : 0

بدون نظر

ثبت دیدگاه

دیدگاه خود را ثبت کنید

امتیاز شما

هنوز دیدگاهی ثبت نشده است. اولین نفر باشید ✨