انتقل إلى المحتوى الرئيسي

المختبر 8.6 - إيقاف خدمة

الأهداف​

في نهاية هذا المختبر، ستكون قادرًا على:

  • تحديد عملية تستخدم منفذًا محددًا
  • العثور على خدمة systemd المرتبطة بعملية
  • فهم لماذا لا يكفي استخدام kill وحده لإيقاف خدمة
  • استخدام systemctl stop وdisable لإيقاف خدمة بشكل دائم
  • أتمتة تحديد خدمة عبر سكربت bash
  • استخدام طرق متقدمة لتشخيص الخدمات

المتطلبات​

  • وجود موقع Wiki.js قيد التشغيل
  • تثبيت nginx
  • تثبيت Ubuntu 24.04
  • وصول sudo/root
  • فتح الطرفية

تثبيت Nginx (إذا لزم الأمر)​

sudo apt update
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl status nginx

السياق​

السيد إريك، مسؤول النظام، يحاول تثبيت وتشغيل تطبيق يسمى Wiki.js على خادم Ubuntu. من المفترض أن يستمع التطبيق على المنفذ 3000، لكنه لا يعمل. بعد عدة محاولات فاشلة، يبدأ إريك سلسلة من التحقيقات لتحديد المشكلة وحلها.


الخطوة 1 – التحقق من المنفذ المستخدم​

يبدأ إريك بالتحقق مما إذا كان المنفذ 3000 مستخدمًا بالفعل من قبل خدمة أخرى. يستخدم الأمر التالي:

lsof -i :3000

النتيجة المحصل عليها:

COMMAND   PID   USER     FD   TYPE DEVICE SIZE/OFF NODE NAME
node 9744 wikijs 22u IPv4 59242 0t0 TCP *:3000 (LISTEN)

عملية node تستمع على المنفذ 3000. يسجل PID: 9744.

التحليل​

  • COMMAND : node - العملية هي تطبيق Node.js
  • PID : 9744 - معرف العملية
  • USER : wikijs - المستخدم الذي يشغل العملية
  • PORT : 3000 - المنفذ المستمع

الخطوة 2 – محاولة تحرير المنفذ باستخدام kill​

يحاول إريك إيقاف العملية يدويًا:

# محاولة إيقاف نظيف (SIGTERM)
kill -15 9744

# إذا لم ينجح ذلك، إيقاف إجباري (SIGKILL)
kill -9 9744

التحقق​

بعد تنفيذ هذه الأوامر، يتحقق إريك مرة أخرى:

lsof -i :3000

النتيجة:

COMMAND   PID   USER     FD   TYPE DEVICE SIZE/OFF NODE NAME
node 9842 wikijs 22u IPv4 59243 0t0 TCP *:3000 (LISTEN)

الاستنتاج: يتم إعادة تشغيل العملية تلقائيًا. يظهر PID جديد (9842). كيان آخر (ربما خدمة systemd) يعيد تشغيله.

لماذا تعيد العملية التشغيل؟​

تعيد العملية التشغيل تلقائيًا لأنها تُدار بواسطة خدمة systemd مع خيار Restart=always في تكوينها. حتى إذا قتلت العملية، فإن systemd يعيد تشغيلها فورًا.


الخطوة 3 – البحث عن خدمة systemd​

يشتبه إريك في وجود خدمة systemd. لذلك يبحث عن اسمها الدقيق.

الأوامر المستخدمة​

# سرد جميع الخدمات
systemctl list-units --type=service

# سرد الخدمات المتوقفة
systemctl list-units --type=service --state=exited

# سرد الخدمات الجارية
systemctl list-units --type=service --state=running

# التصفية للعثور على خدمات Wiki
systemctl list-units --type=service --state=running | grep -i wiki

البحث في ملفات الخدمة​

# سرد ملفات الخدمة حسب تاريخ التعديل
ls -l --sort=time /etc/systemd/system/

# التصفية للعثور على خدمات Wiki
ls -l /etc/systemd/system/ | grep wiki

عمليات البحث المتقاطعة​

