أذكرها وكأنها البارحة، ليلة شتاء قارس، الساعة تقارب الثالثة فجرًا. رنين الهاتف المخصص للطوارئ (on-call) يكسر صمت الليل العميق. على الطرف الآخر، صوت زميلي المتوتر: “أبو عمر، الموقع واقع! كل شيء أحمر!”.
قفزت من سريري، وفي ثوانٍ كنت أمام شاشة اللابتوب. بدأت الفوضى التي أعرفها جيدًا. أنا فتحت الـ Grafana لأرى الرسوم البيانية، وزميلي يصرخ في مكالمة Zoom أنه يفحص سجلات الأخطاء (Logs) على Kibana. شخص ثالث من فريق البنية التحتية يحاول الدخول إلى الـ AWS Console ليرى حالة الخوادم. أما مدير المشروع، فكان يرسل رسائل متتالية على جروب الواتساب: “شو صار؟”، “وين المشكلة؟”، “كم بدكم وقت؟”.
كنا مثل أوركسترا تعزف بدون مايسترو، كل واحد في وادٍ. المعلومات مبعثرة بين خمسة تطبيقات مختلفة على الأقل. كل دقيقة تمر كانت تكلفنا مالًا وسمعة. بعد حوالي 45 دقيقة من “جحيم التبديل بين السياقات” (Context Switching Hell)، اكتشفنا المشكلة وقمنا بحلها. لكن السؤال الذي ظل يطاردني بعد تلك الليلة: “معقول في 2024، لسا بنشتغل بهالعبثية؟”. كانت تلك الليلة هي الشرارة التي دفعتنا للبحث عن حل جذري، وكان الحل يحمل اسمًا بسيطًا وأنيقًا: ChatOps.
ما هي الـ ChatOps؟ وكيف تعمل؟
ببساطة شديدة، ومن الآخر، الـ ChatOps هي ممارسة تتمحور حول جلب أدواتك، عملياتك، وأتمتة عملك… إلى داخل منصة المحادثة التي يستخدمها فريقك بالفعل. سواء كانت Slack، Microsoft Teams، أو أي منصة أخرى، الفكرة هي أن تتحول نافذة الدردشة من مجرد مكان للكلام و”صباح الخير”، إلى مركز قيادة وتحكم متكامل.
تخيل معي هذا المشهد: بدلًا من أن تفتح عشر نوافذ، أنت تكتب أمرًا بسيطًا في قناة الدردشة:
/bot deploy website-v2 to production
فيرد عليك “البوت” في نفس القناة، ويقوم بتنفيذ عملية النشر (Deployment) المعقدة في الخلفية، ويُعلم الجميع بالنتائج خطوة بخطوة. هذا هو جوهر الـ ChatOps: تحويل المحادثات إلى أوامر، والأوامر إلى أفعال موثّقة ومرئية للجميع.
الفوضى المنظمة: مقارنة بين إدارة الحوادث قبل وبعد الـ ChatOps
لكي تتضح الصورة أكثر، دعونا نقارن بين السيناريوهين، سيناريو الفوضى الذي عشته، وسيناريو الهدوء المنظم الذي وصلنا إليه.
الطريقة القديمة: جحيم التبديل بين الأدوات
في أي حادثة (Incident) كانت تمر علينا، كانت هذه هي الأدوات التي نتنقل بينها كالمجانين:
- PagerDuty / Opsgenie: لتلقي التنبيه الأولي على الهاتف.
- Zoom / Google Meet: لفتح مكالمة طارئة لمحاولة فهم ما يجري.
- Slack / WhatsApp: للمحادثات الجانبية السريعة وإرسال لقطات الشاشة.
- Grafana / Datadog: لمراقبة الرسوم البيانية والمقاييس الحيوية للنظام.
- Kibana / Logz.io: للبحث في سجلات الأخطاء (Logs).
- Jira: لإنشاء تذكرة يدوية لتوثيق الحادثة.
- AWS/Azure/GCP Console: للوصول إلى البنية التحتية مباشرة.
- Terminal (SSH): للاتصال بالخوادم وتنفيذ الأوامر.
المشكلة لم تكن في الأدوات نفسها، فهي ممتازة. المشكلة كانت في انعزال المعلومات. الحوار الذي دار في Zoom، لم يره من انضم متأخرًا. لقطة الشاشة التي أُرسلت على واتساب، ضاعت في سجل المحادثات. الأمر الذي نفذه أحدهم على الخادم، لم يتم توثيقه. كانت عملية مرهقة، بطيئة، وتجعل من كتابة تقرير ما بعد الحادثة (Post-mortem) مهمة شبه مستحيلة.
طريقة الـ ChatOps: مركز قيادة موحد
الآن، تخيل معي السيناريو الجديد بعد تبنينا للـ ChatOps:
- (03:01 صباحًا) نظام المراقبة (Prometheus) يكتشف ارتفاعًا حادًا في استخدام الـ CPU لقاعدة البيانات.
- (03:01 صباحًا) التنبيه يُرسَل إلى بوت الـ ChatOps الخاص بنا على Slack.
- (03:02 صباحًا) البوت يقوم تلقائيًا بالآتي:
- ينشئ قناة جديدة خاصة بالحادثة، مثل:
#incident-db-high-cpu-2024-05-20. - يدعو مهندسي الطوارئ (on-call engineers) إلى القناة.
- ينشر ملخصًا أوليًا للمشكلة مع رابط للرسم البياني ذي الصلة في Grafana.
- ينشئ تذكرة في Jira ويربطها بالقناة.
- ينشئ قناة جديدة خاصة بالحادثة، مثل:
- (03:05 صباحًا) أنا وزميلي ندخل القناة. كل المعلومات الأولية أمامنا في مكان واحد. لا حاجة لمكالمة، لا حاجة لسؤال “شو القصة؟”.
- (03:06 صباحًا) أكتب في القناة:
/bot run diagnostics on db-primary. - (03:07 صباحًا) البوت يرد بنتائج الفحص: قائمة بالعمليات الأكثر استهلاكًا للمعالج.
- (03:09 صباحًا) زميلي يكتب:
/bot show slow-queries last 15m. - (03:10 صباحًا) البوت يعرض قائمة بالاستعلامات البطيئة التي تسببت بالمشكلة.
- (03:12 صباحًا) بعد التأكد من المشكلة، نكتب أمرًا لإنهاء الاستعلام الضار:
/bot kill-query 12345. - (03:15 صباحًا) البوت يؤكد أن الوضع عاد طبيعيًا، ويقوم بتحديث تذكرة Jira بالحالة “تم الحل”.
هل ترى الفرق؟ كل خطوة، كل أمر، كل نتيجة، وكل نقاش، تم توثيقه بالترتيب الزمني في مكان واحد. القناة نفسها أصبحت هي “الصندوق الأسود” للحادثة، وهي مصدر الحقيقة الأوحد.
كيف تبدأ رحلتك مع الـ ChatOps؟ خطوات عملية من المطبخ
قد يبدو الأمر معقدًا، ولكنه أسهل مما تتصور إذا اتبعنا نهجًا تدريجيًا. هذه هي الخطوات التي اتبعناها:
الخطوة الأولى: اختر ساحة المعركة (منصة الدردشة)
على الأغلب، فريقك يستخدم منصة ما بالفعل. Slack، Microsoft Teams، Mattermost… لا يهم. المهم هو أن تبدأ من حيث يتواجد فريقك. لا تحاول فرض أداة جديدة عليهم. قوة الـ ChatOps تكمن في أنها تندمج في سير العمل الحالي، لا أن تخلق واحدًا جديدًا.
الخطوة الثانية: جهّز أسلحتك (البوت الخاص بك)
البوت هو قلب وروح نظام الـ ChatOps. لديك خياران رئيسيان:
- استخدام بوت جاهز أو تكاملات مدمجة: معظم الأدوات الحديثة (مثل PagerDuty, Grafana, Jira) تأتي مع تكاملات قوية لمنصات الدردشة. هذا هو أسرع طريق للبدء. يمكنك البدء بتوجيه التنبيهات إلى قناة مخصصة.
- بناء بوتك المخصص: هذا يمنحك مرونة لا نهائية. يمكنك استخدام أطر عمل مثل Hubot (CoffeeScript/JS)، أو Lita (Ruby)، أو ببساطة استخدام مكتبات الـ SDK الخاصة بمنصة الدردشة التي تفضلها (مثل
slack_boltلـ Python أو@slack/boltلـ Node.js).
مثال عملي: بوت بسيط لإدارة الحوادث على Slack باستخدام Python
لأعطيك فكرة ملموسة، هذا مثال بسيط جدًا باستخدام مكتبة slack_bolt في Python. هذا البوت يستجيب لأمر /incident لإنشاء قناة جديدة لحادثة ما.
أولاً، ستحتاج لتثبيت المكتبات:
pip install slack_bolt slack_sdk
ثم، هذا هو كود البوت (مثال مبسط للتوضيح):
import os
from slack_bolt import App
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
import logging
# إعداد اللوغات
logging.basicConfig(level=logging.INFO)
# إعداد التطبيق باستخدام التوكنز من متغيرات البيئة
# SLACK_BOT_TOKEN يبدأ بـ xoxb-
# SLACK_SIGNING_SECRET للتأكد من أن الطلبات قادمة من Slack
app = App(
token=os.environ.get("SLACK_BOT_TOKEN"),
signing_secret=os.environ.get("SLACK_SIGNING_SECRET")
)
# تعريف الأمر /incident
@app.command("/incident")
def handle_incident_command(ack, body, client, logger):
# تأكيد استلام الأمر فورًا
ack()
# استخراج وصف الحادثة من نص الأمر
incident_description = body.get("text", "حادثة جديدة بدون وصف")
user_id = body["user_id"]
channel_name = f"incident-{incident_description.replace(' ', '-')[:20]}-{body['trigger_id'][:5]}"
try:
# محاولة إنشاء قناة جديدة
response = client.conversations_create(
name=channel_name,
is_private=False # يمكن جعلها خاصة is_private=True
)
channel_id = response["channel"]["id"]
logger.info(f"تم إنشاء القناة بنجاح: {channel_id}")
# دعوة المستخدم الذي أطلق الأمر إلى القناة
client.conversations_invite(
channel=channel_id,
users=user_id
)
# إرسال رسالة ترحيبية في القناة الجديدة
client.chat_postMessage(
channel=channel_id,
text=f"🚨 حادثة جديدة: *{incident_description}*n"
f"تم إنشاء هذه القناة بواسطة <@{user_id}> لمتابعة الحادثة.n"
f"هنا سيكون مركز القيادة والتحكم. كل الإجراءات والنقاشات يجب أن تتم هنا للتوثيق."
)
# إعلام المستخدم في القناة الأصلية بأن القناة قد أُنشئت
client.chat_postMessage(
channel=body["channel_id"],
text=f"تم إنشاء قناة الحادثة بنجاح: <#{channel_id}|{channel_name}>"
)
except SlackApiError as e:
logger.error(f"حدث خطأ في التعامل مع Slack API: {e.response['error']}")
client.chat_postMessage(
channel=body["channel_id"],
text=f"عفوًا، لم أتمكن من إنشاء قناة الحادثة. الخطأ: {e.response['error']}"
)
# تشغيل التطبيق
if __name__ == "__main__":
app.start(port=int(os.environ.get("PORT", 3000)))
هذا الكود هو مجرد بداية. يمكنك توسيعه ليشمل دعوة فريق الطوارئ تلقائيًا، نشر معلومات من أنظمة المراقبة، التفاعل مع Jira، وإضافة أوامر أخرى مثل /resolve-incident التي تقوم بأرشفة القناة وإرسال ملخص نهائي.
ثمار الـ ChatOps ونصائح أبو عمر الذهبية
بعد تطبيقنا لهذه الثقافة، لم نعد نتخيل العودة إلى الطريقة القديمة. الفوائد كانت واضحة وملموسة.
الفوائد التي جنيناها
- الشفافية والوضوح (Visibility & Transparency): كل شخص في الشركة، من المهندس المبتدئ إلى المدير التنفيذي، يمكنه الدخول إلى قناة الحادثة ورؤية ما يحدث بالضبط، لحظة بلحظة. لا مزيد من “هل من جديد؟”.
- سرعة في حل المشاكل (Faster Resolution): تقليل وقت التبديل بين الأدوات يعني أننا نقضي وقتًا أطول في حل المشكلة نفسها، لا في البحث عن المعلومات.
- تحسين التعاون (Improved Collaboration): وجود مكان مركزي يشجع على الحوار المنظم والعمل الجماعي الحقيقي.
- توثيق تلقائي (Knowledge Capture): سجل المحادثات في القناة هو أفضل تقرير ما بعد الحادثة (Post-mortem) يمكن أن تطلبه. كل شيء موثق بالوقت، بالشخص، وبالسياق.
- دمقرطة الأدوات (Democratization of Tools): لم يعد حل المشاكل حكرًا على “خبراء” سطر الأوامر. يمكن لمدير المنتج أو مهندس الدعم الفني تشغيل أوامر تشخيصية آمنة ومحددة مسبقًا لفهم المشكلة بشكل أفضل.
نصائح من القلب
من خبرتي المتواضعة، اسمحوا لي أن أقدم لكم بعض النصائح العملية:
- ابدأ صغيرًا (Start Small): لا تحاول أتمتة الكون في يوم واحد. ابدأ بأكبر نقطة ألم. ربما تكون مجرد تجميع كل التنبيهات في قناة واحدة. هذا بحد ذاته فوز كبير. ثم أضف أمرًا واحدًا مفيدًا، ثم الذي يليه.
- الأمان أولًا وقبل كل شيء (Security First): هذه نقطة حرجة. كن حذرًا جدًا بشأن الأوامر التي يمكن للبوت تنفيذها. خصوصًا الأوامر التي تعدّل أو تحذف شيئًا. طبق صلاحيات صارمة (Access Control). تأكد من أن أمرًا مثل
/bot restart production-dbيتطلب صلاحيات خاصة وتأكيدًا متعددًا. مش كل إشي بنفع نكبسله زر يا جماعة! - صمّم للإنسان (Design for Humans): اجعل ردود البوت واضحة، مختصرة، ومفيدة. استخدم التنسيق الجيد، الروابط، وحتى الرموز التعبيرية (باعتدال) لتسهيل قراءة المعلومات. يجب أن يكون التفاعل مع البوت أسهل من فتح الأداة الأصلية.
- وثّق أوامرك (Document Your Commands): يجب أن يكون لدى البوت أمر
/bot helpيعرض قائمة بجميع الأوامر المتاحة وشرحًا بسيطًا لكل منها.
الخلاصة: هل الـ ChatOps هي الحل السحري؟
لا، الـ ChatOps ليست عصا سحرية ستحل كل مشاكلك بلمسة زر. إنها في جوهرها تغيير ثقافي مدعوم بالأدوات، وليس العكس. إنها تتطلب من الفريق تبني عقلية الشفافية، التعاون، والتوثيق المستمر.
بالنسبة لنا، لم تكن الـ ChatOps مجرد أداة جديدة أضفناها إلى مجموعتنا. لقد كانت تغييرًا جوهريًا في طريقة تفكيرنا وعملنا كفريق. انتقلنا من حالة “كل واحد يغني على ليلاه” إلى أوركسترا متناغمة. صرنا نعمل مع بعضنا البعض، وليس فقط بجانب بعضنا البعض. وهذا، يا أصدقائي، هو الفرق الذي يصنع كل الفرق. ✅