النشر للإنتاج
Deploying to Production
النشر للإنتاج — Deploying to Production
كتابة كود يعمل على جهازك الشخصي شيء — ونشره بشكل موثوق يخدم آلاف المستخدمين شيء آخر. في هذا الدرس ستتعلم الأدوات والأنماط التي يستخدمها المطورون المحترفون لنقل تطبيقات Python من بيئة التطوير إلى الإنتاج.
الخطوة الأولى: requirements.txt
requirements.txt هو ملف نصي يُدرج فيه كل الحزم التي يحتاجها تطبيقك مع إصداراتها. هذا ما يضمن أن بيئة الإنتاج (أو جهاز زميلك) تُثبّت نفس الإصدارات تماماً التي طوّرت عليها.
# requirements.txt
flask==3.0.2
gunicorn==21.2.0
python-dotenv==1.0.1
sqlalchemy==2.0.28
requests==2.31.0
أوامر أساسية:
# تثبيت كل الحزم من الملف
pip install -r requirements.txt
# توليد الملف من البيئة الحالية
pip freeze > requirements.txt
# تثبيت حزمة واحدة
pip install flask==3.0.2
نصيحة متقدمة: افصل بين requirements للتطوير والإنتاج:
requirements.txt # الإنتاج فقط
requirements-dev.txt # التطوير: pytest، black، flake8...
# requirements-dev.txt
-r requirements.txt # يشمل الإنتاج
pytest==8.1.0
black==24.3.0
flake8==7.0.0
متغيرات البيئة — Environment Variables
أسوأ خطأ يمكن أن يرتكبه مطور هو وضع كلمات المرور أو مفاتيح API مباشرة في الكود. إذا رفعت الكود على GitHub، الجميع يقرأ أسرارك.
الحل: متغيرات البيئة
import os
# ❌ لا تفعل هذا أبداً — Never do this
DATABASE_URL = "postgresql://user:password123@localhost/mydb"
SECRET_KEY = "super-secret-key-12345"
API_KEY = "sk-abc123..."
# ✅ اقرأ من البيئة — Read from environment
DATABASE_URL = os.environ.get("DATABASE_URL")
SECRET_KEY = os.environ.get("SECRET_KEY")
API_KEY = os.environ.get("API_KEY")
قيم افتراضية للتطوير:
import os
# قيمة افتراضية للتطوير، يجب تعيينها في الإنتاج
# Default for dev, must be set in production
DATABASE_URL = os.environ.get("DATABASE_URL", "sqlite:///local.db")
DEBUG = os.environ.get("DEBUG", "false").lower() == "true"
PORT = int(os.environ.get("PORT", "8000"))
ملف .env للتطوير المحلي:
# .env (لا تضعه في git! — do not commit!)
DATABASE_URL=postgresql://user:pass@localhost/mydb
SECRET_KEY=dev-secret-key
DEBUG=true
PORT=8000
# قراءة .env في التطوير — Load .env in development
from dotenv import load_dotenv # pip install python-dotenv
load_dotenv()
import os
DATABASE_URL = os.environ.get("DATABASE_URL")
تذكر: .env في ملف .gitignore دائماً.
أنماط الإعداد الإنتاجي — Config Patterns
النمط الأفضل هو فصل الإعداد في كلاس مستقل:
import os
from dataclasses import dataclass
@dataclass
class Config:
"""إعداد التطبيق — Application configuration"""
# قاعدة البيانات — Database
database_url: str
# الأمان — Security
secret_key: str
# الخادم — Server
port: int
debug: bool
@classmethod
def from_env(cls) -> "Config":
"""اقرأ الإعداد من متغيرات البيئة — Read config from environment"""
return cls(
database_url=os.environ["DATABASE_URL"], # مطلوب — Required
secret_key=os.environ["SECRET_KEY"], # مطلوب — Required
port=int(os.environ.get("PORT", "8000")),
debug=os.environ.get("DEBUG", "false").lower() == "true",
)
@property
def is_production(self) -> bool:
"""هل نحن في الإنتاج؟ — Are we in production?"""
return not self.debug
# الاستخدام — Usage
config = Config.from_env()
if config.is_production:
print("وضع الإنتاج")
else:
print("وضع التطوير")
gunicorn — خادم الإنتاج
gunicorn (Green Unicorn) هو خادم HTTP للإنتاج. Flask وFastAPI مدمجان بخوادم تطوير فقط — لا تُستخدم في الإنتاج.
# تثبيت — Install
pip install gunicorn
# تشغيل بسيط — Simple run
gunicorn app:app
# بأربعة عمال — With 4 workers
gunicorn app:app -w 4
# مع خيارات كاملة — With full options
gunicorn app:app \
--workers 4 \
--bind 0.0.0.0:8000 \
--timeout 30 \
--access-logfile /var/log/gunicorn/access.log \
--error-logfile /var/log/gunicorn/error.log
قاعدة عدد العمال: (2 × عدد الأنوية) + 1
import multiprocessing
# 4 أنوية → 9 عمال
workers = (2 * multiprocessing.cpu_count()) + 1
لماذا عمال متعددة؟ كل عامل هو عملية Python مستقلة. عامل واحد يعمل على طلب واحد في كل مرة. 4 عمال = 4 طلبات متزامنة. بهذا تتجاوز قيود GIL لأن كل عامل مترجم Python منفصل.
Dockerfile — حاوية التطبيق
Docker يُغلّف تطبيقك مع كل تبعياته في وحدة يمكن تشغيلها في أي مكان:
# Dockerfile
# بيئة Python رسمية خفيفة — Official lightweight Python base
FROM python:3.12-slim
# تعيين مجلد العمل — Set working directory
WORKDIR /app
# نسخ ملف المتطلبات أولاً (استغلال cache) — Copy requirements first (cache optimization)
COPY requirements.txt .
# تثبيت المتطلبات — Install dependencies
RUN pip install --no-cache-dir -r requirements.txt
# نسخ الكود — Copy application code
COPY . .
# فتح المنفذ — Expose port
EXPOSE 8000
# أمر التشغيل — Run command
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000", "--workers", "4"]
بناء وتشغيل الصورة:
# بناء — Build
docker build -t myapp:latest .
# تشغيل — Run
docker run -p 8000:8000 \
-e DATABASE_URL=postgresql://... \
-e SECRET_KEY=production-key \
myapp:latest
ملف .dockerignore لتسريع البناء:
.git
.env
__pycache__
*.pyc
*.pyo
venv/
.venv/
*.egg-info/
قائمة جاهزية الإنتاج — Production Checklist
قبل أي نشر، تحقق من هذه النقاط:
☐ متغيرات البيئة جاهزة (لا أسرار في الكود)
☐ requirements.txt مُحدَّث بإصدارات محددة
☐ DEBUG=False في الإنتاج
☐ قاعدة بيانات الإنتاج معزولة عن التطوير
☐ gunicorn أو uvicorn بدلاً من خادم التطوير
☐ HTTPS مُفعَّل
☐ تسجيل الأخطاء (logging) مُعَدّ
☐ اختبارات تجتاز 100%
☐ نسخة احتياطية لقاعدة البيانات
☐ مراقبة الخادم (monitoring) مُفعّلة
التحديات العملية
التحدي الأول: قراءة متغير بيئة بقيمة افتراضية
التحدي الثاني: كلاس الإعداد
التحدي الثالث: كشف وضع التشغيل
التحدي الرابع: توليد محتوى requirements.txt
التحدي الخامس: دالة فحص الجاهزية