كانت ‘ليالي الإطلاق’ كابوساً: كيف أنقذنا ‘خط أنابيب CI/CD’ من جحيم النشر اليدوي؟

أذكرها وكأنها البارحة، ليلة خميس، الساعة الثانية بعد منتصف الليل. أنا وفريق العمل في مكتبي الصغير، رائحة القهوة المُرّة تملأ المكان، وأصوات نقر الكيبورد لا تهدأ. كان موعد إطلاق نسخة جديدة من تطبيقنا، وهو حدث من المفترض أن يكون سعيداً، لكنه بالنسبة لنا كان أشبه بليلة من ليالي الجحيم.

كنت مسؤولاً عن عملية النشر. فتحتُ الطرفية (Terminal)، وبدأت طقوسي المعتادة: الاتصال بالخادم عبر SSH، سحب آخر التحديثات من Git، تشغيل أوامر البناء، إعادة تشغيل الخادم، ثم… الدعاء. في تلك الليلة، حدث ما كنا نخشاه. خطأ بسيط، ربما نسيت تحديث إحدى المكتبات، أو سحبت التفرع الخاطئ من Git. النتيجة؟ الموقع بأكمله توقف عن العمل. “الموقع طار يا جماعة!”، صرختُ بقلق. بدأ الذعر، محاولات يائسة لإصلاح المشكلة يدوياً، والعملاء بدأت رسائلهم تصل. بعد ساعتين من التوتر والعرق البارد، تمكنا من إعادة الموقع للعمل. في تلك اللحظة، نظرت إلى زملائي وقلت: “يا زلمة، لازم يكون في طريقة أحسن من هيك. مش معقول نضل عايشين بهاد الرعب مع كل إطلاق!”.

تلك الليلة كانت نقطة التحول. كانت بداية رحلتنا من الفوضى المنظمة إلى عالم الأتمتة الجميل، عالم الـ CI/CD. وفي هذه المقالة، سآخذكم معي في هذه الرحلة بالتفصيل.

ما هو الجحيم الذي كنا نعيش فيه؟ (عالم النشر اليدوي)

قبل أن ننتقل إلى الحل، دعوني أصف لكم بالتفصيل حجم المعاناة التي كنا نمر بها. لم تكن عملية النشر مجرد “نسخ ولصق”، بل كانت سلسلة من الخطوات اليدوية المحفوفة بالمخاطر.

قائمة الخطوات اليدوية القاتلة

كانت عملية النشر لدينا تبدو كالتالي لكل تحديث:

  1. الاتصال بالخادم: فتح الطرفية وكتابة ssh user@server_ip.
  2. سحب الكود: الانتقال إلى مجلد المشروع وتشغيل git pull origin main. (وهنا تحدث الكارثة أحياناً إذا سحبت من الفرع الخطأ).
  3. تثبيت الاعتماديات: تشغيل npm install أو composer install. (ويا ويلك لو نسيت هذه الخطوة!).
  4. بناء المشروع: تشغيل أوامر مثل npm run build لتهيئة ملفات الواجهة الأمامية.
  5. تشغيل migrations: تحديث قاعدة البيانات إن لزم الأمر.
  6. إعادة تشغيل الخادم: استخدام أدوات مثل pm2 restart app أو systemctl restart nginx.
  7. الاختبار اليدوي: فتح الموقع وتصفحه بسرعة للتأكد من أن كل شيء يعمل.

أي خطأ أو نسيان في أي من هذه الخطوات كان يعني كارثة محققة، ووقت ضائع، وضغط نفسي هائل على الفريق.

“على جهازي شغال!” – كابوس عدم تطابق البيئات

كم مرة سمعت هذه الجملة؟ “لكن الكود شغال تماماً على جهازي!”. هذه لم تكن مزحة، بل كانت حقيقة مؤلمة. بيئة التطوير على جهاز المبرمج تختلف تماماً عن بيئة الخادم (Production). إصدارات مختلفة من Node.js، مكتبات نظام مختلفة، متغيرات بيئة (Environment Variables) غير موجودة… كل هذه الاختلافات كانت مصدراً لا ينتهي من الأخطاء التي لا تظهر إلا بعد النشر.

الخوف من زر “النشر”

