3.1 · ملف compose.yml : الخدمات (services) والمنافذ (ports) والمجلدات (volumes)

المستوى 3 · دوكر كومبوز (Docker Compose)

3.1ملف compose.yml : الخدمات (services) والمنافذ (ports) والمجلدات (volumes)

الهدف: وصف تطبيق كامل (وب + قاعدة) في ملف compose.yml مقروء.
الوقت المقدّر: 14 دقيقة · قراءة ذاتية · إذا كان لديك 5 دقائق فقط: اقرأ «الأساسي في 30 ثانية» + المخطط.

الأساسي في 30 ثانية

  • صرّح بالحالة المطلوبة، لا بالأوامر : كل خدمة (service) لها صورتها (image) (أو بناؤها build)، ومنافذها، ومتغيراتها، ومجلداتها (volumes) وشبكتها (network) — كومبوز ينشئ كل شيء من هذا الملف المُصدَر.
  • خدمة واحدة = صورة + منافذ + بيئة + مجلدات : المنافذ (ports) بين علامتي تنصيص ("8080:80")، والمجلدات والشبكات تُصرَّح في الأسفل وتُنشَأ تلقائيا، وdepends_on لترتيب بدء التشغيل.
  • YAML : الإزاحة هي القانون : مسافات، ولا علامات جدولة أبدا، ومسافتان لكل مستوى — docker compose config يتحقق ويعرض الملف المحلول قبل أي إطلاق.

حالة مصغرة مسلسلة — إدير يستبدل أسطر الـ 200 حرف

إدير، ديفوبس مبتدئ في الجزائر، يطلق نموذج فريقه بسطري docker run من 200 حرف منسوخين من مذكرة — منفذ منسي، والعرض يفشل. يكتب compose.yml من 25 سطرا (وب + قاعدة، ومجلد مسمى، و depends_on)، ويتحقق منه مع docker compose config، ويلتزم به : من الآن، ملف واحد يُعتَمَد عليه وكل الفريق يطلق التطبيق نفسه. انتهت وثيقة « كيف نطلق » المروية من الذاكرة.

هذه الحالة نفسها تعود في الدرس والمخطط والنص الجاهز وتحدي 48 ساعة.

1. التصريح بدل الأمر : الملف الذي يُعتَمَد عليه

يستبدل كومبوز (Compose) أوامر docker run خاصتكم بملف مُصدَر : نصف فيه الحالة المطلوبة (الحالة المرغوبة) للتطبيق (أي خدمات، وأي منافذ، وأي مجلدات، وأي شبكات) وكومبوز ينشئ كل شيء — الشبكات والمجلدات والحاويات (containers) بالترتيب. انتهت أسطر الـ 200 حرف المنسوخة من الذاكرة : فـ compose.yml مُلتزَم به، ويُراجَع كالكود، وهو المُشغِّل الرسمي للتطبيق. إنه العبور من الفعل اليدوي إلى التصريحي.

كل خدمة (service) (وب، وقاعدة بيانات bdd، وذاكرة cache…) تصرح بصورتها (image) (أو بنائها (build) المحلي)، ومنافذها (ports) ("8080:80"، وعلامتا التنصيص واجبتان في YAML)، وبيئتها (environment)، ومجلداتها (volumes) (pgdata:/var/lib/postgresql/data) وشبكتها. وdepends_on يثبت ترتيب بدء التشغيل بين الخدمات. والمجلدات والشبكات تُصرَّح في الأسفل من الملف : ينشئها كومبوز تلقائيا عند أول up.

2. YAML : الإزاحة هي القانون، و config هو الحَكَم

يتكلم كومبوز YAML : مسافات ولا علامات جدولة أبدا، ومسافتان لكل مستوى، و« : » متبوعة بمسافة. فالغالبية الساحقة من أخطاء كومبوز تأتي من هنا : إزاحة مكسورة، ومنافذ دون علامتي تنصيص (8080:80 يُقرَأ عددا ستينيا !)، و« : » دون مسافة. اكتبوا ببطء، وأزيحوا بنظافة : فذلك 80 % من العمل.

المنعكس قبل كل إطلاق : docker compose config. يتحقق هذا الأمر من الملف ويعرض كومبوز المحلول — أو الخطأ الدقيق مع سطره. فإدير لا يطلق أبدا up على ملف غير مُتحقق منه : أولا config، ثم up. ملف واحد لكل تطبيق، مُلتزَم به، ومُتحقق منه : قابل لإعادة الإنتاج في كل مكان.