# البحث في الاتصالات الشبكية
sudo ss | grep -i wiki
sudo ss | grep -i 3000

# البحث عن عمليات Node.js
ps aux | grep node

# البحث عن الخدمات التي تحتوي على "node"
systemctl | grep node

الأوامر الفائزة​

الأوامر الأكثر فعالية لتحديد الخدمة هي:

# العثور على خدمات Wiki الجارية
systemctl list-units --type=service --state=running | grep -i wiki

# البحث عن ملفات خدمة Wiki
ls -l /etc/systemd/system/ | grep wiki

# رؤية عمليات Node.js
ps aux | grep node

# البحث عن الخدمات التي تحتوي على "node"
systemctl | grep node

الفرضية المؤكدة: يبدو أن خدمة تسمى wikijs.service مسؤولة عن العملية.


الخطوة 4 – التحقق من الارتباط بين العملية والمنفذ والخدمة​

يقوم إريك بربط العملية node والمنفذ 3000 والخدمة المعنية يدويًا:

تحديد العملية على المنفذ​

# رؤية العملية التي تستمع على المنفذ 3000
lsof -i :3000

# رؤية جميع عمليات Node.js ومنافذها
sudo lsof -i -P -n | grep node

# رؤية جميع عمليات Wiki.js
sudo lsof -i -P -n | grep wiki

تحديد ملف الخدمة​

# البحث عن ملف الخدمة
ls -l /etc/systemd/system/ | grep wiki

الملف المحدد: wikijs.service

التحقق من الخدمة​

# رؤية حالة الخدمة
sudo systemctl status wikijs.service

# رؤية سجلات الخدمة
sudo journalctl -u wikijs.service --no-pager --lines=50

الخطوة 5 – الإيقاف النهائي للخدمة وتحرير المنفذ​

يقوم إريك بإيقاف الخدمة بشكل نظيف وتعطيل إعادة تشغيلها التلقائي:

إيقاف الخدمة​

# إيقاف الخدمة
sudo systemctl stop wikijs.service

تعطيل إعادة التشغيل التلقائي​

# تعطيل الخدمة عند بدء التشغيل
sudo systemctl disable wikijs.service

التحقق النهائي​

# التحقق من أن المنفذ تم تحريره
lsof -i :3000

# التحقق من حالة الخدمة
sudo systemctl status wikijs.service

النتيجة: تم تحرير المنفذ 3000 الآن. لن تعيد الخدمة التشغيل تلقائيًا.


الخطوة الإضافية – فحص كامل للمنافذ المفتوحة (اختياري)​

للتأكد من الحالة العامة للخادم، يستخدم إريك أداة nmap:

# تثبيت nmap
sudo apt install nmap -y

# فحص المنافذ المفتوحة على localhost
sudo nmap -sT -O localhost

# فحص منفذ محدد
sudo nmap -p 3000 localhost

أسئلة للتفكير​

  1. لماذا كان المنفذ 3000 يبقى محجوزًا رغم استخدام kill؟

    • اشرح دور systemd في إدارة الخدمات
    • لماذا لا يكفي kill وحده؟
  2. ما هي الطريقة التي تسمح بتحديد اسم الخدمة التي تستخدم منفذًا محددًا؟

    • اشرح الطريقة خطوة بخطوة
    • ما هي الأوامر الأكثر فعالية؟
  3. ما هي الأوامر التي يمكن استخدامها للبحث عن جميع الخدمات التي تحتوي على كلمة wiki في اسمها أو وصفها؟

    • اقترح عدة طرق
  4. اقترح سكربت bash يسمح بأتمتة هذا التحقيق.

    • يجب أن يحدد السكربت تلقائيًا الخدمة المرتبطة بمنفذ

الملحق 1: طرق أكثر تقدمًا​

الطريقة الموصوفة (البحث اليدوي من المنفذ باستخدام lsof، ps، systemctl، إلخ) هي موثوقة ولكنها يدوية. هناك طرق أكثر تقدمًا وأتمتة، مفيدة للبيئات المعقدة، مثل الخوادم الإنتاجية أو العناقيد.