مع الوقت، تحول يوم الإطلاق من يوم حماسي إلى يوم مرعب. أصبح الفريق يتجنب إجراء التحديثات إلا للضرورة القصوى، مما أدى إلى تراكم التغييرات وجعل كل عملية إطلاق أكبر وأكثر خطورة. فقدنا الرشاقة (Agility) وأصبح تطوير الميزات الجديدة بطيئاً خوفاً من عملية النشر.

بداية الخلاص: تعرفنا على CI/CD

بعد ليلة الكارثة، عقدنا العزم على إيجاد حل. بدأنا البحث والقراءة، وهنا تعرفنا على مصطلحين غيرا حياتنا المهنية: التكامل المستمر (Continuous Integration) والنشر المستمر (Continuous Deployment/Delivery)، أو اختصاراً CI/CD.

شو يعني CI/CD؟ (ببساطة يا جماعة)

لنبسط الأمور. تخيل أن لديك مصنعاً لتجميع السيارات. بدلاً من بناء كل سيارة يدوياً من الصفر، لديك خط تجميع آلي.

  • التكامل المستمر (CI): هو الجزء الأول من خط التجميع. كلما أضاف مهندس قطعة جديدة (كود جديد)، يقوم الروبوت (نظام الـ CI) بأخذها ودمجها مع هيكل السيارة، ثم يجري عليها اختبارات سريعة للتأكد من أنها رُكّبت بشكل صحيح ولا تتعارض مع القطع الأخرى. إذا فشل الاختبار، يتوقف الخط فوراً ويتم إبلاغ المهندس. هذا يضمن اكتشاف الأخطاء مبكراً جداً.
  • النشر/التسليم المستمر (CD): هو الجزء الثاني من الخط. بعد أن تنجح السيارة في كل اختبارات الجودة (CI)، يقوم روبوت آخر (نظام ال-CD) بطلائها وتجهيزها ثم إرسالها تلقائياً إلى صالة العرض (الخادم). التسليم المستمر (Continuous Delivery) يعني أن السيارة جاهزة للإرسال بضغطة زر، بينما النشر المستمر (Continuous Deployment) يعني أنها تُرسل تلقائياً بدون أي تدخل بشري.

باختصار، CI/CD هو بناء “خط أنابيب” (Pipeline) آلي يأخذ الكود من المبرمج ويمرره عبر سلسلة من مراحل البناء والاختبار والنشر بشكل تلقائي وموثوق.

رحلتنا العملية: بناء أول خط أنابيب CI/CD

الكلام النظري جميل، لكن التطبيق العملي هو الأهم. قررنا استخدام GitHub Actions لبناء أول خط أنابيب لنا، لأنه مدمج مباشرة في GitHub وسهل البدء به. سأريكم مثالاً عملياً لتطبيق Node.js بسيط.

الخطوة الأولى: تحديد مراحل خط الأنابيب

قبل كتابة أي كود، رسمنا المراحل التي نريد أتمتتها:

  1. Trigger (المُحفّز): عند عمل push للكود على الفرع الرئيسي (main).
  2. Build (البناء): تثبيت جميع الاعتماديات.
  3. Test (الاختبار): تشغيل الاختبارات الآلية (Unit Tests).
  4. Deploy (النشر): إذا نجحت كل الخطوات السابقة، قم بنشر الكود الجديد على الخادم.

مثال عملي: بناء Pipeline لتطبيق Node.js باستخدام GitHub Actions

في مستودع المشروع (repository) على GitHub، قمنا بإنشاء مجلد جديد باسم .github/workflows، وداخله ملف main.yml. هذا الملف هو الذي يصف خط الأنابيب الخاص بنا.

نصيحة من أبو عمر: ملفات YAML حساسة جداً للمسافات البادئة. استخدم مسافتين (spaces) وليس Tab، وتأكد من محاذاة كل سطر بشكل صحيح.

هذا هو محتوى ملف main.yml الذي يغطي مرحلتي البناء والاختبار (CI):


# اسم خط الأنابيب الذي سيظهر في GitHub
name: CI/CD Pipeline

# متى يتم تشغيل هذا الـ workflow
on:
  # عند الدفع إلى الفرع الرئيسي
  push:
    branches: [ "main" ]

# الوظائف (Jobs) التي سيتم تنفيذها
jobs:
  # وظيفة البناء والاختبار
  build-and-test:
    # نوع الخادم الافتراضي الذي ستعمل عليه الوظيفة
    runs-on: ubuntu-latest

    # الخطوات (Steps) التي سيتم تنفيذها بالترتيب
    steps:
      # 1. سحب الكود من المستودع
      - name: Checkout code
        uses: actions/checkout@v3

      # 2. إعداد بيئة Node.js بالإصدار المطلوب
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      # 3. تثبيت الاعتماديات (Dependencies)
      - name: Install Dependencies
        run: npm install

      # 4. تشغيل الاختبارات الآلية
      - name: Run Tests
        run: npm test

