نشر المشروع والإطلاق — من التطوير إلى الإنتاج
إطلاق المنتج مثل إطلاق صاروخ — الدروس الـ 24 الأولى تغطي التصميم والتصنيع، وهذا الدرس عن العد التنازلي والإطلاق. هناك قائمة مراجعة طويلة قبل الإطلاق، ولا يمكنك إشعال المحركات حتى يتم التحقق من كل بند. الإطلاق بدون قائمة مراجعة هو مقامرة.
1. ما ستتعلمه
- قائمة مراجعة بيئة الإنتاج: تقييم ثلاثي الأبعاد للأمان والأداء والمراقبة
- استراتيجيات النشر المرحلي: أساليب تنفيذ النشر الأزرق-الأخضر والنشر الكناري
- أمان ترحيل قاعدة البيانات: أفضل ممارسات Alembic للترحيل بدون توقف
- تجميع السجلات: سجلات مهيكلة + تكامل ELK / Loki
- Alice: الفصل الأخير — يُطلق PriceTracker رسميًا
2. القصة الحقيقية لـ Alice
(1) نقطة الألم: حوادث متكررة أثناء النشر
واجه PriceTracker مشاكل خلال أول عملية نشرين: في المرة الأولى، نسوا إعداد HTTPS؛ في المرة الثانية، تسبب قفل جدول خلال ترحيل قاعدة البيانات في انقطاع خدمة لمدة 10 دقائق؛ وفي المرة الثالثة، لم تكن السجلات مجمعة، لذا بعد ظهور مشكلة، قضى Charlie ساعتين في البحث في السجلات عبر خمسة خوادم. تحتاج Alice إلى عملية نشر منهجية لضمان أن كل نشر آمن وخاضع للرقابة.
(2) حل قائمة مراجعة النشر
النشر ليس مجرد "دفع الكود والانتهاء"؛ إنه سلسلة من قوائم المراجعة: التصلب الأمني، والتحقق من الأداء، واستراتيجية الترحيل، والنشر المرحلي، والتحقق من المراقبة — لا يمكنك الانتقال إلى الخطوة التالية إلا بعد التحقق من كل بند.
(3) العائد
النشر الثالث: تم التحقق من جميع بنود قائمة المراجعة؛ تم إعداد HTTPS؛ اكتمل الترحيل بدون توقف؛ بدأ إصدار متدرج بتوجيه 10% من حركة المرور للتحقق أولاً؛ والسجلات جُمعت تلقائيًا إلى Loki — عملية النشر بالكامل سارت بسلاسة، ولوحة مراقبة Charlie ظلت باللون الأخضر طوال الوقت.
3. قائمة مراجعة بيئة الإنتاج
(1) عملية الإطلاق
flowchart TD
A[تجميد الكود] --> B[تدقيق أمني]
B --> C[اختبار حمل]
C --> D[نشر Staging]
D --> E[اختبار دخان]
E --> F[إصدار كناري 10%]
F --> G{المقاييس جيدة؟}
G -->|نعم| H[نشر كامل 100%]
G -->|لا| I[تراجع]
I --> J[تحقيق]
J --> A
H --> K[مراقبة ساعة]
K --> L[✓ مباشر]
(2) قائمة المراجعة ثلاثية الأبعاد
| البُعد | بند الفحص | الحالة |
|---|---|---|
| الأمان | إعداد شهادة HTTPS | ☐ |
| CORS يسمح فقط بنطاقات الإنتاج | ☐ | |
| تفعيل تحديد المعدل | ☐ | |
| تم تغيير JWT SECRET_KEY | ☐ | |
| لا مفاتيح مُصلبة برمجيًا | ☐ | |
| اجتاز الفحص الأمني | ☐ | |
| الأداء | Uvicorn Workers ≥ 4 | ☐ |
| حجم مناسب لتجمع اتصالات قاعدة البيانات | ☐ | |
| تفعيل تخزين Redis المؤقت | ☐ | |
| تفعيل ضغط GZip | ☐ | |
| اجتاز اختبار الحمل (QPS المستهدف) | ☐ | |
| المراقبة | نقطة النهاية /health تعمل بشكل طبيعي | ☐ |
| جمع مقاييس Prometheus | ☐ | |
| لوحة Grafana جاهزة | ☐ | |
| إعداد قواعد التنبيه | ☐ | |
| تجميع السجلات يعمل | ☐ |
4. استراتيجية النشر المرحلي
(1) النشر الأزرق-الأخضر
flowchart LR
LB[موازن التحميل] -->|100% حركة المرور| Blue[الأزرق v1]
subgraph Deploy
Green[الأخضر v2]
end
LB -.->|تبديل| Green
style Blue fill:#4caf50
style Green fill:#2196f3
| الخطوة | الإجراء | التراجع |
|---|---|---|
| 1 | نشر بيئة الأخضر (v2) | - |
| 2 | تشغيل اختبارات دخان في الأخضر | - |
| 3 | LB يتحول إلى الأخضر | العودة إلى الأزرق |
| 4 | مراقبة الأخضر لمدة 30 دقيقة | العودة إلى الأزرق |
| 5 | تأكيد الاستقرار، إيقاف الأزرق | - |
(1) ▶مثال: إعداد Nginx للنشر الأزرق-الأخضر
# nginx/conf.d/pricetracker.conf
upstream pricetracker_blue {
server api-blue:8000;
}
upstream pricetracker_green {
server api-green:8000;
}
# يخدم حاليًا الأزرق
server {
listen 80;
server_name api.pricetracker.example.com;
location / {
proxy_pass http://pricetracker_blue;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# التبديل إلى الأخضر بتغيير هدف proxy_pass
# ثم: docker compose -f docker-compose.green.yml up -d
الناتج:
// التنفيذ ناجح
(2) الإصدار الكناري
| الاستراتيجية | توزيع الحركة | فترة المراقبة | التراجع |
|---|---|---|---|
| 10% | 1 v2 + 9 v1 | 15 دقيقة | العودة إلى v1 |
| 30% | 3 v2 + 7 v1 | 15 دقيقة | العودة إلى v1 |
| 50% | 5 v2 + 5 v1 | 15 دقيقة | العودة إلى v1 |
| 100% | الكل v2 | 30 دقيقة | التراجع لإصدار الصورة |
5. ترحيل قاعدة البيانات بدون توقف
(1) مبادئ الترحيل الآمن
| المبدأ | الوصف | مثال |
|---|---|---|
| أضف فقط، لا تحذف | أضف عمودًا جديدًا أولاً؛ لا تحذف العمود القديم | ALTER TABLE ADD COLUMN new_col |
| توافق الكتابة المزدوجة | الكود الجديد والقديم يعملان | الكود الجديد يكتب في عمودين؛ الكود القديم يقرأ العمود القديم فقط |
| تنظيف مؤجل | احذف الأعمدة القديمة فقط بعد تأكيد الاستقرار | احذف الأعمدة القديمة بعد 7 أيام من نشر v2 |
| ترحيل تزايدي | غيّر شيئًا واحدًا فقط في كل مرة | لا تضف أعمدة أو تغيّر أنواع بيانات في ترحيل واحد |
(1) ▶مثال: ترحيل إضافة عمود آمن
# alembic/versions/xxx_add_wholesale_price.py
"""إضافة عمود wholesale_price إلى المنتجات
ترحيل آمن: ADD COLUMN غير حظر في PostgreSQL
"""
def upgrade():
op.add_column(
"products",
sa.Column("wholesale_price", sa.Float(), nullable=True),
)
# تعيين القيمة الافتراضية للصفوف الموجودة (بيان منفصل للأداء)
op.execute("UPDATE products SET wholesale_price = base_price * 0.6 WHERE wholesale_price IS NULL")
# اجعلها غير قابلة للفراغ في الترحيل التالي بعد نشر الكود
def downgrade():
op.drop_column("products", "wholesale_price")
الناتج:
# تم تعريف الدالة بنجاح
(2) ترحيل محفوف بالمخاطر مقابل ترحيل آمن
| نوع الترحيل | الأمان | خطر قفل الجدول | التوصيات |
|---|---|---|---|
| ADD COLUMN | آمن | لا يوجد | يمكن تنفيذه عبر الإنترنت |
| CREATE INDEX | آمن نسبيًا | ممكن | استخدم CREATE INDEX CONCURRENTLY |
| DROP COLUMN | خطر | نعم | تأكد أولاً أن الكود لم يعد يستخدمه |
| ALTER COLUMN TYPE | خطر | عالٍ | ترحيل مرحلي (أضف عمود جديد ← رحّل البيانات ← احذف العمود القديم) |
| RENAME COLUMN | خطر | متوسط | أعِد التسمية بعد تفعيل توافق الكتابة المزدوجة |
6. تجميع السجلات
(1) السجلات المهيكلة
(1) ▶مثال: إعداد السجلات المهيكلة
# app/core/logging.py
import logging
import json
from datetime import datetime
class JSONFormatter(logging.Formatter):
def format(self, record):
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"level": record.levelname,
"message": record.getMessage(),
"module": record.module,
"function": record.funcName,
"line": record.lineno,
}
# إضافة سياق الطلب إذا كان متاحًا
if hasattr(record, "request_id"):
log_entry["request_id"] = record.request_id
if hasattr(record, "user_id"):
log_entry["user_id"] = record.user_id
return json.dumps(log_entry)
# إعداد التسجيل
logger = logging.getLogger("pricetracker")
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)
الناتج:
# تم تعريف الدالة بنجاح
(2) مقارنة حلول تجميع السجلات
| الحل | المزايا | العيوب | السيناريوهات الموصى بها |
|---|---|---|---|
| ELK (Elasticsearch + Logstash + Kibana) | ميزات شاملة، قدرات بحث قوية | استهلاك موارد عالٍ | المشاريع الكبيرة |
| Loki+Grafana+Promtail | خفيف، متكامل مع Grafana | قدرات بحث محدودة | المشاريع الصغيرة والمتوسطة |
| CloudWatch Logs | بدون صيانة | حصر AWS | نشر على AWS |
(2) ▶مثال: إضافة Loki إلى Docker Compose
# أضف إلى docker-compose.yml
loki:
image: grafana/loki:latest
ports:
- "3100:3100"
volumes:
- loki_data:/loki
promtail:
image: grafana/promtail:latest
volumes:
- /var/log:/var/log:ro
- ./docker/promtail.yml:/etc/promtail/config.yml
depends_on:
- loki
الناتج:
CONTAINER ID IMAGE STATUS PORTS
abc123 nginx:latest Up 2 hours 0.0.0.0:80->80/tcp
7. يُطلق PriceTracker رسميًا
(1) معالم إنجاز المشروع
gantt
title الجدول الزمني لتطوير PriceTracker
dateFormat YYYY-MM-DD
section المرحلة 1
مقدمة FastAPI :p1a, 2026-01-01, 1d
التثبيت و UV :p1b, after p1a, 1d
معاملات المسار والاستعلام :p1c, after p1b, 1d
هيكل الطلب و Pydantic :p1d, after p1c, 1d
نماذج الاستجابة :p1e, after p1d, 1d
مشروع المرحلة 1 :p1f, after p1e, 2d
section المرحلة 2
Middleware :p2a, after p1f, 1d
حقن التبعية :p2b, after p2a, 1d
قاعدة البيانات SQLAlchemy :p2c, after p2b, 2d
عمليات CRUD :p2d, after p2c, 1d
المصادقة JWT :p2e, after p2d, 2d
مشروع المرحلة 2 :p2f, after p2e, 2d
section المرحلة 3
WebSocket :p3a, after p2f, 1d
Celery :p3b, after p3a, 2d
رفع الملفات :p3c, after p3b, 1d
الاختبار :p3d, after p3c, 1d
التخزين المؤقت :p3e, after p3d, 1d
OpenAPI :p3f, after p3e, 1d
section المرحلة 4
Docker :p4a, after p3f, 1d
الأداء :p4b, after p4a, 1d
المراقبة :p4c, after p4b, 1d
CI/CD :p4d, after p4c, 1d
section المرحلة 5
تصميم المشروع :p5a, after p4d, 1d
تطوير المشروع :p5b, after p5a, 2d
نشر المشروع :p5c, after p5b, 1d
(2) قائمة مراجعة التحقق من النشر
| بند التحقق | طريقة التحقق | معايير النجاح |
|---|---|---|
| توفر API | curl /health |
{"status": "healthy"} |
| تكامل الواجهة الأمامية | Bob يستدعي API من الواجهة الأمامية | جميع نقاط النهاية تعمل بشكل صحيح |
| المصادقة | تسجيل دخول JWT + نقاط نهاية محمية | تسجيل الدخول ناجح؛ يُرجع 401 إذا لم تتم المصادقة |
| الصلاحيات | تحديد معدل Free/Pro/Enterprise | محدد بشكل صحيح حسب الخطة |
| WebSocket | اتصال + بث الأسعار | استقبال تحديثات فورية |
| التخزين المؤقت | معدل إصابة التخزين المؤقت للمنتجات الشائعة | > 80% |
| المراقبة | لوحة Grafana | المقاييس تُعرض بشكل طبيعي |
| التنبيهات | محاكاة ارتفاع P99 | تنبيه مشغل إشعار |
| السجلات | استعلام Loki | سجلات مهيكلة قابلة للبحث |
| CI/CD | نشر مُطلق بدفع tag | نشر تلقائي ناجح |
❓أسئلة شائعة
weight (server v2:8000 weight=1; server v1:8000 weight=9;)، بينما يستخدم K8s نشر canary لتعديل عدد النسخ.CREATE INDEX CONCURRENTLY (لإنشاء فهارس بدون قفل الجداول) وتجنب تنفيذ عبارات DDL خلال ساعات الذروة. رحّل الجداول الكبيرة على دفعات.📖ملخص
- الأبعاد الثلاثة لقائمة مراجعة النشر: الأمان (HTTPS/CORS/RateLimit)، الأداء (Workers/تجمع الاتصالات/التخزين المؤقت)، المراقبة (المقاييس/التنبيهات/السجلات)
- النشر الأزرق-الأخضر: التبديل بين بيئتين مع تراجع في ثوانٍ؛ النشر الكناري: توسع تدريجي — 10% ← 30% ← 50% ← 100%
- مبادئ الترحيل بدون توقف: أضف فقط، لا تحذف أبدًا؛ توافق الكتابة المزدوجة؛ التنظيف المؤجل؛ الترحيل التزايدي
- سجلات JSON مهيكلة + تجميع Loki/Grafana، مع تتبع الطلبات عبر
request_id - أُطلق PriceTracker رسميًا: تكامل واجهة Bob الأمامية ناجح، نظام مراقبة Charlie يُعطي الضوء الأخضر، وملايين نقاط بيانات الأسعار تتدفق بسلاسة
📝تمارين
- تمرين أساسي (الصعوبة: ⭐): أنشئ قائمة مراجعة نشر لـ PriceTracker (5 بنود لكل من الأمان والأداء والمراقبة) واستخدمها للتحقق من بيئة النشر بندًا ببند. تلميح: راجع جدول قائمة المراجعة في هذا الدرس.
- مسألة متقدمة (الصعوبة ⭐⭐): نفذ تسجيل JSON مهيكل (بما في ذلك timestamp و level و message و request_id)؛ أضف middleware تسجيل لحقن request_id في كل طلب؛ وإعداد Docker Compose و Loki لتجميع السجلات. تلميح: JSONFormatter +
logging.getLogger("pricetracker") - تحدٍ (الصعوبة: ⭐⭐⭐): أكمل عملية النشر — اكتب سكريبت ترحيل آمن (اتبع مبدأ "أضف فقط، لا تحذف")، إعداد نشر Nginx أزرق-أخضر، ضبط قواعد تنبيه Grafana (P99 > 500 مللي ثانية + معدل الخطأ > 5%)، وأجرِ تحقق إصدار كناري (وجّه 10% من حركة المرور إلى v2 أولاً، ثم حوّل بالكامل). تلميح:
CREATE INDEX CONCURRENTLY+ تبديل upstream في Nginx
---| العودة إلى الفهرس



