مشروع مصغر: أتمتة تشغيل بيئة تطوير (React + Node + DB) بملف YAML واحد

دقائق القراءة: 5

مشروع مصغر: أتمتة تشغيل بيئة تطوير (React + Node + DB) بملف YAML واحد

عندما يبدأ الفريق ببناء واجهة React مع خادم Node.js وقاعدة بيانات، تظهر فوراً مشكلة اختلاف البيئات بين المطورين. جهاز يعمل عليه PostgreSQL محلياً، وآخر يستخدم منفذاً مختلفاً، وثالث يثبت نسخة متباينة من Node. هنا تتحول الأتمتة من رفاهية إلى ضرورة هندسية.

الحل العملي هو تجميع كامل بيئة التطوير داخل ملف YAML واحد باستخدام Docker Compose. إذا كنت تريد فهماً تأسيسياً أوسع، فارجع إلى مقال ما هو Docker Compose؟ ولماذا نحتاجه لتشغيل المشاريع المعقدة؟، لأنه يشرح فلسفة تشغيل الخدمات المتعددة كمنظومة واحدة.

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

لماذا هذا النمط مهم في مسار ما هو DevOps؟ ولماذا تدفع الشركات ثروات لمهندسي الأتمتة السحابية؟؟

فلسفة DevOps لا تعني فقط نشر الإنتاج بسرعة، بل تعني أيضاً تقليل الاحتكاك في بيئة التطوير اليومية. عندما تصبح بيئة التشغيل معرفة ككود داخل ملف docker-compose.yml، فإن الفريق يزيل قدراً كبيراً من الأخطاء البشرية والتباين غير المقصود.

هذا النهج يعالج مباشرة المشكلة الشهيرة التي ناقشها مقال مشكلة “الكود يعمل على جهازي فقط” وكيف يحلها Docker نهائياً؟. بدلاً من الاعتماد على تثبيتات يدوية طويلة، يصبح ملف التكوين هو المرجع الوحيد للحقيقة Single Source of Truth.

المعمارية المقترحة للمشروع

سنفترض وجود بنية ملفات بسيطة داخل مستودع واحد Monorepo:

  • مجلد frontend لتطبيق React.
  • مجلد backend لتطبيق Node.js/Express.
  • خدمة قاعدة بيانات PostgreSQL جاهزة من صورة رسمية.

كل خدمة ستعمل داخل حاوية مستقلة، لكنها ستشترك في شبكة داخلية واحدة. هذا المبدأ تم شرحه تقنياً في مقال إدارة الشبكات (Docker Networks): كيف تتحدث الحاويات مع بعضها بأمان؟، وهو ضروري لفهم كيف يصل backend إلى قاعدة البيانات عبر اسم الخدمة بدلاً من localhost.

ملف docker-compose.yml الكامل

الملف التالي ينسق عملية البناء، ربط المنافذ، التخزين الدائم، وترتيب الإقلاع المبدئي. وهو امتداد عملي لما تم تناوله في مقال كتابة أول ملف docker-compose.yml خطوة بخطوة.

version: "3.9"

services:
  frontend:
    build:
      context: ./frontend
    container_name: react_frontend
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - CHOKIDAR_USEPOLLING=true
      - REACT_APP_API_URL=http://localhost:5000
    depends_on:
      - backend
    command: npm start

  backend:
    build:
      context: ./backend
    container_name: node_backend
    ports:
      - "5000:5000"
    volumes:
      - ./backend:/app
      - /app/node_modules
    environment:
      - PORT=5000
      - DB_HOST=db
      - DB_PORT=5432
      - DB_NAME=appdb
      - DB_USER=appuser
      - DB_PASSWORD=secret123
    depends_on:
      - db
    command: npm run dev

  db:
    image: postgres:15-alpine
    container_name: postgres_db
    restart: unless-stopped
    ports:
      - "5432:5432"
    environment:
      - POSTGRES_DB=appdb
      - POSTGRES_USER=appuser
      - POSTGRES_PASSWORD=secret123
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

كيف يقرأ Compose هذا الملف؟

1) البناء المحلي للخدمات التطبيقية

