في دورة حياة تطوير البرمجيات الحديثة، يعد التوافق بين بيئات التطوير المحلية، والاختبار، والإنتاج أمراً بالغ الأهمية. بينما يوفر Docker محرك الحاويات، فإن Docker Compose هو المنسق الذي يحول تطبيقات الحاويات المتعددة إلى واقع. بالنسبة للمطورين من المستوى المتوسط والمتقدم، فإن الانتقال من سير العمل أحادي الحاوية إلى إعداد Compose قوي ومحدد ليس مجرد رفاهية، بل هو ضرورة للتوسع والتعاون.
سيأخذك هذا الدليل خلال عملية هندسة بيئة تطوير محلية تحاكي بيئة الإنتاج باستخدام Docker Compose، مع التركيز على أفضل الممارسات في تعريف الخدمات، وإدارة الأحجام (Volumes)، والشبكات.
فهم البنية المعمارية
قبل كتابة الكود، يجب علينا تعريف الخدمات. قد تتكون تطبيق ويب نموذجي من تطبيق واجهة أمامية (Frontend)، وواجهة برمجة تطبيقات خلفية (Backend API)، وقاعدة بيانات. يتيح لنا Docker Compose تعريف هذه التبعيات في ملف واحد docker-compose.yml. يضمن هذا النهج التصريحي أن أي مطور في الفريق يمكنه تشغيل المجموعة الكاملة من الخدمات بأمر واحد، مما يقضي على متلامة "إنه يعمل على جهازي".
تعريف خدماتك
لنقم ببناء سيناريو واقعي: واجهة برمجة تطبيقات Node.js متصلة بقاعدة بيانات PostgreSQL ومقدمة عبر واجهة أمامية React. سنحدد ثلاث خدمات مميزة في ملف التكوين الخاص بنا. تعمل كل خدمة كمخطط لحاوية، حيث تحدد الصورة، وسياق البناء، والمنافذ، والمتغيرات البيئية.
إليك تكوين docker-compose.yml قوي يتعامل مع هذه التبعيات:
version: '3.8'
services:
api:
build:
context: ./api
dockerfile: Dockerfile.dev
container_name: dev-api
ports:
- "4000:4000"
environment:
- DATABASE_URL=postgresql://user:password@db:5432/mydb
- NODE_ENV=development
volumes:
- ./api:/usr/src/app
- /usr/src/app/node_modules
depends_on:
- db
networks:
- dev-net
db:
image: postgres:15-alpine
container_name: dev-db
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- dev-net
web:
build:
context: ./web
dockerfile: Dockerfile.dev
container_name: dev-web
ports:
- "3000:3000"
volumes:
- ./web:/usr/src/app
- /usr/src/app/node_modules
depends_on:
- api
networks:
- dev-net
volumes:
pgdata:
networks:
dev-net:
driver: bridge
استراتيجيات التكوين الرئيسية
يتم استخدام أنماط حرجة متعددة في المثال أعلاه لضمان تجربة تطوير سلسة.
إدارة الأحجام (Volumes)
لاحظ استخدام الأحجام في خدمات api و web. من خلال تحميل دليل الكود المحلي (./api:/usr/src/app)، نتيح قدرات إعادة التحميل الفوري (Hot-reloading). عندما تحفظ ملفاً محلياً، يتم عكس التغييرات فوراً في الحاوية دون الحاجة إلى إعادة البناء. الحجم الثاني، - /usr/src/app/node_modules، هو حجم مسمى يخفي بشكل فعال مجلد node_modules داخل الحاوية. يمنع هذا مشكلات الأذونات المحلية ويضمن تشغيل npm install بشكل صحيح داخل سياق الحاوية.
عزل الشبكة
نحن نعرف شبكة جسر مخصصة (dev-net) بدلاً من الاعتماد على الشبكة الافتراضية. يوفر هذا عزلاً أفضل ويسمح للخدمات باكتشاف بعضها البعض عبر أسماء DNS (على سبيل المثال، يمكن للواجهة البرمجية الوصول إلى قاعدة البيانات ببساطة باستخدام db كاسم مضيف). يحاكي هذا سلوك شبكة الإنتاج بشكل أكثر دقة.
ترتيب التبعيات
يضمن استخدام depends_on بدء تشغيل قاعدة البيانات والواجهة البرمجية قبل العميل الويب. بينما لا ينتظر Compose بشكل افتراضي أن تكون قاعدة البيانات *جاهزة* لقبول الاتصالات، فإنه يضمن بدء تشغيل الحاويات بالترتيب الصحيح. من أجل جاهزية الإنتاج، عادةً ما تقوم بتنفيذ فحوصات الصحة (Health checks)، ولكن للتطوير المحلي، غالباً ما يكون هذا الترتيب البسيط كافياً.
تشغيل بيئتك
بمجرد وضع ملف docker-compose.yml، يكون تشغيل مجموعتك بسيطاً. افتح طرفية الأوامر (Terminal) في الدليل الجذري لمشروعك وقم بتشغيل:
docker-compose up --build
يضمن العلم --build إعادة بناء ملفات Dockerfiles الخاصة بك إذا قمت بإجراء تغييرات عليها. لتشغيل هذا في الخلفية (وضع منفصل)، أضف -d إلى الأمر.
الخاتمة
يعد إعداد Docker Compose للتطوير المحلي استثماراً يجني ثماره في إنتاجية الفريق وموثوقية النشر. من خلال تعريف البنية التحتية الخاصة بك ككود، فإنك تنشئ بيئة قابلة للتكرار تجريد التعقيدات الخاصة بنظام التشغيل. مع زيادة راحتك مع Compose، يمكنك توسيع هذا الإعداد ليشمل طبقات التخزين المؤقت مثل Redis، أو طوابير الرسائل مثل RabbitMQ، أو وكلاء العكس مثل Nginx، وكلها يتم إدارتها من ملف تكوين واحد.
ابدأ ببساطة، وكرر العملية كثيراً، ودع Docker Compose يتولى العمل الشاق حتى تتمكن من التركيز على كتابة برمجيات رائعة.