1. systemd-cgls أو systemd-cgtop​

تتيح هذه الأدوات عرض شجرة الخدمات والعمليات التي يتحكم فيها systemd.

# رؤية الشجرة الكاملة
systemd-cgls

# التصفية لـ Wiki.js
systemd-cgls | grep -i wiki

# التصفية لـ PostgreSQL
systemd-cgls | grep -i postgres

# التصفية لـ Nginx
systemd-cgls | grep -i nginx

# رؤية شجرة خدمة محددة
systemd-cgls /system.slice/wikijs.service

# سرد cgroups
ls /sys/fs/cgroup/system.slice/ | grep wiki

# رؤية عمليات Wiki
ps -ef | grep wiki

2. systemctl status مع --property​

يمكنك استجواب جميع الخدمات وطلب رؤية MainPID، ثم التقاطع مع المنفذ:

# رؤية جميع MainPID للخدمات
systemctl show --all --property=MainPID --no-pager

# لخدمة محددة
systemctl show wikijs.service --property=MainPID

ثم:

# رؤية PID الذي يستخدم المنفذ 3000
sudo lsof -i :3000

وتقارن MainPID مع PID الذي يستخدم المنفذ.

3. استخدام fuser لقتل العملية مباشرة عبر المنفذ​

# قتل العملية المرتبطة بالمنفذ 3000
sudo fuser -k 3000/tcp

تنبيه: هذه الطريقة لا تعطل الخدمة، لذا يمكن أن تعيد التشغيل. إنها مفيدة في سكربت مؤقت.

4. باستخدام ss --processes​

# رؤية العملية التي تستمع على المنفذ 3000
sudo ss -lptn 'sport = :3000'

هذا يظهر مباشرة:

  • المنفذ،
  • البروتوكول،
  • العملية،
  • وأحيانًا اسم الخدمة إذا تم تكوينه بشكل جيد.

5. استخدام netstat مع --program (إذا كان متاحًا)​

# تثبيت net-tools إذا لزم الأمر
sudo apt update
sudo apt install net-tools

# رؤية العملية على المنفذ 3000
sudo netstat -tulnp | grep 3000

يسمح بتحديد البرنامج الذي يستخدم منفذًا مباشرة. يمكنك التقاطع مع systemctl:

# رؤية تفاصيل العملية
ps -p <PID> -o pid,cmd

6. عبر سجلات systemd​

إذا تم تشغيل الخدمة بشكل جيد بواسطة systemd، يمكنك القيام بـ:

# رؤية سجلات الخدمة
journalctl -u wikijs.service

# رؤية السجلات في الوقت الحقيقي
journalctl -u wikijs.service -f

# رؤية السطور الأخيرة
journalctl -u wikijs.service --no-pager --lines=50

هذا يظهر لك تاريخ التنفيذ، بما في ذلك المنفذ المستمع.


الملحق 2: أتمتة تحديد الخدمة​

سكربت Bash: تحديد خدمة systemd وراء منفذ​

قم بإنشاء ملف recherche_service_port.sh:

#!/bin/bash

# طلب من المستخدم إدخال رقم المنفذ
read -p "أدخل رقم المنفذ (مثال: 3000) : " PORT

# الخطوة 1: الحصول على PID للعملية التي تستمع على هذا المنفذ
PID=$(sudo lsof -i :$PORT -sTCP:LISTEN -t)

# التحقق مما إذا تم العثور على PID
if [ -z "$PID" ]; then
echo "لا يبدو أن هناك عملية تستمع على المنفذ $PORT."
exit 1
fi

echo "تم الكشف عن عملية على المنفذ $PORT : PID = $PID"

# الخطوة 2: عرض المعلومات حول العملية
echo "الأمر المرتبط بهذا PID :"
ps -p $PID -o pid,cmd

# الخطوة 3: البحث عن خدمة systemd التي تنتمي إليها هذا PID
echo ""
echo "البحث عن خدمة systemd المقابلة..."

# الطريقة 1: البحث عبر systemctl
SERVICE=$(systemctl | grep $PID | awk '{print $1}')