بمجرد إضافة هذا الملف وعمل push، أصبح GitHub يقوم تلقائياً بتشغيل هذه الخطوات مع كل تحديث على الفرع الرئيسي. إذا فشل أمر npm test، يتوقف خط الأنابيب ونتلقى إشعاراً فورياً. لقد كانت هذه أول خطوة نحو راحة البال!

الارتقاء بالمستوى: إضافة مرحلة النشر (CD)

الآن بعد أن تأكدنا من جودة الكود، حان وقت أتمتة النشر. قررنا استخدام SSH للاتصال بالخادم وتشغيل أوامر النشر. لكن هنا واجهنا سؤالاً مهماً: كيف نتعامل مع المعلومات الحساسة مثل مفتاح SSH وكلمات المرور؟

الحل هو استخدام GitHub Secrets. هي ميزة تتيح لك تخزين معلومات حساسة بشكل آمن و استخدامها داخل الـ workflow.

قمنا بإضافة وظيفة جديدة (job) اسمها deploy إلى ملف main.yml:


# ... (الكود السابق الخاص بـ build-and-test)

  # وظيفة النشر
  deploy:
    # هذه الوظيفة لن تبدأ إلا بعد نجاح وظيفة build-and-test
    needs: build-and-test
    # نوع الخادم
    runs-on: ubuntu-latest

    steps:
      - name: Deploy to server
        # نستخدم action جاهز للتعامل مع SSH
        uses: appleboy/ssh-action@master
        with:
          # معلومات الخادم التي قرأناها من GitHub Secrets
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          # الأوامر التي نريد تنفيذها على الخادم
          script: |
            cd /var/www/my-app
            git pull origin main
            npm install --production
            pm2 restart app

قمنا بالذهاب إلى Settings > Secrets and variables > Actions في مستودعنا على GitHub وأضفنا الـ Secrets التالية:

  • SERVER_HOST: عنوان IP الخاص بالخادم.
  • SERVER_USERNAME: اسم المستخدم على الخادم (مثلاً ubuntu).
  • SSH_PRIVATE_KEY: المفتاح الخاص للاتصال بالخادم بدون كلمة مرور.

والنتيجة؟ أصبح الآن أي تحديث ندفعه إلى الفرع الرئيسي، يتم اختباره تلقائياً، وإذا نجح، يتم نشره على الخادم خلال دقائق بدون أي تدخل بشري. انتهت ليالي الرعب!

نصائح من قلب المعركة (من خبرة أبو عمر)

خلال رحلتنا، تعلمنا دروساً قاسية لكنها مفيدة. إليكم بعض النصائح العملية:

  • ابدأ صغيراً ثم توسع: لا تحاول أتمتة كل شيء من اليوم الأول. ابدأ بخط أنابيب بسيط يقوم بالبناء والاختبار فقط. عندما تتقنه، أضف مرحلة النشر إلى بيئة تجريبية (Staging)، ثم أخيراً إلى البيئة الإنتاجية (Production).
  • الاختبارات هي شبكة الأمان: خط أنابيب CI/CD بدون اختبارات آلية جيدة هو مجرد طريقة سريعة لنشر الأخطاء. استثمر وقتاً في كتابة Unit Tests و Integration Tests.
  • اجعل الفشل سريعاً وواضحاً (Fail Fast): يجب أن يفشل خط الأنابيب عند أول علامة خطأ، ويرسل إشعاراً واضحاً للفريق (عبر Slack أو البريد الإلكتروني) يحدد المشكلة بالضبط.
  • توحيد البيئات باستخدام Docker: لحل مشكلة “شغال على جهازي” بشكل نهائي، الخطوة التالية هي استخدام Docker. عن طريق وضع تطبيقك داخل “حاوية” (Container)، تضمن أن البيئة التي يتم الاختبار فيها هي نفسها تماماً البيئة التي سيتم النشر عليها. هذا موضوع كبير يستحق مقالة خاصة به.

الخلاصة: من ليالٍ سوداء إلى إطلاقات بضغطة زر ☕

