المستوى المطلوب: مبتدئ — مناسب لأي حد يعرف يفتح Terminal ويكتب أمر، حتى لو دي أول مرة يسمع فيها كلمة systemd.
في آخر المقال هتقدر تخلّي أي تطبيق (Node.js أو Python أو أي بروسيس) يشتغل لوحده أول ما السيرفر يقوم، ويرجّع نفسه في ثواني لو وقع، من غير ما تفضل صاحي تراقبه.
إزاي تخلّي تطبيقك خدمة دائمة على لينكس بـ systemd
المشكلة باختصار
شغّلت تطبيقك بـ node app.js، وقفلت الـ SSH، فالتطبيق وقف معاك. أو السيرفر عمل reboot الساعة 3 الفجر، ومحدش شغّل التطبيق تاني، فالموقع قعد نازل لحد ما عميل اتصل يشتكي. ده مش سوء حظ. ده غياب حاجة تدير خدمتك وتراقبها بدالك. الحاجة دي موجودة أصلاً في سيرفرك واسمها systemd.
الفكرة بمثال قبل التعريف العلمي
تخيّل عمارة فيها حارس. لو لمبة السلّم انطفت، بيغيّرها على طول. لو المصعد وقف، بيعيد تشغيله. لو فيه قطع كهربا ورجعت، بيتأكد إن كل حاجة رجعت تشتغل. انت مش قاعد تراقب العمارة بنفسك، الحارس بيعمل ده 24 ساعة.
systemd هو حارس العمارة بتاع لينكس. بالتعريف الدقيق: هو الـ init system والـ service manager اللي بيشتغل كأول بروسيس في النظام (الـ PID رقم 1) بمجرد الإقلاع، ومسؤول عن تشغيل وإيقاف ومراقبة كل الخدمات. لما تعرّف تطبيقك كـ خدمة (service unit)، systemd بيضمن 3 حاجات: يشغّله عند إقلاع السيرفر، يعيد تشغيله لو وقع، ويجمّع لوجاته في مكان واحد تقدر تقراه بأمر واحد.
ملف الوحدة خطوة بخطوة (مثال شغّال)
الافتراض إن عندك سيرفر لينكس واحد (مثلاً Ubuntu 22.04 أو 24.04) بصلاحية sudo، وتطبيق Node.js موجود في /opt/myapp/app.js. الخطوات دي بنفس المنطق على Python، بس غيّر سطر ExecStart.
أنشئ الملف ثم الصق فيه التعريف:
sudo nano /etc/systemd/system/myapp.service[Unit]
Description=My Node App
After=network.target
StartLimitIntervalSec=60
StartLimitBurst=5
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node /opt/myapp/app.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production
[Install]
WantedBy=multi-user.targetدلوقتي حمّل التعريف وفعّل الخدمة:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
systemctl status myappلو شفت سطر active (running) باللون الأخضر، يبقى خدمتك بقت تحت إدارة systemd. وعلشان تشوف اللوجات لحظة بلحظة:
journalctl -u myapp -fإزاي بيرجّع نفسه: دورة الإعادة و trade-offs
الدورة بسيطة. التطبيق يقع (مثلاً exit code 1) ثم systemd يلاحظ خلال أقل من ثانية ثم يطبّق سياسة Restart=always بعد مهلة RestartSec=3 ثم التطبيق يرجع active (running). كل ده بدون تدخل منك. عمليًا، بدل ما خدمة واقعة تفضل نازلة دقايق لحد ما حد ياخد باله ويشغّلها بإيده، الـ systemd بيرجّعها في حوالي 3 ثواني.
الفرق بين أشهر سياستين: Restart=on-failure بيعيد التشغيل بس لو التطبيق خرج بخطأ (exit code مش صفر)، يعني لو انت بنفسك أوقفته بـ systemctl stop مش هيشغّله. أما Restart=always بيرجّعه حتى لو خرج بنجاح. للخدمات اللي المفروض تفضل شغّالة على طول، always هو الاختيار المعتاد.
الـ trade-off هنا صريح: Restart=always بيديك تعافي تلقائي، بس ممكن يخبّي عليك مشكلة دائمة. لو التطبيق بيكراش كل ثانية بسبب بورت محجوز أو متغيّر بيئة ناقص، systemd هيفضل يحاول. علشان كده حطينا StartLimitBurst=5 في StartLimitIntervalSec=60: لو فشل 5 مرات في دقيقة، systemd بيسيبه في حالة failed ويبطّل محاولة. المكسب: مفيش لفّة لا نهائية بتاكل الـ CPU. الخسارة: لو مراقبتش اللوجات، ممكن خدمة بتتعافى وتكراش بشكل متكرر تبان شغّالة وانت مش واخد بالك، فاحتجت مراقبة وتنبيه فوق systemd زي Healthchecks أو Prometheus.
متى متستخدمش systemd
مش كل حالة محتاجة service unit. لو تطبيقك جوّه حاوية Docker أو Kubernetes، اعتمد على سياسة إعادة التشغيل بتاعة المنصّة دي (مثلاً restart: always في compose أو الـ Pod restartPolicy) بدل ما تحط systemd جوّه الحاوية. لو المهمة بتتنفّذ مرة وتخلص (نسخة احتياطية يومية مثلاً)، الـ cron أو الـ systemd timer أنسب من خدمة دائمة. ولو محتاج توزيع الحمل وتوسّع تلقائي عبر أكتر من سيرفر، systemd لوحده مش كفاية، هتحتاج orchestrator. وطبعًا systemd خاص بلينكس، فمش هينفع على ويندوز.
الخطوة التالية
افتح سيرفرك دلوقتي، اعمل ملف /etc/systemd/system/myapp.service بالقالب اللي فوق بعد ما تغيّر User وWorkingDirectory وExecStart على تطبيقك، وشغّل sudo systemctl enable --now myapp. وبعدين اعمل reboot للسيرفر وتأكد إن الخدمة رجعت active (running) لوحدها. لو رجعت، يبقى تطبيقك بقى خدمة دائمة فعلاً.
المصادر
- توثيق systemd الرسمي — وحدات الخدمة: systemd.service(5)
- توثيق systemd الرسمي — تعريف الوحدات و StartLimit: systemd.unit(5)
- توثيق التحكم في الخدمات: systemctl(1)
- قراءة اللوجات: journalctl(1)