العودة للدورة|ابنِ واجهة REST API إنتاجية: من الصفر حتى النشر مع FastAPI
معمل

حاوية TaskFlow ونشره

35 دقيقة
متوسط
محاولات مجانية غير محدودة

التعليمات

الهدف

تعبئة واجهة TaskFlow API للنشر في الإنتاج. ستُنشئ ملف Dockerfile متعدد المراحل وتكوين Docker Compose للإنتاج وخط أنابيب CI/CD مع GitHub Actions وإعدادات تطبيق مُحصنة للإنتاج.

الجزء 1: Dockerfile (25 نقطة)

أنشئ ملف Dockerfile في جذر المشروع ببناء متعدد المراحل.

المتطلبات

مرحلة البناء:

  • استخدم python:3.12-slim كصورة أساسية (إصدار مُثبت، وليس latest)
  • ثبّت تبعيات النظام اللازمة لتجميع حزم Python (build-essential، libpq-dev)
  • انسخ requirements.txt أولاً، ثم ثبّت التبعيات مع --no-cache-dir و --prefix=/install
  • هذا الترتيب يضمن عمل التخزين المؤقت لطبقات Docker -- طبقات التبعيات تُعاد بناؤها فقط عند تغيير requirements.txt

مرحلة الإنتاج:

  • استخدم python:3.12-slim مرة أخرى كقاعدة نظيفة
  • ثبّت مكتبات النظام للتشغيل فقط (libpq5، curl)
  • أنشئ مستخدماً ومجموعة غير جذريين باسم taskflow
  • انسخ حزم Python المُثبتة من مرحلة البناء باستخدام COPY --from=builder
  • انسخ كود التطبيق
  • عيّن الملكية لمستخدم taskflow وانتقل إليه بـ USER taskflow
  • أضف HEALTHCHECK يفحص نقطة /health
  • اعرض المنفذ 8000
  • استخدم Gunicorn مع عمال Uvicorn كنقطة دخول: gunicorn app.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

مثال على الهيكل

# المرحلة 1: البناء
FROM python:3.12-slim AS builder
WORKDIR /app
# تثبيت تبعيات البناء
# نسخ وتثبيت تبعيات Python

# المرحلة 2: الإنتاج
FROM python:3.12-slim AS production
# تثبيت تبعيات التشغيل فقط
# إنشاء مستخدم غير جذري
# النسخ من مرحلة البناء
# نسخ كود التطبيق
# تعيين المستخدم وفحص الصحة والعرض والأمر

الجزء 2: Docker Compose للإنتاج (25 نقطة)

أنشئ docker-compose.prod.yml مع ثلاث خدمات.

المتطلبات

خدمة API:

  • البناء من Dockerfile مع استهداف مرحلة production
  • ربط المنفذ 8000
  • تحميل البيئة من .env.production
  • الاعتماد على db و redis مع condition: service_healthy
  • تعيين حدود الموارد: 1 CPU، 512MB ذاكرة
  • تعيين restart: unless-stopped
  • الاتصال بشبكتي external و internal

خدمة PostgreSQL:

  • استخدام صورة postgres:18
  • حفظ البيانات بحجم مُسمى pgdata مركب على /var/lib/postgresql/data
  • تكوين اسم قاعدة البيانات والمستخدم وكلمة المرور عبر متغيرات البيئة
  • إضافة فحص صحة باستخدام pg_isready
  • الاتصال بشبكة internal فقط

خدمة Redis:

  • استخدام صورة redis:7-alpine
  • تفعيل استمرارية AOF مع --appendonly yes
  • تعيين الحد الأقصى للذاكرة إلى 128MB مع سياسة إخلاء allkeys-lru
  • حفظ البيانات بحجم مُسمى redisdata مركب على /data
  • إضافة فحص صحة باستخدام redis-cli ping
  • الاتصال بشبكة internal فقط

الشبكات:

  • external: شبكة جسر افتراضية (API يمكن الوصول إليه من الخارج)
  • internal: تعيين internal: true لعزل db وredis عن المضيف

الأحجام:

  • pgdata و redisdata كأحجام مُسماة

الجزء 3: GitHub Actions CI/CD (25 نقطة)

أنشئ .github/workflows/ci.yml مع خط أنابيب CI/CD.

المتطلبات

المشغل: عند push إلى فرع main وعند pull_request إلى main

مهمة الاختبار:

  • تعمل على ubuntu-latest
  • تشغيل PostgreSQL 18 وRedis 7 كحاويات خدمة مع فحوصات صحة
  • الخطوات:
    1. actions/checkout@v4
    2. actions/setup-python@v5 مع Python 3.12
    3. تثبيت التبعيات من requirements.txt
    4. تشغيل المُدقق: ruff check .
    5. تشغيل الاختبارات: pytest --cov=app tests/
  • تمرير DATABASE_URL و REDIS_URL و SECRET_KEY كمتغيرات بيئة لخطوة الاختبار