خطأ شائع في الفهم: « depends_on ينتظر حتى تجهز القاعدة، ويمكن كتابة المنافذ دون علامتي تنصيص ». لا، مرتين. فـ depends_on يرتب بدء التشغيل دون انتظار التوفر — والمتانة تأتي من فحوص الصحة (healthchecks) وإعادة المحاولة (retries) (المستوى 4). و 8080:80 دون علامتي تنصيص يقرؤه YAML عددا ستينيا : فالمنافذ تُقتبَس دائما. فالترتيب ليس انتظارا، والاقتباس ليس زخرفة.
وصف التطبيق بدل إصدار الأوامر الخدمات والمجلدات والشبكات والتحقق الخدماتصورة (image) + منافذ مُقتبَسة + بيئة + مجلدات + depends_on+المجلدات + الشبكاتمُصرَّح بها في الأسفل، وتُنشَأ تلقائيا+docker compose configيتحقق ويعرض المحلول قبل up ملف مُصدَر واحد يصف كل شيء : قابل لإعادة الإنتاج في كل مكان.
الخدمات والمجلدات والشبكات والتحقق
نص المخطط (SEO / قارئات الشاشة / الترجمة): 1) الخدمات : يصرح إدير بالوب (web) (صورة، ومنافذ مُقتبَسة) والقاعدة (bdd) (صورة، وكلمة سر في متغير، ومجلد) بدل سطري run. 2) القاعدة : مجلدات وشبكات مُصرَّح بها في الأسفل، وتُنشَأ تلقائيا عند أول up. 3) التحقق : يعرض docker compose config الملف المحلول أو الخطأ الدقيق قبل أي إطلاق. الدرس : نصرّح بالحالة المطلوبة، وكومبوز ينفذ — والملف المُلتزَم به يعوض الوثيقة.

🔎 مثال ملموس — وب + قاعدة في 25 سطرا، مُتحقق منه قبل الإطلاق

يكتب إدير أول ستاك (stack) وب + قاعدة له، وكلمة السر في متغير.

services:
  web:
    image: nginx:1.27
    ports: ["8080:80"]
    depends_on: [bdd]
    networks: [front]
  bdd:
    image: postgres:16.4
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes: [pgdata:/var/lib/postgresql/data]
    networks: [front]
volumes:
  pgdata:
networks:
  front:
# ثم : docker compose config (للتحقق)، وكلمة السر في .env غير مُلتزَم به.

القراءة : خدمتان، ومجلد دائم واحد، وشبكة واحدة، وترتيب بدء تشغيل.

الدرس : هذا الملف المُلتزَم به يعوض كل وثيقة « كيف نطلق ».

مفردات القسم

خدمة (Service)
حاوية (container) موصوفة في كومبوز (وب، وقاعدة bdd، وذاكرة cache) : صورة (image) أو بناء (build)، ومنافذ، ومتغيرات، ومجلدات، وشبكة.

مثال بسيط: خدمة الوب عند إدير (nginx، والمنفذ 8080 منشور).

ما ليس كذلك: سطر docker run منسوخ من الذاكرة.

رد فعل: دور تطبيقي واحد = خدمة واحدة مُصرَّح بها.

depends_on
ترتيب بدء التشغيل بين الخدمات : يطلق القاعدة قبل الوب، دون انتظار حتى تجهز.

مثال بسيط: الوب web يعتمد depends_on على bdd : تبدأ القاعدة أولا.

ما ليس كذلك: ضمان بأن القاعدة متوفرة.

رد فعل: رتب مع depends_on، ووثّق مع healthcheck وإعادة المحاولة.

مجلد كومبوز (Volume Compose)
مجلد مسمى مُصرَّح به في أسفل الملف ويُنشَأ تلقائيا : ديمومة البيانات.

مثال بسيط: المجلد pgdata مركب على /var/lib/postgresql/data.

ما ليس كذلك: بيانات سجينة حاوية زائلة.

رد فعل: كل بيانات تُحفَظ = مجلد مسمى.

config
أمر يتحقق من كومبوز ويعرض الملف المحلول — أو الخطأ الدقيق.

مثال بسيط: إدير يمرر config قبل كل up.

ما ليس كذلك: up أعمى على YAML مكسور.

رد فعل: أولا config، ثم up، دائما.

YAML
صيغة compose.yml المُزاحة : مسافات (ولا علامات جدولة أبدا)، و« : » + مسافة، والمنافذ بين علامتي تنصيص.

مثال بسيط: "8080:80" مُقتبَس، ومسافتان لكل مستوى.

ما ليس كذلك: علامات جدولة ومنافذ غير مُقتبَسة.

رد فعل: مسافات، اثنتان لكل مستوى، وعلامتا تنصيص على المنافذ.

في التطبيق — كتابة أول ستاك (stack) لكم

  1. أنشئوا مجلدا مع compose.yml وب + قاعدة أعلاه (كلمة السر في ${POSTGRES_PASSWORD}، و .env محلي غير مُلتزَم به).
  2. تحققوا منه مع docker compose config : اقرؤوا الملف المحلول المعروض.
  3. صححوا حتى صفر خطأ (الإزاحة، وعلامتا تنصيص المنافذ، و« : » + مسافة).
  4. التزموا بالملف : فهو من الآن مُشغِّلكم الرسمي، ويُراجَع كالكود.
تطبيقكم موصوف في ملف مُصدَر ومُتحقق منه : قابل لإعادة الإنتاج من كل الفريق.

نص جاهز للقول — عرض كومبوز على الفريق (30 ثانية)

