Docker: الممارسة المتكاملة للمرحلة الثانية
آخر تحديث: 2026-08-26
تجميع مفاهيم المرحلة الثانية — من الكود المصدري إلى الصورة الجاهزة للإنتاج: تحويل تطبيق ويب كامل إلى حاويات.
1. ما ستتعلمه
- مشروع عملي كامل مبني على مراحل متعددة
- سياسة إدارة إعدادات البيئة
- حلول استمرارية السجلات
- فحوصات الصحة وإعدادات الشفاء الذاتي
- وسوم الصور والتحكم في الإصدارات
2. قصة عن استلام مشروع قديم
(1) نقطة الألم: مشاريع قديمة لا تعمل في Docker
استلم تشارلي مشروع Python قديم "لا يعمل في Docker" — كان لديه Dockerfile بحجم 1.2 جيجابايت، يستغرق 10 دقائق للبناء في كل مرة، بدون فحوصات صحة، يكتب السجلات داخل الحاوية (التي كانت تُفقد عند إعادة التشغيل)، يعمل كمستخدم root، ولديه متغيرات بيئة مشفرة. استغرق النشر 30 دقيقة وكان غير مستقر.
(2) حل التحويل الكامل إلى حاويات
ساعدته أليس بتحليل شجرة التبعيات، وكتابة Dockerfile متعدد المراحل، وإعداد استمرارية السجلات، وإضافة فحوصات الصحة، وتشغيل التطبيق كمستخدم غير root. في النهاية، تم بناء المشروع ونشره في أقل من 3 دقائق.
DOCKERFILE
# Dockerfile إنتاج متعدد المراحل
FROM python:3.12-slim AS builder
# ... بناء venv محسن
FROM python:3.12-slim
# ... نسخ venv، غير root، healthcheck
(3) المدة: من 30 دقيقة إلى 3 دقائق
| المقياس | قبل التحسين | بعد التحسين |
|---|---|---|
| حجم الصورة | 1.2 جيجابايت | 150 ميجابايت |
| وقت البناء | 10 دقائق | 3 دقائق |
| وقت النشر | 30 دقيقة | 3 دقائق |
| درجة الأمان | 45 | 85 |
3. تصميم بنية المشروع
(1) بنية التطبيق
في هذا الدرس، سنحول تطبيق Flask لقائمة المهام إلى حاويات: Flask + PostgreSQL + Nginx.
graph TB
USER["المتصفح"] --> NGX["Nginx<br/>وكيل عكسي + ثابت"]
NGX -->|"proxy_pass :5000"| APP["تطبيق Flask<br/>API + واجهة قائمة المهام"]
APP -->|"psycopg2 :5432"| DB["PostgreSQL<br/>قاعدة بيانات المهام"]
DB --> VOL["وحدة تخزين مسماة<br/>pg-data"]
APP --> LOGS["وحدة تخزين مسماة<br/>app-logs"]
(2) استراتيجية التحويل إلى حاويات
| المكون | الصورة الأساسية | السياسة |
|---|---|---|
| تطبيق Flask | python:3.12-slim |
بناء متعدد المراحل + غير root + HEALTHCHECK |
| PostgreSQL | postgres:15-alpine |
صورة رسمية + وحدة تخزين مسماة |
| Nginx | nginx:1.25-alpine |
صورة رسمية + تركيب Bind لملف الإعدادات |
4. Dockerfile لتطبيق Flask
(1) هيكل المشروع
TEXT
📖 للعرض فقط
todo-app/
├── app.py # تطبيق Flask
├── requirements.txt # تبعيات Python
├── templates/ # قوالب HTML
│ └── index.html
├── Dockerfile # بناء إنتاج متعدد المراحل
├── .dockerignore # استبعاد الملفات غير الضرورية
├── nginx.conf # إعدادات وكيل Nginx العكسي
└── docker-run.sh # برنامج نشر بنقرة واحدة
▶ مثال: كتابة Dockerfile متعدد المراحل (الصعوبة: ⭐⭐⭐)
DOCKERFILE
# ============================================
# Dockerfile متعدد المراحل لتطبيق Flask للمهام
# المرحلة 1: بناء البيئة الافتراضية
# المرحلة 2: تشغيل الإنتاج
# ============================================
# ---------- المرحلة 1: البناء ----------
FROM python:3.12-slim AS builder
WORKDIR /build
# التخزين المؤقت: تثبيت التبعيات أولاً
COPY requirements.txt .
RUN python -m venv /opt/venv && \
/opt/venv/bin/pip install --no-cache-dir -r requirements.txt
# ---------- المرحلة 2: الإنتاج ----------
FROM python:3.12-slim
# تثبيت curl لفحص الصحة
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
# إنشاء مستخدم غير root
RUN groupadd -r appgroup && \
useradd -r -g appgroup -u 1000 -m -d /home/appuser appuser
WORKDIR /app
# نسخ البيئة الافتراضية من مرحلة البناء
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# نسخ كود التطبيق
COPY --chown=appuser:appgroup . .
# إنشاء دليل السجلات
RUN mkdir -p /app/logs && chown appuser:appgroup /app/logs
# التبديل إلى مستخدم غير root
USER appuser
# متغيرات البيئة (افتراضيات، التجاوز وقت التشغيل)
ENV FLASK_ENV=production \
LOG_LEVEL=info \
APP_PORT=5000
EXPOSE 5000
# فحص الصحة
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
# بدء التطبيق
CMD ["python", "app.py"]
(2) .dockerignore
TEXT
📖 للعرض فقط
# .dockerignore
__pycache__
*.pyc
*.pyo
.git
.env
venv
.venv
*.md
Dockerfile
docker-compose*.yml
5. إدارة إعدادات البيئة
(1) تسلسل متغيرات البيئة
| المستوى | الطريقة | الأولوية | السيناريوهات المطبقة |
|---|---|---|---|
| Dockerfile ENV | القيمة الافتراضية | الأدنى (1) | الإعدادات الافتراضية العامة |
| docker run -e | تجاوز وقت التشغيل | متوسط (2) | إعدادات النشر |
| ملف .env | --env-file |
الجزء 3 | إدارة متغيرات متعددة |
| Docker Secrets | --secret |
الأعلى | المعلومات الحساسة |
▶ مثال: إعداد متغيرات البيئة (الصعوبة: ⭐⭐)
BASH
# التشغيل مع متغيرات بيئة مخصصة
docker run -d \
--name todo-app \
-e FLASK_ENV=production \
-e DATABASE_URL="postgresql://appuser:apppass@todo-db:5432/tododb" \
-e LOG_LEVEL=warning \
-p 5000:5000 \
todo-app:1.0
▶ مثال: استخدام ملف .env (الصعوبة: ⭐⭐)
BASH
# إنشاء ملف .env
cat > .env << 'EOF'
FLASK_ENV=production
DATABASE_URL=postgresql://appuser:apppass@todo-db:5432/tododb
LOG_LEVEL=warning
APP_PORT=5000
EOF
# التشغيل بـ --env-file
docker run -d \
--name todo-app \
--env-file .env \
-p 5000:5000 \
todo-app:1.0
6. استمرارية السجلات
▶ مثال: إعداد استمرارية السجلات (الصعوبة: ⭐⭐)
BASH
# تركيب وحدة تخزين مسماة لسجلات التطبيق
docker run -d \
--name todo-app \
-v app-logs:/app/logs \
-e LOG_LEVEL=info \
todo-app:1.0
(1) مقارنة سياسات التسجيل
| الحل | المزايا | العيوب |
|---|---|---|
| التسجيل داخل الحاوية | بسيط | يُفقد عند حذف الحاوية |
| استمرارية وحدة التخزين | يستمر بعد حذف الحاوية | يجب إدارة تدوير السجلات يدويًا |
| stdout + برنامج تشغيل السجل | إدارة Docker الأصلية | إعدادات معقدة |
| التسجيل المركزي (ELK/Loki) | قابلية بحث كاملة | يتطلب بنية تحتية إضافية |
7. وسوم الصور وإدارة الإصدارات
(1) استراتيجية الوسم
| الاستراتيجية | تنسيق الوسم | مثال | السيناريوهات المطبقة |
|---|---|---|---|
| الترقيم الدلالي | vرئيسي.ثانوي.تصحيح |
v2.1.0 |
إصدار الإنتاج |
| Git SHA | sha-<commit> |
sha-a1b2c3d |
تتبع CI/CD |
| latest | latest |
latest |
التطوير/البدء السريع |
| اسم الفرع | <branch> |
main, dev |
بيئة التطوير |
▶ مثال: الدفع بوسوم متعددة (الصعوبة: ⭐⭐)
BASH
# البناء بوسوم متعددة
docker build -t todo-app:v1.0.0 -t todo-app:latest .
# دفع جميع الوسوم
docker push localhost:5000/todo-app:v1.0.0
docker push localhost:5000/todo-app:latest
8. نشر المجموعة الكاملة
▶ مثال: نشر Flask + PostgreSQL + Nginx بنقرة واحدة (الصعوبة: ⭐⭐⭐)
BASH
# ============================================
# برنامج نشر بنقرة واحدة
# ============================================
# 1. إنشاء الشبكة ووحدات التخزين
docker network create todo-net
docker volume create pg-data
docker volume create app-logs
# 2. بدء PostgreSQL
docker run -d \
--name todo-db \
--network todo-net \
-e POSTGRES_USER=appuser \
-e POSTGRES_PASSWORD=apppass \
-e POSTGRES_DB=tododb \
-v pg-data:/var/lib/postgresql/data \
--restart=unless-stopped \
postgres:15-alpine
# 3. انتظار تهيئة PostgreSQL
sleep 15
# 4. بناء وبدء تطبيق Flask
docker build -t todo-app:1.0 ./todo-app
docker run -d \
--name todo-app \
--network todo-net \
-e DATABASE_URL="postgresql://appuser:apppass@todo-db:5432/tododb" \
-v app-logs:/app/logs \
--restart=unless-stopped \
todo-app:1.0
# 5. بدء وكيل Nginx العكسي
docker run -d \
--name todo-nginx \
--network todo-net \
-p 80:80 \
-v $(pwd)/todo-app/nginx.conf:/etc/nginx/conf.d/default.conf \
--restart=unless-stopped \
nginx:1.25-alpine
# 6. التحقق
docker ps
curl http://localhost/health
9. نتائج التحقق والتحسين
(1) التحقق من التحسين باستخدام dive
BASH
# تحليل الصورة متعددة المراحل
dive todo-app:1.0
# المتوقع: درجة الكفاءة > 90%، بدون مساحة مهدرة
(2) مقارنة أحجام الصور
| الإصدار | Dockerfile | حجم الصورة | وقت البناء |
|---|---|---|---|
| V1 مرحلة واحدة | FROM python:3.12 + COPY . . + RUN pip install |
1.2 جيجابايت | 5 دقائق |
| V2 صورة أساسية محسنة | FROM python:3.12-slim + تنظيف الذاكرة المؤقتة |
350 ميجابايت | 3 دقائق |
| V3 متعدد المراحل | builder + slim + غير root + HEALTHCHECK | 150 ميجابايت | 3 دقائق (30 ثانية مع إصابة الذاكرة المؤقتة) |
10. مثال كامل: تحويل تطبيق قائمة المهام إلى حاويات
BASH
# ============================================
# شرح كامل: تحويل تطبيق Flask إلى حاويات
# يغطي: Dockerfile، بناء، نشر متعدد الحاويات
# ============================================
# 1. بناء الصورة المحسنة
docker build -t todo-app:v1.0.0 -t todo-app:latest ./todo-app
# 2. التحقق من الصورة
docker images todo-app
docker history todo-app:v1.0.0
# 3. إنشاء البنية التحتية
docker network create todo-net
docker volume create pg-data
docker volume create app-logs
# 4. بدء PostgreSQL مع تخزين دائم
docker run -d \
--name todo-db \
--network todo-net \
-e POSTGRES_USER=appuser \
-e POSTGRES_PASSWORD=apppass \
-e POSTGRES_DB=tododb \
-v pg-data:/var/lib/postgresql/data \
--restart=unless-stopped \
postgres:15-alpine
# 5. بدء تطبيق Flask
docker run -d \
--name todo-app \
--network todo-net \
-e DATABASE_URL="postgresql://appuser:apppass@todo-db:5432/tododb" \
-v app-logs:/app/logs \
--restart=unless-stopped \
todo-app:v1.0.0
# 6. بدء وكيل Nginx العكسي
docker run -d \
--name todo-nginx \
--network todo-net \
-p 8080:80 \
-v $(pwd)/todo-app/nginx.conf:/etc/nginx/conf.d/default.conf \
--restart=unless-stopped \
nginx:1.25-alpine
# 7. التحقق من المجموعة الكاملة
echo "=== الحاويات ===" && docker ps
echo "=== فحص الصحة ===" && docker inspect todo-app --format='{{.State.Health.Status}}'
echo "=== استجابة التطبيق ===" && curl -s http://localhost:8080/health
# 8. الدفع إلى المستودع الخاص (اختياري)
docker tag todo-app:v1.0.0 localhost:5000/todo-app:v1.0.0
docker push localhost:5000/todo-app:v1.0.0
# 9. التنظيف (اختياري)
# docker stop todo-nginx todo-app todo-db
# docker rm todo-nginx todo-app todo-db
❓ أسئلة شائعة
س هل الحاوية الواحدة تشغل عملية واحدة؟
ج أفضل ممارسة هي "حاوية واحدة، عملية واحدة" — حاوية لتطبيق Flask، وأخرى لـ Nginx، وأخرى لـ PostgreSQL. الفوائد: توسع مستقل، تحديثات مستقلة، وعزل الأعطال. مثال مضاد: إذا شغلت حاوية واحدة Nginx و Flask و PostgreSQL، فإن تعطل أي مكون يؤدي إلى تعطل النظام بأكمله، ولا يمكن التوسع المستقل.
س هل يجب كتابة ملفات السجل داخل الحاوية أم في وحدة تخزين مركبة؟
ج مزيج من كلا النهجين: ① التطبيق يكتب إلى stdout (يمكن عرضه بـ
docker logs) وإلى ملف (مستمر في وحدة تخزين مركبة)؛ ② في بيئة الإنتاج، نوصي باستخدام stdout مع جمع مركزي للسجلات (ELK/Loki)، وعدم الكتابة في الملفات بعد الآن. النهج القائم على وحدة التخزين المغطى في هذا الدرس هو حل وسيط.س كيف أميز بين بيئات التطوير والإنتاج أثناء عملية البناء؟
ج هناك ثلاث طرق: ① ARG + RUN شرطي (غير موصى به، لأنه يجعل Dockerfile أكثر تعقيدًا)؛ ② Dockerfiles متعددة (Dockerfile.dev / Dockerfile.prod)؛ ③ بناء متعدد المراحل + اختيار --target (موصى به). في هذا الدرس، سنستخدم متغيرات ENV لتعيين القيم الافتراضية وتجاوزها بـ
docker run -e.س كيف تدار أرقام إصدارات الصور؟
ج الترقيم الدلالي (SemVer): الإصدار الرئيسي.الإصدار الثانوي.رقم البناء (مثال: v2.1.0). في CI/CD، تُطبق أيضًا وسوم Git SHA (مثال: sha-a1b2c3d) لتسهيل التتبع. وسم
latest يشير دائمًا إلى أحدث إصدار مستقر، لكن في بيئات الإنتاج، استخدم رقم الإصدار الدقيق بدلاً من latest.س كيف أعين المنطقة الزمنية للحاوية؟
ج هناك طريقتان: ①
docker run -e TZ=Asia/Shanghai (يتطلب تثبيت tzdata على الصورة الأساسية)؛ ② -v /etc/localtime:/etc/localtime:ro (يستخدم المنطقة الزمنية للمضيف مباشرة). صورة Alpine تتطلب RUN apk add --no-cache tzdata لدعم متغير TZ.📖 ملخص
- بناء متعدد المراحل: تُنشأ البيئة الافتراضية أثناء مرحلة البناء، ومرحلة التشغيل تنسخ البيئة الافتراضية فقط؛ ينخفض حجم الصورة من 1.2 جيجابايت إلى 150 ميجابايت
- إدارة هرمية لمتغيرات البيئة: Dockerfile ENV (افتراضي) →
docker run -e(تجاوز وقت التشغيل) → ملف .env (متغيرات متعددة) - استمرارية السجلات: وحدة تخزين مسماة تُركب في /app/logs؛ تُحتفظ بالسجلات بعد إعادة تشغيل الحاوية أو إعادة بنائها
- فحوصات الصحة: curl /health endpoint؛ يكتشف Docker المشكلات تلقائيًا وينفذ سياسة إعادة التشغيل للشفاء الذاتي
- إدارة إصدارات الصور: الترقيم الدلالي + Git SHA + دفع متعدد الوسوم "latest"
- التشغيل كمستخدم غير root + HEALTHCHECK + استمرارية السجلات = العناصر الثلاثة الأساسية لـ Dockerfile على مستوى الإنتاج
📝 تمارين
- مهمة أساسية (الصعوبة: ⭐): استنسخ مشروع Flask/Express مفتوح المصدر، واكتب Dockerfile لبناء صورة، وشغلها.
- تمرين متقدم (الصعوبة: ⭐⭐): اكتب Dockerfile متعدد المراحل لهذا المشروع وقارن الفروق في حجم الصورة بين الصور أحادية المرحلة ومتعددة المراحل.
- تحدٍ (الصعوبة: ⭐⭐⭐): استخدم
diveلتحليل الصورة المحسنة، وحدد الطبقات التي يمكن تحسينها أكثر، ثم أصلحها وتحقق من الانخفاض في حجم الملف.