مهمة البناء:

  • تعمل فقط عند الدفع إلى main (وليس عند طلبات السحب)
  • تعتمد على نجاح مهمة الاختبار (needs: test)
  • الخطوات:
    1. actions/checkout@v4
    2. بناء صورة Docker مُوسمة بـ SHA الخاص بالإيداع

الجزء 4: تكوين الإنتاج (25 نقطة)

أنشئ أو حدّث الملفات التالية في التطبيق.

4أ. تكوين Gunicorn

أنشئ gunicorn.conf.py في جذر المشروع:

import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "uvicorn.workers.UvicornWorker"
bind = "0.0.0.0:8000"
accesslog = "-"
errorlog = "-"
loglevel = "info"

4ب. وسيط ترويسات الأمان

أنشئ وسيطاً في app/middleware/security.py يُضيف هذه الترويسات لكل استجابة:

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • Strict-Transport-Security: max-age=31536000; includeSubDomains
  • X-XSS-Protection: 1; mode=block
  • Referrer-Policy: strict-origin-when-cross-origin
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import Response

class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next) -> Response:
        response = await call_next(request)
        response.headers["X-Content-Type-Options"] = "nosniff"
        response.headers["X-Frame-Options"] = "DENY"
        response.headers["Strict-Transport-Security"] = (
            "max-age=31536000; includeSubDomains"
        )
        response.headers["X-XSS-Protection"] = "1; mode=block"
        response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
        return response

4ج. تكوين CORS

في app/main.py، كوّن CORS بأصول صريحة للإنتاج (لا تستخدم * كأصل شامل أبداً في الإنتاج):

from fastapi.middleware.cors import CORSMiddleware

if settings.is_production:
    allowed_origins = ["https://taskflow.example.com"]
else:
    allowed_origins = ["http://localhost:3000"]

app.add_middleware(
    CORSMiddleware,
    allow_origins=allowed_origins,
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE"],
    allow_headers=["Authorization", "Content-Type"],
)

4د. إعدادات مبنية على البيئة

أنشئ app/config.py باستخدام Pydantic Settings لتحميل والتحقق من جميع التكوينات من متغيرات البيئة:

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str
    redis_url: str
    secret_key: str
    environment: str = "development"
    api_v1_prefix: str = "/api/v1"

    @property
    def is_production(self) -> bool:
        return self.environment == "production"

    model_config = {"env_file": ".env"}

settings = Settings()

4هـ. إصدارات API

يجب تركيب جميع الموجهات تحت بادئة /api/v1/:

from app.config import settings

app.include_router(tasks_router, prefix=settings.api_v1_prefix)
app.include_router(auth_router, prefix=settings.api_v1_prefix)

ما يجب تقديمه

يجب أن يحتوي تقديمك على 7 أقسام ملفات في المحرر أدناه. يبدأ كل قسم بعنوان # FILE N:.


تلميحات

  • اختبر Dockerfile محلياً بـ docker build -t taskflow . قبل التسليم
  • شغّل docker compose -f docker-compose.prod.yml up للتحقق من بدء جميع الخدمات ونجاح فحوصات الصحة
  • ترتيب تعليمات COPY في Dockerfile مهم للتخزين المؤقت -- ضع الملفات نادرة التغيير أولاً
  • لسير عمل CI، استخدم مفتاح services تحت المهمة لتشغيل PostgreSQL وRedis

معايير التقييم

Dockerfile يستخدم بناء متعدد المراحل مع قاعدة python:3.12-slim مُثبتة، ترتيب COPY صحيح للتخزين المؤقت للطبقات (requirements.txt قبل كود التطبيق)، مستخدم غير جذري مُنشأ ومُفعل، تعليمة HEALTHCHECK موجودة، وGunicorn مع UvicornWorker كـ CMD25 نقاط
ملف Docker Compose للإنتاج يُعرف ثلاث خدمات (api، db، redis) مع PostgreSQL 18 وRedis 7، أحجام مُسماة للاستمرارية، فحوصات صحة على جميع الخدمات، حدود موارد على API، سياسة إعادة التشغيل، وعزل الشبكة (شبكة داخلية لـ db/redis، خارجية لـ API)25 نقاط
سير عمل GitHub Actions يُشغل عند الدفع إلى main وطلبات السحب، يستخدم حاويات خدمة PostgreSQL وRedis مع فحوصات صحة، يُشغل checkout وإعداد Python 3.12 وتثبيت التبعيات ومُدقق ruff واختبارات pytest مع التغطية، ويتضمن مهمة بناء تعتمد على نجاح الاختبار وتعمل فقط على main25 نقاط
تكوين الإنتاج يتضمن تكوين Gunicorn مع UvicornWorker، وسيط SecurityHeadersMiddleware يُضيف جميع ترويسات الأمان الخمس، CORS بأصول صريحة (وليس شاملة) حسب البيئة، Pydantic Settings مع تحميل env_file وخاصية is_production، وجميع الموجهات مُركبة تحت بادئة /api/v1/25 نقاط

قائمة التحقق

0/7

حلك

محاولات مجانية غير محدودة