# الطريقة 2: إذا لم يتم العثور عليها، البحث في ملفات الخدمة
if [ -z "$SERVICE" ]; then
echo "البحث في ملفات الخدمة..."
# البحث عن PID في cgroups
for service_file in /etc/systemd/system/*.service; do
if [ -f "$service_file" ]; then
service_name=$(basename "$service_file")
# التحقق مما إذا كانت الخدمة نشطة وتطابق PID
main_pid=$(systemctl show "$service_name" --property=MainPID --value 2>/dev/null)
if [ "$main_pid" = "$PID" ]; then
SERVICE="$service_name"
break
fi
fi
done
fi

# الطريقة 3: البحث عبر cgroup
if [ -z "$SERVICE" ]; then
cgroup=$(cat /proc/$PID/cgroup 2>/dev/null | grep system.slice | cut -d: -f3)
if [ -n "$cgroup" ]; then
SERVICE=$(basename "$cgroup" .service)
fi
fi

if [ -z "$SERVICE" ]; then
echo "لم يتم العثور على خدمة systemd تلقائيًا لـ PID $PID."
echo "التحقق اليدوي ممكن باستخدام:"
echo " systemctl status <nom_du_service>"
echo "أو البحث في /etc/systemd/system/"
echo ""
echo "الأوامر المفيدة:"
echo " ps -p $PID -o pid,cmd"
echo " systemctl list-units --type=service | grep -i wiki"
echo " ls -l /etc/systemd/system/ | grep wiki"
else
echo "تم الكشف عن خدمة systemd : $SERVICE"
echo ""
echo "حالة الخدمة:"
systemctl status $SERVICE --no-pager -l
echo ""
echo "لإيقاف الخدمة:"
echo " sudo systemctl stop $SERVICE"
echo " sudo systemctl disable $SERVICE"
fi

الاستخدام​

  1. احفظ السكربت في ملف:
nano recherche_service_port.sh
  1. اجعله قابلًا للتنفيذ:
chmod +x recherche_service_port.sh
  1. نفذه:
./recherche_service_port.sh

ما تعلمته​

  • كيفية ربط منفذ بعملية (lsof)
  • كيفية الرجوع إلى الخدمة عبر systemctl وgrep
  • كيفية أتمتة تشخيص الشبكة في Bash
  • كيفية استخدام cgroups لتحديد الخدمات

ملخص الأوامر المهمة​

الأمرالوصف
lsof -i :3000رؤية العملية التي تستمع على المنفذ 3000
kill -15 PIDإيقاف نظيف للعملية (SIGTERM)
kill -9 PIDإيقاف إجباري للعملية (SIGKILL)
systemctl list-units --type=service --state=runningسرد الخدمات النشطة
systemctl stop wikijs.serviceإيقاف خدمة
systemctl disable wikijs.serviceتعطيل خدمة عند بدء التشغيل
systemctl status wikijs.serviceرؤية حالة خدمة
journalctl -u wikijs.serviceرؤية سجلات خدمة
sudo ss -lptn 'sport = :3000'رؤية العملية على منفذ باستخدام ss
sudo fuser -k 3000/tcpقتل العملية على منفذ

التحقق النهائي​

تحقق من أنك قد نجحت في:

  • تحديد العملية التي تستخدم المنفذ 3000
  • فهم لماذا لا يكفي kill وحده
  • العثور على خدمة systemd المسؤولة
  • إيقاف وتعطيل الخدمة بشكل صحيح
  • التحقق من أن المنفذ تم تحريره
  • استخدام الطرق المتقدمة للتشخيص
  • إنشاء واستخدام سكربت الأتمتة
  • الإجابة على أسئلة التفكير

الخطوات التالية​

  • المختبر 8.1: إدارة خدمات systemd (مراجعة)
  • المختبر 8.5: مثيلات Wiki.js متعددة (إنشاء مثيلات متعددة)
  • TP 3: اختبار systemd والعمليات (تقييم)

تم إنشاء المختبر في: ديسمبر 2024