« انتهت أسطر run من 200 حرف : فـ compose.yml واحد يصف وب + قاعدة — المنافذ والمجلد وترتيب بدء التشغيل — مُتحقق منه مع config ومُلتزَم به. كل واحد يطلق التطبيق نفسه تماما، دون مذكرة. »

يُقال في اجتماع الفريق ؛ واعرضوا المحلول config.

نموذج نسخ-لصق — ستاك وب + قاعدة صالح

services:
  web:
    image: nginx:1.27
    ports:
      - "8080:80"
    depends_on:
      - bdd
    networks:
      - front
  bdd:
    image: postgres:16.4
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - front

volumes:
  pgdata:

networks:
  front:
# .env محلي (غير مُلتزَم به) : POSTGRES_PASSWORD=<قيمة محلية>

مستقل

يكفي compose.yml مُتحقق منه مع config وعرضكم يطلق في كل مكان بتماثل.

مقاولة صغيرة في الجزائر

يلتزم إدير بالستاك وب + قاعدة : يطلق الفريق النموذج نفسه دون مذكرة.

فريق منتج

افرضوا config أخضر + التزام compose قبل كل عرض مشترك.

مبتدئ

هذا الأسبوع : ستاك وب + قاعدة مُتحقق منه بزر config، ثم مُلتزَم به.

حذر: كلمة سر القاعدة عبر .env المحلي، ولا تُكتَب أبدا ثابتة في compose المُلتزَم به : ${POSTGRES_PASSWORD} في الملف، والقيمة الحقيقية فقط في .env (غير المُصدَر، ويُقدَّم عبر .env.example).

✓ ممارسات جيدة

  • ضعوا المنافذ بين علامتي تنصيص في YAML ("8080:80")، منهجيا.
  • مرروا docker compose config قبل كل up، واقرؤوا المحلول.
  • ملف واحد لكل تطبيق، مُلتزَم به ويُراجَع كالكود.

✗ أخطاء شائعة

  • علامات الجدولة في YAML : مسافات فقط، اثنتان لكل مستوى.
  • منافذ دون علامتي تنصيص (8080:80 يصبح عددا ستينيا).
  • الاعتقاد بأن depends_on ينتظر حتى تجهز القاعدة (فلا يفعل سوى الترتيب).

النقاط الأساسية

  • كومبوز يصف الحالة المطلوبة، ودوكر ينفذ : والملف المُصدَر يعوض أسطر run.
  • خدمة (SERVICE) = صورة (أو بناء) + منافذ مُقتبَسة + بيئة + مجلدات + depends_on للترتيب.
  • YAML : مسافات، ولا علامات جدولة أبدا، و« : » + مسافة — 80 % من الأخطاء تأتي من هنا.
  • المجلدات (VOLUMES) والشبكات (RÉSEAUX) مُصرَّح بها في الأسفل، وتُنشَأ تلقائيا ؛ و config يتحقق قبل up.

تحدي 48 ساعة — طبّق غدا

استبدلوا إطلاقا يدويا واحدا بـ compose.yml مُتحقق منه (config) ومُلتزَم به، مع كلمة السر في متغير.

قائمة الخروج من القسم
  • تطبيقي موصوف في ملف مُصدَر واحد.
  • منافذي مُقتبَسة و YAML خاصتي دون علامات جدولة.
  • الـ config عندي أخضر قبل كل up.
تقييم ذاتي 1-5 : هل يطلق شخص آخر تطبيقي دون أن يسألني سؤالا ؟هل كل كلمة سر خارج الملف المُلتزَم به ؟

أسئلة شائعة

هل ينتظر depends_on حتى تجهز القاعدة ؟

لا : فـ depends_on يرتب بدء التشغيل (تبدأ القاعدة قبل الوب) دون انتظار توفرها. وإذا اتصل الوب مبكرا جدا، يفشل : فالمتانة تأتي من فحوص الصحة (healthchecks) وإعادة المحاولة التطبيقية (retries) (المستوى 4.2). احفظوا : الترتيب ≠ الانتظار. ولنموذج بسيط، تكفي إعادة إطلاق الوب ؛ ولستاك حقيقي، حلقة إعادة اتصال عند بدء التشغيل جهة التطبيق.

هل نُصدِر compose.yml، وأين نضع الأسرار ؟

نعم، دائما : فـ compose.yml هو المُشغِّل الرسمي للتطبيق، ويُراجَع كالكود ويُلتزَم به. ولا تظهر الأسرار فيه أبدا ثابتة : استعملوا متغيرات (${POSTGRES_PASSWORD}) المغذاة بـ .env محلي غير مُلتزَم به (أو سر مُدار في الإنتاج)، وصَدِّروا .env.example بقيم وهمية لتوثيق المفاتيح المنتظرة.

تحقّق من فهمك

ماذا يتحقق منه « docker compose config » قبل أي إطلاق ؟

موارد إضافية (اختياري، للتعمّق أكثر)

اختبار المستوى 3أسئلة جديدة وأصعب للتحقق من مكتسباتك