Docker: الممارسة المتكاملة للمرحلة الثالثة
آخر تحديث: 2026-08-26
تجميع مفاهيم المرحلة الثالثة — بناء خلفية تجارة إلكترونية قائمة على الخدمات المصغرة.
1. ما ستتعلمه
- تصميم هيكل مشروع Compose متعدد الطبقات
- اكتشاف الخدمات وموازنة الحمل
- استراتيجيات استمرارية البيانات
- إدارة التكوين متعدد البيئات
- فحوصات الصحة والشفاء الذاتي
2. القصة وراء خلفية منصة تجارة إلكترونية
(1) نقطة الألم: 6 خدمات يجب بدؤها يدويًا
يحتاج تشارلي إلى نشر ست خدمات لخلفية منصة التجارة الإلكترونية: واجهة React أمامية، وكيل Nginx عكسي، Go API، PostgreSQL، ذاكرة تخزين Redis المؤقتة، وطابور رسائل RabbitMQ. استخدام docker run يدويًا يتطلب تذكر أكثر من 30 معاملًا، وبما أن ترتيب البدء صارم، فإن معدل الخطأ مرتفع للغاية.
(2) حل للتكوين بنقرة واحدة
عالج تشارلي كل شيء بملف docker-compose.yml واحد.
BASH
docker compose up -d
(3) الفوائد: بدء 6 خدمات بنقرة واحدة
اختُزل من 30 دقيقة يدويًا إلى docker compose up -d في 30 ثانية. يمكن للموظفين الجدد تشغيل الخلفية بالكامل في 5 دقائق.
3. تصميم بنية الخدمات المصغرة
(1) نظرة عامة على البنية
graph TB
USER["المتصفح"] --> NGX["Nginx<br/>:80 وكيل عكسي"]
NGX -->|"api/"| API1["Go API #1<br/>:8080"]
NGX -->|"api/"| API2["Go API #2<br/>:8080"]
NGX -->|"api/"| API3["Go API #3<br/>:8080"]
NGX -->|"/"| REACT["React SPA<br/>ملفات ثابتة"]
API1 --> PG["PostgreSQL<br/>:5432"]
API2 --> PG
API3 --> PG
API1 --> REDIS["Redis<br/>:6379"]
API2 --> REDIS
API3 --> MQ["RabbitMQ<br/>:5672"]
(2) قائمة الخدمات
| الخدمة | الصورة | المنفذ | الشبكة | التبعيات |
|---|---|---|---|---|
| Nginx | nginx:1.25-alpine | 80→80 | frontend, backend | api (healthy) |
| React | مستضافة ذاتيًا (متعددة المراحل) | - | frontend | - |
| Go API | بناء ذاتي (متعدد المراحل) | 8080 | backend, db-net, cache-net | postgres (healthy), redis |
| PostgreSQL | postgres:15-alpine | 5432 | db-net | - |
| Redis | redis:7-alpine | 6379 | cache-net | - |
| RabbitMQ | rabbitmq:3-management | 5672, 15672 | backend | - |
4. كتابة ملفات Compose
▶ مثال: كتابة ملف compose كامل (الصعوبة: ⭐⭐⭐)
YAML
# ============================================
# docker-compose.yml - خدمات التجارة الإلكترونية المصغرة
# ============================================
services:
# ---------- الواجهة الأمامية ----------
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
- react-build:/usr/share/nginx/html:ro
depends_on:
api:
condition: service_healthy
restart: unless-stopped
networks:
- frontend
- backend
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 5s
react:
build:
context: ./frontend
dockerfile: Dockerfile
volumes:
- react-build:/app/build
networks:
- frontend
# ---------- الخلفية ----------
api:
build:
context: ./api
dockerfile: Dockerfile
environment:
DATABASE_URL: postgresql://appuser:${DB_PASSWORD:-secret}@postgres:5432/${DB_NAME:-ecommerce}
REDIS_URL: redis://redis:6379
RABBITMQ_URL: amqp://guest:guest@rabbitmq:5672
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
deploy:
replicas: 3
resources:
limits:
cpus: "1.0"
memory: 512M
networks:
- backend
- db-net
- cache-net
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:8080/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 10s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
# ---------- مخازن البيانات ----------
postgres:
image: postgres:15-alpine
environment:
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
POSTGRES_DB: ${DB_NAME:-ecommerce}
volumes:
- pg-data:/var/lib/postgresql/data
restart: unless-stopped
networks:
- db-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
restart: unless-stopped
networks:
- cache-net
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
rabbitmq:
image: rabbitmq:3-management-alpine
ports:
- "15672:15672" # واجهة الإدارة
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
volumes:
- mq-data:/var/lib/rabbitmq
restart: unless-stopped
networks:
- backend
# ---------- وحدات التخزين ----------
volumes:
pg-data:
redis-data:
mq-data:
react-build:
# ---------- الشبكات ----------
networks:
frontend:
backend:
db-net:
internal: true # لا وصول خارجي
cache-net:
internal: true
(1) إعدادات Nginx (موازنة الحمل)
TEXT
📖 للعرض فقط
# nginx.conf
upstream api_backend {
server api:8080; # DNS round-robin من Docker لـ 3 نسخ
}
server {
listen 80;
server_name localhost;
# الملفات الثابتة (React SPA)
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
# وكيل API
location /api/ {
proxy_pass http://api_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
5. تكوين متعدد البيئات
▶ مثال: التجاوز في بيئة التطوير (الصعوبة: ⭐⭐)
YAML
# docker-compose.dev.yml
services:
api:
build:
context: ./api
dockerfile: Dockerfile.dev
volumes:
- ./api/src:/app/src # إعادة تحميل تلقائية
environment:
GO_ENV: development
deploy:
replicas: 1 # نسخة واحدة للتصحيح
# للتطوير فقط: واجهة إدارة قاعدة البيانات
adminer:
image: adminer
ports:
- "8081:8080"
profiles: ["dev"]
networks:
- db-net
6. فحوصات الصحة والشفاء الذاتي
▶ مثال: إضافة فحوصات الصحة لجميع الخدمات (الصعوبة: ⭐⭐)
YAML
# تكوين فحص الصحة لكل خدمة
services:
api:
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 20s
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
interval: 5s
timeout: 3s
retries: 5
redis:
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 3
المخرجات:
NAME STATUS ecommerce-api-1 Up 2 minutes (healthy) ecommerce-postgres Up 2 minutes (healthy) ecommerce-redis-1 Up 2 minutes (healthy)
7. التحقق من النشر
(1) قائمة التحقق
| عنصر الاختبار | الأمر | النتيجة المتوقعة |
|---|---|---|
| جميع الخدمات قيد التشغيل | docker compose ps |
6+ خدمات نشطة |
| Nginx سليم | curl http://localhost |
200 OK |
| صحة API | curl http://localhost/api/health |
{"status":"ok"} |
| عدد نسخ API | docker compose ps api |
3 حاويات |
| اتصال Redis | docker compose exec redis redis-cli ping |
PONG |
| اتصال PostgreSQL | docker compose exec postgres pg_isready |
accepting connections |
| عزل قاعدة البيانات | Ping إلى Postgres من حاوية Nginx | فشل (شبكة داخلية) |
8. مثال كامل: نشر منصة تجارة إلكترونية بنقرة واحدة
BASH
# ============================================
# شرح كامل: خدمات التجارة الإلكترونية المصغرة
# ============================================
# 1. بناء وبدء جميع الخدمات
docker compose up -d --build
# 2. التحقق من تشغيل جميع الخدمات
docker compose ps
# 3. التحقق من حالة الصحة
docker compose ps --format "table {{.Name}}\t{{.Status}}"
# 4. اختبار API
curl -s http://localhost/api/health | python3 -m json.tool
# 5. التحقق من موازنة الحمل (طلبات متعددة لنسخ مختلفة)
for i in $(seq 1 6); do
curl -s http://localhost/api/health | jq -r '.hostname'
done
# 6. التحقق من اتصال قاعدة البيانات من API
docker compose exec api wget -qO- http://localhost:8080/health
# 7. الوصول إلى واجهة إدارة RabbitMQ
# افتح http://localhost:15672 (guest/guest)
# 8. عرض السجلات
docker compose logs -f api
# 9. توسيع API إلى 5 نسخ
docker compose up -d --scale api=5
# 10. التنظيف
docker compose down
docker compose down -v # يزيل أيضًا وحدات تخزين البيانات
❓ أسئلة شائعة
س هل يجب استخدام أسماء الشبكة المستعارة أم أسماء الخدمات للتواصل بين الخدمات؟
ج في Compose، يوصى باستخدام أسماء الخدمات (مثل
postgres و redis). يسجل Compose تلقائيًا سجلات DNS لكل خدمة، ويعمل اسم الخدمة كاسم مضيف. تُستخدم الأسماء المستعارة للشبكة في سيناريوهات تتطلب فيها نفس الخدمة أسماء مختلفة عبر شبكات مختلفة.س كيف يتم ضمان ترتيب بدء التبعيات؟
ج
depends_on + condition: service_healthy. لن تبدأ API إلا بعد اجتياز فحص الصحة لـ postgres. ملاحظة: depends_on: [db] (الشرط الافتراضي: service_started) ينتظر فقط بدء الحاوية؛ لا ينتظر حتى تكون الخدمة جاهزة.س كيف تتعامل API متعددة النسخ مع موازنة الحمل؟
ج DNS round-robin المدمج في Docker + Nginx upstream. جميع حاويات API الثلاث مسجلة باسم DNS
api، وسيقوم upstream api_backend { server api:8080; } في Nginx بتوزيع الطلبات بالدوران. لاستراتيجيات موازنة حمل أكثر تعقيدًا، يمكنك استخدام HAProxy.س كيف أقوم بتكوين نسخ رئيسي-تابع لقاعدة البيانات؟
ج لمثيل Compose أحادي العقدة، يمكنك استخدام حاويات PostgreSQL متعددة مع تكوين نسخ رئيسي-تابع. ومع ذلك، للنسخ الرئيسي-التابع على مستوى الإنتاج، نوصي باستخدام قاعدة بيانات مُدارة (AWS RDS / مزود سحابي) أو أدوات مخصصة (Patroni/Stolon). مثيل PostgreSQL في هذا الدرس هو مثيل أحادي العقدة.
س كيف أنفذ إعادة التحميل التلقائية؟
ج في بيئة التطوير، قم بتركيب الكود المصدري باستخدام وحدة تخزين (مثال:
-v ./api/src:/app/src) واستخدم أداة إعادة تحميل تلقائية (air لـ Go، nodemon لـ Node، flask --debug لـ Python). في بيئة الإنتاج، لا تقم بتركيب الكود المصدري؛ بدلاً من ذلك، طبق تغييرات التكوين عبر متغيرات البيئة وأعد التشغيل باستخدام docker compose up -d.📖 ملخص
- بنية Compose للخدمات المصغرة: عزل شبكة ثلاثي الطبقات — الواجهة الأمامية ← الخلفية ← مخازن البيانات
internal: trueمنع الوصول الخارجي المباشر إلى قاعدة البيانات/ذاكرة التخزين المؤقت عبر الشبكة- موازنة الحمل باستخدام نسخ API متعددة و Nginx upstream
depends_on: { condition: service_healthy }يضمن أن التبعيات جاهزة فعليًا- تدوير السجلات
logging: { options: { max-size: "10m" } }لمنع امتلاء القرص - إدارة الاختلافات في ملفات dev/prod Override بين البيئات
📝 تمارين
- تمرين أساسي (الصعوبة: ⭐): صمم بنية متعددة الخدمات لنظام مدونة (Nginx + API + DB + Cache)، واكتب ملف
docker-compose.yml، وابدأ النظام. - تمرين متقدم (الصعوبة: ⭐⭐): عدل API بنسخ متعددة (replicas: 3) وموازنة حمل Nginx، وتحقق من توزيع الطلبات عبر نسخ مختلفة.
- تحدٍ (الصعوبة: ⭐⭐⭐): أضف مجموعتين من ملفات التجاوز لـ dev و prod (dev: أضف Adminer وإعادة تحميل تلقائية؛ prod: أضف حدود موارد وتدوير سجلات)، ثم ابدأ كل بيئة للتحقق من الاختلافات.