الخدمتان frontend وbackend تُبنيان من مجلدين محليين. هذا يعني أن لكل جزء ملف Dockerfile خاصاً به. إذا كنت لم تبنِ صوراً مخصصة من قبل، فمقال كتابة أول Dockerfile: تحويل سكربت Python إلى صورة (Image) معزولة يقدم المفهوم الأساسي بشكل واضح.

2) الربط بين الخدمات بالأسماء

لاحظ أن قيمة DB_HOST=db لا تشير إلى عنوان خارجي، بل إلى اسم خدمة قاعدة البيانات داخل الشبكة الداخلية. هذه من أهم مزايا service discovery في Docker Compose.

3) التخزين الدائم لقاعدة البيانات

المجلد المنطقي postgres_data يضمن بقاء البيانات بعد إعادة تشغيل الحاوية. هذا عنصر حاسم، خصوصاً في المشاريع التطويرية التي تتضمن بيانات اختبار أو مخططات schema. ويمكن التوسع فيه عبر ما ورد في مقال التخزين الدائم (Docker Volumes): كيف نمنع ضياع قواعد البيانات عند توقف الحاوية؟.

4) المتغيرات البيئية

استخدام Environment Variables يزيل القيم الثابتة من الكود نفسه، ويجعل الترحيل بين بيئات development وstaging وproduction أكثر انضباطاً. ويمكنك مراجعة مقال تمرير المتغيرات البيئية (Environment Variables) للحاويات بشكل آمن لفهم الممارسات الأفضل.

لا تضع كلمات المرور الحقيقية أو مفاتيح API داخل ملف docker-compose.yml إذا كان المستودع مشتركاً أو عاماً. الأفضل استخدام ملف .env محلي أو أنظمة أسرار مخصصة عند الانتقال إلى بيئات أعلى.

أوامر التشغيل والفحص

بعد تجهيز الملف، يمكن تشغيل البيئة كاملة بهذه الأوامر:

docker compose up --build

docker compose ps

docker compose logs -f backend

docker compose down

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

أفضل الممارسات الهندسية لهذا المشروع

افصل بيئة التطوير عن الإنتاج

ملف التطوير عادة يستخدم bind mounts، وأوامر مثل npm start أو npm run dev. أما الإنتاج فيعتمد غالباً على صور نهائية أصغر، بدون أدوات المراقبة الحية hot reload.

استخدم صوراً خفيفة

الصورة postgres:15-alpine مثال جيد على تقليل الحجم الزائد. الفكرة نفسها مهمة عند بناء صور Node، وقد تناولها مقال تقليل حجم الحاويات: بناء صور دوكر خفيفة جداً وسريعة (Alpine Linux).

تحقق من جاهزية قاعدة البيانات

الاعتماد على depends_on وحده لا يضمن أن قاعدة البيانات أصبحت جاهزة لقبول الاتصالات. الأفضل إضافة healthcheck أو منطق إعادة المحاولة داخل تطبيق backend.

من أخطر الأخطاء التشغيلية أن يبدأ خادم Node.js بالاعتماد على قاعدة بيانات غير جاهزة ثم يتوقف نهائياً. طبّق آلية retry with backoff أو فحص صحة صريح لتجنب أعطال البداية المتقطعة.

كيف يخدم هذا الملف مستقبلاً في CI/CD؟

رغم أن الهدف هنا هو بيئة تطوير محلية، فإن نفس المنطق قابل لإعادة الاستخدام داخل خطوط CI. يمكن استخدام الملف لتشغيل بيئة اختبار مؤقتة أثناء تنفيذ اختبارات التكامل، بحيث يقل الفرق بين بيئة المطور وبيئة التحقق الآلي.

هذا يرفع موثوقية الأنابيب ويجعل أي انتقال لاحق إلى Jenkins أو GitHub Actions أكثر سلاسة، لأن وصف الخدمات والبورتات والاعتماديات موجود مسبقاً ككود قابل للتنفيذ والتكرار.

الخلاصة

ملف YAML واحد قد يبدو تفصيلاً صغيراً، لكنه في الحقيقة طبقة تنظيمية قوية جداً. فهو يوحد تشغيل React وNode.js وPostgreSQL ضمن بيئة ثابتة، قابلة للتكرار، وسهلة الانضمام لأي عضو جديد في الفريق.

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

2 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *