Docker: تدريب عملي شامل

آخر تحديث: 2026-08-26

هذا هو المشروع النهائي لهذه الدورة — يجمع المعرفة من جميع الدروس الـ 23 لنشر microservice كامل من الصفر إلى بيئة الإنتاج.

1. ما ستتعلمه



2. قصة تسليم في 3 أيام

(1) التحدي: الانتقال من المحلي إلى الإنتاج في 3 أيام

كُلف تشارلي بمهمة: نشر منصة تجارة إلكترونية من التطوير المحلي إلى بيئة الإنتاج في ثلاثة أيام. تتكون البنية من واجهة React أمامية، Go API، PostgreSQL، Redis، و RabbitMQ — خمس خدمات وصفر عمليات آلية.

(2) حل لأدوات Docker الشاملة

استخدم تشارلي أدوات Docker الشاملة لإكمال المشروع في يومين: كتابة Dockerfile ← التنسيق بـ Compose ← نشر CI/CD آلي ← المراقبة والتنبيهات.

(3) الفائدة: اكتمل وتم التسليم في يومين

من النشر اليدوي إلى الأتمتة الكاملة، أكملنا تصميم البنية، التحويل إلى حاويات، التنسيق، CI/CD، والمراقبة في يومين فقط — هذه هي قيمة إتقان مهارات Docker الشاملة.



3. تصميم البنية الشاملة

(1) نظرة عامة على البنية

100%
graph TB
    USER["المتصفح"] --> ING["Nginx<br/>:80<br/>React SPA + وكيل API"]
    ING -->|"api/"| API1["Go API #1<br/>:8080"]
    ING -->|"api/"| API2["Go API #2<br/>:8080"]
    ING -->|"api/"| API3["Go API #3<br/>:8080"]
    API1 --> PG["PostgreSQL<br/>:5432<br/>قاعدة البيانات الرئيسية"]
    API2 --> PG
    API3 --> PG
    API1 --> REDIS["Redis<br/>:6379<br/>ذاكرة تخزين مؤقت"]
    API2 --> REDIS
    API3 --> MQ["RabbitMQ<br/>:5672<br/>طابور الرسائل"]
    MQ --> WRK["Worker<br/>مهام خلفية"]
    PROM["Prometheus<br/>:9090<br/>مقاييس"] --> GRAF["Grafana<br/>:3000<br/>لوحات المعلومات"]
    PROM --> API1
    PROM --> PG
    PROM --> REDIS

(2) قائمة الخدمات

الخدمة مجموعة التقنيات الصور المنافذ
Nginx وكيل عكسي + ملفات ثابتة مستضافة ذاتيًا (متعددة المراحل) 80
Go API REST API مستضافة ذاتيًا (متعددة المراحل) 8080
PostgreSQL قاعدة بيانات علائقية postgres:15-alpine 5432
Redis ذاكرة تخزين مؤقت + جلسات redis:7-alpine 6379
RabbitMQ طابور الرسائل rabbitmq:3-management 5672/15672
Worker معالجة المهام الخلفية مستضافة ذاتيًا (نفس صورة API) -
Prometheus جمع المقاييس prom/prometheus 9090
Grafana لوحة معلومات مرئية grafana/grafana 3000


4. Dockerfile الواجهة الأمامية (React + Nginx)

▶ مثال: بناء متعدد المراحل لـ Dockerfile الواجهة الأمامية (الصعوبة: ⭐⭐⭐)

DOCKERFILE
# ============================================
# المرحلة 1: بناء تطبيق React
# ============================================
FROM node:20-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# ============================================
# المرحلة 2: الخدمة باستخدام Nginx
# ============================================
FROM nginx:1.25-alpine

# نسخ ملفات البناء
COPY --from=builder /app/dist /usr/share/nginx/html

# نسخ تكوين Nginx لتوجيه SPA
COPY nginx.conf /etc/nginx/conf.d/default.conf

# الأمان: مستخدم غير root
RUN chown -R nginx:nginx /usr/share/nginx/html && \
    chown -R nginx:nginx /var/cache/nginx && \
    chown -R nginx:nginx /var/log/nginx

EXPOSE 80
HEALTHCHECK --interval=30s --timeout=5s \
  CMD wget -qO- http://localhost/ || exit 1

CMD ["nginx", "-g", "daemon off;"]


5. Dockerfile الخلفية (Go متعدد المراحل)

▶ مثال: بناء متعدد المراحل لـ Dockerfile الخلفية (الصعوبة: ⭐⭐⭐)

DOCKERFILE
# ============================================
# المرحلة 1: ترجمة برنامج Go الثنائي
# ============================================
FROM golang:1.22-alpine AS builder

RUN apk add --no-cache git

WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /app/server

# ============================================
# المرحلة 2: وقت تشغيل أدنى
# ============================================
FROM alpine:3.19

RUN apk --no-cache add ca-certificates tzdata curl && \
    adduser -D -u 1000 appuser

WORKDIR /app
COPY --from=builder /app/server .

RUN chown -R appuser:appuser /app
USER appuser

EXPOSE 8080

HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

CMD ["/app/server"]


6. تنسيق Docker Compose

▶ مثال: docker-compose.prod.yml كامل (الصعوبة: ⭐⭐⭐)

YAML
# ============================================
# docker-compose.prod.yml - Full stack
# ============================================
services:
  nginx:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    ports:
      - "80:80"
    depends_on:
      api:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - frontend
      - backend
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    environment:
      DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/${DB_NAME}
      REDIS_URL: redis://redis:6379
      RABBITMQ_URL: amqp://guest:${MQ_PASSWORD}@rabbitmq:5672
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - backend
      - db-net
      - cache-net
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 15s
      timeout: 5s
      retries: 3
      start_period: 10s
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

  worker:
    build:
      context: ./api
      dockerfile: Dockerfile
    command: ["/app/server", "worker"]
    environment:
      DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/${DB_NAME}
      RABBITMQ_URL: amqp://guest:${MQ_PASSWORD}@rabbitmq:5672
    depends_on:
      postgres:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - backend
      - db-net

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U appuser"]
      interval: 5s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - db-net

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 5s
    restart: unless-stopped
    networks:
      - cache-net

  rabbitmq:
    image: rabbitmq:3-management-alpine
    environment:
      RABBITMQ_DEFAULT_PASS: ${MQ_PASSWORD}
    ports:
      - "15672:15672"
    volumes:
      - mq-data:/var/lib/rabbitmq
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
      interval: 15s
      timeout: 10s
    restart: unless-stopped
    networks:
      - backend

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    ports:
      - "9090:9090"
    restart: unless-stopped
    networks:
      - backend
      - db-net
      - cache-net

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD}
    volumes:
      - grafana-data:/var/lib/grafana
    depends_on:
      - prometheus
    restart: unless-stopped
    networks:
      - backend

volumes:
  pg-data:
  redis-data:
  mq-data:
  prometheus-data:
  grafana-data:

networks:
  frontend:
  backend:
  db-net:
    internal: true
  cache-net:
    internal: true


7. تكوين CI/CD

(1) مسار GitHub Actions الكامل

YAML
# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ${{ secrets.REGISTRY }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_PASS }}

      - name: Build and push API
        uses: docker/build-push-action@v5
        with:
          context: ./api
          push: true
          tags: ${{ secrets.REGISTRY }}/api:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Build and push Frontend
        uses: docker/build-push-action@v5
        with:
          context: ./frontend
          push: true
          tags: ${{ secrets.REGISTRY }}/frontend:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Deploy to production
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /opt/ecommerce
            export API_TAG=${{ github.sha }}
            export FRONTEND_TAG=${{ github.sha }}
            docker compose -f docker-compose.prod.yml pull
            docker compose -f docker-compose.prod.yml up -d --remove-orphans
            docker image prune -f


8. تكوين المراقبة

(1) تكوين Prometheus

YAML
# monitoring/prometheus.yml
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'api'
    static_configs:
      - targets: ['api:8080']
    metrics_path: /metrics

  - job_name: 'postgres'
    static_configs:
      - targets: ['postgres-exporter:9187']

  - job_name: 'redis'
    static_configs:
      - targets: ['redis-exporter:9121']

  - job_name: 'rabbitmq'
    static_configs:
      - targets: ['rabbitmq:15692']


9. النشر والتحقق

(1) قائمة التحقق من النشر

الخطوة الإجراء التحقق
1 docker compose -f docker-compose.prod.yml up -d --build docker compose ps الكل Up
2 زيارة http://localhost صفحة React تظهر بشكل صحيح
3 curl http://localhost/api/health {"status":"ok"}
4 زيارة http://localhost:3000 صفحة تسجيل الدخول Grafana
5 زيارة http://localhost:15672 صفحة إدارة RabbitMQ
6 docker compose logs api لا أخطاء في سجلات API

(2) جدول المقارنة: Bare Metal مقابل Docker مقابل K8s

البُعد النشر على المعدن مباشرة Docker Compose Kubernetes
وقت النشر 1–2 يوم 30 دقيقة 1–2 يوم (الإعداد الأولي)
قابلية التكرار
التوسع التلقائي ✅ HPA
الشفاء الذاتي سياسة إعادة التشغيل ✅ إعادة بناء تلقائية
تحديثات بدون توقف صعب إعادة تشغيل Compose ✅ تحديثات متدرجة
المراقبة يدوي Prometheus+Grafana مدمجة + Prometheus
التعقيد منخفض متوسط عالٍ


10. مثال كامل: نشر Full-Stack بنقرة واحدة

BASH
# ============================================
# شرح كامل: نشر Full-Stack
# ============================================

# 1. إنشاء ملف .env (لا تقم أبدًا بـ commit لهذا الملف)
cat > .env << 'EOF'
DB_PASSWORD=secure_db_pass_2024
DB_NAME=ecommerce
REDIS_PASSWORD=secure_redis_pass
MQ_PASSWORD=secure_mq_pass
GRAFANA_PASSWORD=admin123
EOF

# 2. بناء وبدء جميع الخدمات
docker compose -f docker-compose.prod.yml up -d --build

# 3. انتظار تهيئة الخدمات
sleep 30

# 4. التحقق من جميع الخدمات
docker compose -f docker-compose.prod.yml ps
echo "=== Health Checks ==="
docker compose -f docker-compose.prod.yml ps --format "table {{.Name}}\t{{.Status}}"

# 5. اختبار API
curl -s http://localhost/api/health

# 6. التحقق من اتصال قاعدة البيانات
docker compose -f docker-compose.prod.yml exec postgres pg_isready -U appuser

# 7. الوصول إلى المراقبة
echo "Grafana: http://localhost:3000 (admin/${GRAFANA_PASSWORD})"
echo "RabbitMQ: http://localhost:15672 (guest/${MQ_PASSWORD})"
echo "Prometheus: http://localhost:9090"

# 8. عرض السجلات المجمعة
docker compose -f docker-compose.prod.yml logs --tail 50 api

# 9. توسيع API إذا لزم الأمر
docker compose -f docker-compose.prod.yml up -d --scale api=5

# 10. التنظيف
docker compose -f docker-compose.prod.yml down

❓ أسئلة شائعة

س ما مدى تعقيد microservices مقارنة بالبنية المتجانسة؟
ج يزداد التعقيد التشغيلي بشكل كبير — تكوين الشبكة، اكتشاف الخدمات، تجميع السجلات، والتتبع الموزع كلها تمثل تحديات جديدة. ومع ذلك، تشمل الفوائد النشر المستقل، التوسع المستقل، وعزل الأعطال. توصية: الفرق الصغيرة (<5 أشخاص) يجب أن تستخدم بنية متجانسة معيارية، بينما الفرق الأكبر يجب أن تستخدم microservices. لا تتبنى microservices لمجرد التبني.
س كيف تنفذ ترحيل قاعدة البيانات في CI/CD؟
ج أضف خطوات الترحيل قبل خطوات النشر: ① بناء صورة الترحيل؛ ② docker run --rm migrate:latest alembic upgrade head؛ ③ نشر الإصدار الجديد. نقطة رئيسية: يجب أن تكون الترحيلات متوافقة مع الإصدارات السابقة — يجب أن يدعم الكود الجديد هيكلي الجدول القديم والجديد.
س كيف يمكن دمج سجلات الخدمات المتعددة؟
ج هناك ثلاث طرق: ① ELK Stack (Elasticsearch + Logstash + Kibana) — المعيار الصناعي؛ ② Loki + Grafana (خفيف الوزن، موصى به للبيئات السحابية الأصلية)؛ ③ خدمات التسجيل من مزودي السحابة (AWS CloudWatch / Alibaba Cloud SLS). الكل يتبع: stdout الحاوية ← المجمع ← التخزين المركزي ← لوحة البحث.
س كيف أُعد HTTPS في بيئة الإنتاج؟
ج تكوين TLS في حاوية Nginx: ① شهادة Let's Encrypt مجانية + تجديد تلقائي عبر Certbot؛ ② وضع الوكيل العكسي: Nginx يتولى TLS، بينما الاتصال الداخلي يستخدم HTTP؛ ③ موازن الحمل لدى مزود السحابة يتولى TLS (ALB/SLB)، لذا لا تحتاج الحاوية إلى شهادة.
س كيف تراقب صحة مجموعة microservices بالكامل؟
ج التركيبة الذهبية لـ Prometheus و Grafana: ① Prometheus يجمع البيانات من نقاط نهاية /metrics لكل خدمة؛ ② Grafana يعرض لوحات المعلومات وقواعد التنبيه؛ ③ المقاييس الرئيسية: زمن استجابة API (P50/P95/P99)، معدل الخطأ، استخدام CPU/الذاكرة، وعدد اتصالات قاعدة البيانات. راقب أولاً، ثم حسّن.

📖 ملخص


📝 تمارين

  1. تمرين أساسي (الصعوبة: ⭐): صمم مخطط بنية microservices لنظام مدونة (Nginx + API + قاعدة بيانات + ذاكرة تخزين مؤقت)، واذكر الصورة والمنفذ لكل خدمة.
  2. تمرين متقدم (الصعوبة: ⭐⭐): انشر هذه البنية باستخدام تقنية Docker الشاملة، واكتب ملف docker-compose.prod.yml، وابدأ التطبيق بنجاح.
  3. تحدٍ (الصعوبة: ⭐⭐⭐): أعد لوحة مراقبة Prometheus + Grafana، وأضف لوحات لزمن استجابة API ومعدل الأخطاء، وكوّن قواعد تنبيه بالبريد الإلكتروني.
Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%