التحول إلى CI/CD لم يكن مجرد تغيير تقني، بل كان تغييراً في ثقافة الفريق بأكمله. انتقلنا من الخوف والتردد إلى الثقة والسرعة. أصبحت عمليات الإطلاق أحداثاً روتينية وغير مؤلمة، تحدث عدة مرات في اليوم أحياناً، بدلاً من مرة كل شهر. أصبحنا نركز على كتابة كود أفضل وبناء ميزات جديدة، بدلاً من إطفاء الحرائق.

إذا كنت أنت وفريقك لا تزالون تعانون من جحيم النشر اليدوي، فأتمنى أن تكون قصتي هذه حافزاً لكم للبدء. الرحلة قد تبدو صعبة في البداية، لكن صدقني، العائد يستحق كل دقيقة تقضيها في بناء أول خط أنابيب لك. ابدأ اليوم، ولو بخطوة صغيرة، وستشكرني لاحقاً. 🚀

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

نصائح برمجية

كان إطلاق الميزات الجديدة كابوساً: كيف أنقذتنا ‘أعلام الميزات’ (Feature Flags) من جحيم عمليات النشر عالية المخاطر؟

تذكرون تلك الليالي الطوال التي نقضيها في إصلاح الأخطاء بعد كل عملية نشر؟ في هذه المقالة، أشارككم قصة كيف حولت 'أعلام الميزات' (Feature Flags) عمليات...

10 مايو، 2026 قراءة المزيد
​معمارية البرمجيات

لماذا اتخذنا هذا القرار؟: كيف أنقذتنا ‘سجلات القرارات المعمارية’ (ADRs) من جحيم النسيان

أشارككم قصة حقيقية من قلب المعركة البرمجية، وكيف أن أداة بسيطة تُدعى "سجلات القرارات المعمارية" (ADRs) أصبحت طوق النجاة لفريقي. اكتشفوا كيف يمكن لتوثيق "لماذا"...

10 مايو، 2026 قراءة المزيد
خوارزميات

كان البحث في موقعنا كالبحث عن إبرة في كومة قش: كيف أنقذتنا ‘خوارزمية البحث الثنائي’ من جحيم تجربة المستخدم البطيئة؟

أتذكر جيدًا كيف كانت الشكاوى تنهال علينا بخصوص بطء البحث في موقعنا الجديد. في هذه المقالة، أشارككم قصة حقيقية حول كيف أنقذتنا العودة لأساسيات الخوارزميات،...

10 مايو، 2026 قراءة المزيد
تسويق رقمي

كنا نستهدف الجمهور الخطأ: كيف أنقذتنا ‘التجزئة التنبؤية بالذكاء الاصطناعي’ من جحيم هدر ميزانية الإعلانات؟

أشارككم قصة حقيقية من قلب المعركة، كيف انتقلنا من حرق ميزانية الإعلانات بلا طائل إلى تحقيق عائد استثماري مذهل. السر كان في التوقف عن مخاطبة...

10 مايو، 2026 قراءة المزيد
تجربة المستخدم والابداع البصري

كان كل فريق يغني على ليلاه: كيف أنقذ “نظام التصميم” مشروعنا من الفوضى البصرية؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف انتقلنا من فوضى الواجهات وتعدد الأزرار إلى نظام تصميم موحد أنقذ المشروع. هذه ليست مجرد مقالة تقنية،...

10 مايو، 2026 قراءة المزيد
برمجة وقواعد بيانات

كانت استعلاماتنا تزحف كالسلحفاة: كيف أنقذتنا ‘فهارس قواعد البيانات المركبة’ من جحيم الاستعلامات البطيئة؟

أشارككم قصة حقيقية من قلب المعركة البرمجية، كيف تحولنا من استعلامات SQL تستغرق دقائق إلى أخرى تتم في أجزاء من الثانية. اكتشفوا معنا سر "الفهارس...

10 مايو، 2026 قراءة المزيد
الشبكات والـ APIs

مفتاح عدم تكرار المعاملة (Idempotency Key): طوق النجاة الذي أنقذنا من فوضى الطلبات المكررة

في ليلة إطلاق محمومة، كادت نقرات المستخدمين المزدوجة أن تغرقنا في بحر من الفوضى والطلبات المكررة. أشارككم اليوم قصة كيف أنقذنا "مفتاح عدم تكرار المعاملة"...

10 مايو، 2026 قراءة المزيد
البودكاست