حول المحتوى:
شرح عملي لإنشاء ملف docker-compose لتشغيل قواعد بيانات، واجهات، وخدمات خلفية معًا، إدارة الشبكات، المتغيرات البيئية، وطرق التطوير المحلية السهلة.
في أغلب مشروعات الويب والتطبيقات الحديثة لن تتعامل مع خدمة واحدة فقط، بل ستحتاج إلى خلفية (Backend)، وقاعدة بيانات، وربما واجهة أمامية (Frontend)، وخدمات مساعدة أخرى مثل Redis أو Nginx. هنا يأتي دور Docker Compose متعدد الخدمات ليجعل إدارة كل هذه المكونات أسهل بكثير.
في هذا الشرح سنرى كيفية إنشاء ملف docker-compose.yml لتشغيل عدة خدمات معًا، مع توضيح:
إذا كنت جديدًا على Docker نفسه، يمكنك مراجعة مقال تعلم الدوكر: شرح أساسيات التعامل مع الحاويات ثم العودة إلى هذا الدليل التطبيقي.
Docker Compose هو أداة تتيح لك تعريف وتشغيل عدة حاويات Docker كمنظومة واحدة. من خلال ملف واحد docker-compose.yml يمكنك:
عندما نقول Docker Compose متعدد الخدمات فنحن نقصد مشروعًا يعتمد على أكثر من حاوية متصلة معًا عبر شبكة داخلية، بحيث يتواصل الـ Backend مع قاعدة البيانات، ويتصل الـ Frontend بالـ Backend، وهكذا.
ملف docker-compose.yml يعتمد على صيغة YAML، وأبسط هيكل لمشروع متعدد الخدمات يكون بالشكل التالي:
version: "3.9"
services:
backend:
image: my-backend-image
ports:
- "8000:8000"
frontend:
image: my-frontend-image
ports:
- "3000:3000"
db:
image: postgres:16
ports:
- "5432:5432"
هذا مثال مبسط، لكنه يوضح الفكرة:
لنأخذ مثالًا أكثر واقعية لمشروع مكون من:
افترض أن هيكل مشروعك كالتالي:
project/
backend/
Dockerfile
...
frontend/
Dockerfile
...
docker-compose.yml
.env
ملف docker-compose.yml يمكن أن يكون بالشكل التالي:
version: "3.9"
services:
db:
image: postgres:16
container_name: project_db
restart: always
environment:
POSTGRES_USER: app_user
POSTGRES_PASSWORD: app_password
POSTGRES_DB: app_db
ports:
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
networks:
- project_network
backend:
build: ./backend
container_name: project_backend
depends_on:
- db
environment:
DATABASE_URL: postgres://app_user:app_password@db:5432/app_db
ENV: development
ports:
- "8000:8000"
volumes:
- ./backend:/app
networks:
- project_network
frontend:
build: ./frontend
container_name: project_frontend
depends_on:
- backend
environment:
VITE_API_URL: http://localhost:8000
ports:
- "3000:3000"
volumes:
- ./frontend:/app
networks:
- project_network
volumes:
db_data:
networks:
project_network:
driver: bridge
في هذا المثال ركزنا على فكرة Docker Compose متعدد الخدمات وشرحنا كيف تتكامل المكونات:
من أهم مزايا Docker Compose متعدد الخدمات أنه ينشئ شبكة خاصة بالخدمات، بحيث:
في المثال السابق، الـ Backend يتصل بقاعدة البيانات عبر:
DATABASE_URL=postgres://app_user:app_password@db:5432/app_db
لاحظ استخدام اسم الخدمة db بدلًا من localhost، لأن الـ Backend داخل شبكة Docker لن يستطيع الوصول لقاعدة البيانات عبر localhost، بل عبر اسم الحاوية داخل الشبكة.
يمكنك أيضًا تعريف أكثر من شبكة لعزل بعض الخدمات عن الأخرى، مثل أن يكون لديك:
مثال مختصر:
networks:
internal_net:
internal: true
public_net:
driver: bridge
services:
db:
...
networks:
- internal_net
backend:
...
networks:
- internal_net
- public_net
frontend:
...
networks:
- public_net
هنا قاعدة البيانات db لا يمكن الوصول لها إلا من الخدمات الموجودة على internal_net، أي من الـ Backend فقط.
المتغيرات البيئية عنصر أساسي في أي مشروع يستخدم Docker Compose متعدد الخدمات لأنها:
بدلًا من كتابة القيم مباشرة في ملف docker-compose.yml، يمكن تخزينها في ملف .env في نفس مسار المشروع:
# ملف .env
POSTGRES_USER=app_user
POSTGRES_PASSWORD=app_password
POSTGRES_DB=app_db
BACKEND_PORT=8000
FRONTEND_PORT=3000
ثم في docker-compose.yml:
services:
db:
image: postgres:16
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- "5432:5432"
backend:
build: ./backend
ports:
- "${BACKEND_PORT}:8000"
frontend:
build: ./frontend
ports:
- "${FRONTEND_PORT}:3000"
بهذا الشكل يمكن تغيير المنافذ أو بيانات قاعدة البيانات بسهولة دون تغيير ملف Compose نفسه.
في سيناريو Docker Compose متعدد الخدمات ستحتاج غالبًا إلى نوعين من الـ Volumes:
في المثال السابق استخدمنا:
volumes:
db_data:
services:
db:
...
volumes:
- db_data:/var/lib/postgresql/data
هذا يضمن عدم فقدان البيانات في كل مرة تقوم فيها بتشغيل أو إيقاف الحاوية.
أثناء التطوير، لا تريد إعادة بناء الصورة في كل تغيير للكود. لذلك نستخدم:
services:
backend:
build: ./backend
volumes:
- ./backend:/app
بهذا الشكل، كل تغيير في ملفات مجلد backend/ على جهازك ينعكس مباشرة داخل الحاوية في المسار /app، مما يجعل التجربة أقرب ما تكون لتشغيل المشروع مباشرة على جهازك، مع الاستفادة من عزلة Docker.
من داخل مجلد المشروع الذي يحتوي على docker-compose.yml:
docker-compose up
هذا الأمر يقوم ببناء الصور (إن لزم) ثم تشغيل كل الخدمات. إذا أردت التشغيل في الخلفية (Detached Mode):
docker-compose up -d
لإيقاف كل الخدمات:
docker-compose down
إذا أردت أيضًا حذف الـ Volumes (مثل بيانات قاعدة البيانات):
docker-compose down -v
إذا قمت بتعديل Dockerfile أو إعداد بناء الخدمة:
docker-compose up -d --build
لمتابعة ما يحدث داخل الخدمات، يمكنك عرض السجلات:
docker-compose logs -f
أو لسervice معينة فقط:
docker-compose logs -f backend
حتى تستفيد بالكامل من Docker Compose متعدد الخدمات في بيئة التطوير المحلية، إليك بعض الممارسات المفيدة:
uvicorn --reload مع FastAPI لإعادة تشغيل الخادم عند تغيير الملفات. يمكنك الرجوع لمقال بناء RESTful APIs باستخدام FastAPI لمعرفة كيفية تشغيل واجهات برمجية في بيئة تطوير.docker-compose.dev.yml للإعدادات الخاصة بالتطوير.docker-compose.prod.yml للإعدادات الخاصة بالإنتاج.docker-compose -f docker-compose.dev.yml up إذا كنت تعمل بمشروعات Python، وخاصة مع FastAPI أو Django، فإن الجمع بين البرمجة غير المتزامنة وDocker يناسب المشروعات ذات الحمل العالي. يمكنك قراءة مقال البرمجة غير المتزامنة في بايثون: تحسين الأداء باستخدام async و await ثم تطبيق هذا التصور داخل حاوية الـ Backend في Docker.
مثال بسيط لخدمة Backend FastAPI داخل Dockerfile:
# backend/Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
ثم تشغيلها مع قاعدة بيانات وFrontend كما رأينا في ملف docker-compose.yml السابق.
api_backend بدلاً من app لتسهيل الصيانة.postgres:16 بدلاً من postgres:latest لتجنب المفاجآت عند التحديث.استخدام Docker Compose متعدد الخدمات يسهّل بشكل كبير إدارة مشروعات تحتوي على:
من خلال ملف واحد docker-compose.yml يمكنك:
مع القليل من الممارسة ستتمكن من تصميم ملفات Docker Compose متعدد الخدمات تناسب أي مشروع تقريبًا، من تطبيقات ويب بسيطة إلى منظومات معقدة تضم عشرات الخدمات.
شرح عملي لإنشاء ملف docker-compose لتشغيل قواعد بيانات، واجهات، وخدمات خلفية معًا، إدارة الشبكات، المتغيرات البيئية، وطرق التطوير المحلية السهلة.
مساحة اعلانية