3.4 · المتغيرات والملفات الشخصية (profiles) والتراكبات حسب البيئة

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

3.4المتغيرات والملفات الشخصية (profiles) والتراكبات حسب البيئة

الهدف: صرف كومبوز في التطوير / الإنتاج دون تكرار الملف.
الوقت المقدّر: 12 دقيقة · قراءة ذاتية · إذا كان لديك 5 دقائق فقط: اقرأ «الأساسي في 30 ثانية» + المخطط.

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

  • الـ .env : قيمة واحدة، ووجوه عدة : يقرأ ${PORT:-3000} المتغير أو افتراضيه — ملف .env واحد لكل بيئة، وكومبوز واحد لأوجه N.
  • التراكبات : قاعدة + نسخة : compose.override.yml مُحمَّل تلقائيا في التطوير، و-f compose.yml -f compose.prod.yml في الإنتاج — ولا يصف كل ملف سوى فرقه.
  • الملفات الشخصية : خدمات اختيارية : profiles: [dev] يجعل adminer غائبا افتراضيا، وحاضرا مع --profile dev — فالستاك الافتراضي أدنى وآمن.

حالة مصغرة مسلسلة — إدير يوحد التطوير والإنتاج

إدير، ديفوبس مبتدئ في الجزائر، يصون compose.yml منسوخين (التطوير مع adminer، والإنتاج دونه) — فيتباعدان، ويوما ما تغادر وحدة تحكم التطوير إلى الإنتاج. يعيد التأسيس : قاعدة وحيدة مع ${PORT:-3000}، و adminer تحت profiles: [dev]، و .env لكل بيئة غير مُلتزَم به. التطوير : --profile dev up -d ؛ والإنتاج : up -d، مقتصد افتراضيا. مصدر حقيقة واحد، ووجهان — فلا يحتوي الإنتاج أبدا أدوات التطوير.

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

1. الاستيفاء و .env : ضبط دون تكرار

في compose.yml، يقرأ ${PORT:-3000} المتغير PORT أو 3000 افتراضيا : فيصبح كومبوز قابلا للضبط. ويثبت ملف .env بجانب كومبوز القيم حسب البيئة (التطوير : منافذ منشورة + adminer ؛ والإنتاج : قيم أخرى، ولا adminer) — ويُحمَّل تلقائيا. ملف واحد، وأوجه N : الصورة نفسها، والبنية نفسها، وقيم تتغير.

قاعدة النظافة : فالـ .env المحتوي أسرارا لا يُلتزَم به أبدا — بل نُصدِر .env.example وهميا يوثق المفاتيح المنتظرة. وتُختار الافتراضيات ${X:-…} آمنة للإنتاج : فدون متغير، يبدأ الستاك في شكله الأكثر تقتيرا، لا الأكثر انفتاحا.

2. التراكبات -f والملفات الشخصية : النسخ والاختيار

التراكبات (SURCHARGES) : نحتفظ بـ compose.yml قاعدة ونضيف النسخ — compose.override.yml، المُحمَّل تلقائيا في التطوير (تركيبات ربط، وتنقيح)، أو compose.prod.yml المنادَى صراحة (-f compose.yml -f compose.prod.yml). ولا يصف كل ملف سوى فرقه ؛ ومن اليسار إلى اليمين، كل -f يتراكب على سابقه. انتهى التكرار الكامل حسب البيئة.

الملفات الشخصية (PROFILS) : فـ profiles: [dev] على adminer يجعله اختياريا — غائبا افتراضيا، وحاضرا مع --profile dev. انتهى « نسيت إزالة وحدة التحكم في الإنتاج » : فالستاك افتراضيا أدنى وآمن، وأدوات التطوير تُفعَّل صراحة. قاعدة دنيا، وخيارات في ملفات شخصية، وافتراضي آمن للإنتاج.

خطأ شائع في الفهم: « كومبوز لكل بيئة أوضح، ويمكن أن تبقى ملفات dev الشخصية نشطة افتراضيا ». لا، مرتين. فملفان منسوخان يتباعدان — ويجب حمل كل تصحيح مرتين، ويوما ما تغادر وحدة تحكم التطوير إلى الإنتاج. والملف الشخصي النشط افتراضيا لم يعد ملفا شخصيا : فالاختيار لا يوجد إلا إذا كان الافتراضي مقتصدا. قاعدة واحدة، وتراكبات، واختيارات.
الصرف دون تكرار القاعدة والقيم والنسخ والاختيار قاعدة مُصدَرةcompose.yml ‏+ ${VAR:-افتراضي آمن للإنتاج}+قيم حسب البيئة.env محلي غير مُلتزَم به + .env.example+نسخ + اختيارتراكبات -f، و override التطوير، و profiles افتراضيا : أدنى وآمن ؛ والتطوير يُفعَّل صراحة.
القاعدة والقيم والنسخ والاختيار
نص المخطط (SEO / قارئات الشاشة / الترجمة): 1) القاعدة : يكتب إدير كومبوز وحيدا مع ${PORT:-3000} بدل ملفين منسوخين. 2) القيم : .env لكل بيئة غير مُلتزَم به، و .env.example مُصدَر، وافتراضيات آمنة للإنتاج. 3) النسخ : override تلقائي في التطوير، و -f الإنتاج صريح، و adminer في الملف الشخصي dev — ومقتصد افتراضيا. الدرس : قاعدة واحدة، وقيم، وفروق في تراكب.

🔎 مثال ملموس — تطوير غني وإنتاج مقتصد : القاعدة نفسها والوجهان

يضبط إدير المنفذ، ويضع adminer في الملف الشخصي dev، ويطلق كل بيئة.

# compose.yml (قاعدة)
services:
  api:
    build: ./api
    ports: ["${PORT:-3000}:3000"]
    networks: [appnet]
  adminer:
    image: adminer:4.8
    profiles: [dev]
    ports: ["8081:8080"]
    networks: [appnet]
networks:
  appnet:
# .env (التطوير، غير مُلتزَم به) : PORT=3000
# التطوير : docker compose --profile dev up -d
# الإنتاج : PORT=80 docker compose up -d

القراءة : القاعدة نفسها، و adminer فقط في التطوير، والمنفذ بمتغير.

الدرس : فلا يحتوي الإنتاج أبدا أدوات التطوير — ومقتصد افتراضيا.

مفردات القسم

الاستيفاء (Interpolation)
يُحَل ${VAR:-افتراضي} من البيئة أو .env : كومبوز قابل للضبط.

مثال بسيط: الـ ${PORT:-3000} الخاص بإدير، 3000 دون متغير.

ما ليس كذلك: منفذ ثابت مكرر في ملفين.

رد فعل: افتراضي آمن للإنتاج بعد كل :-.

التراكب (Surcharge)
ملف -f إضافي يعدل القاعدة : كل -f يتراكب على سابقه، من اليسار إلى اليمين.

مثال بسيط: -f compose.yml -f compose.prod.yml في الإنتاج.

ما ليس كذلك: كومبوز ثان منسوخ متطابق 95 %.

رد فعل: كل نسخة لا تصف سوى فرقها.

override
تراكب التطوير (compose.override.yml) المُحمَّل تلقائيا : تركيبات حية وتنقيح، دون مساس القاعدة.

مثال بسيط: التركيبات الحية الخاصة بإدير في التطوير فقط.

ما ليس كذلك: تركيبات تطوير تتسرب إلى الإنتاج.

رد فعل: التطوير في override، ولا في القاعدة أبدا.

الملف الشخصي (Profil)
مجموعة اختيارية (profiles: [dev]) تُفعَّل مع --profile : خدمة غائبة افتراضيا.

مثال بسيط: Adminer حاضر فقط مع --profile dev.

ما ليس كذلك: وحدة تحكم التطوير تغادر إلى الإنتاج سهوا.

رد فعل: أدوات التطوير في ملفات شخصية، وستاك مقتصد افتراضيا.

.env
ملف قيم محلي بجانب كومبوز، يُحمَّل تلقائيا — وغير مُلتزَم به إذا احتوى أسرارا.

مثال بسيط: الـ .env الخاص بإدير مع PORT وكلمات سر محلية.

ما ليس كذلك: .env بأسرار مدفوع إلى المستودع.

رد فعل: صَدِّروا .env.example، ولا الأسرار أبدا.

في التطبيق — تطوير/إنتاج دون تكرار

  1. أضيفوا ${PORT:-3000} وملفا شخصيا dev ‏(adminer)‏ إلى كومبوز القاعدة خاصتكم.
  2. اطلقوا دون ملف شخصي : تحققوا من غياب adminer (ستاك مقتصد).
  3. أعيدوا الإطلاق مع --profile dev : يظهر adminer — اختيار صريح.
  4. غيروا PORT عبر البيئة وأعيدوا الإطلاق : فيتبع المنفذ، دون مساس الملف.
تخدم قاعدة واحدة كل البيئات : قيم حسب البيئة، وفروق في تراكب، وأدوات في اختيار.

نص جاهز للقول — تبرير القاعدة الوحيدة (30 ثانية)

« كومبوز قاعدة واحد : فالمنفذ يأتي من متغير، ووحدة تحكم التطوير من ملف شخصي اختياري، وفروق الإنتاج من تراكب. تطوير غني مع --profile dev، وإنتاج مقتصد افتراضيا — ولا ملف منسوخ يتباعد بعد، ولا أداة تطوير تتسرب إلى الإنتاج. »

يُقال في مراجعة البنية ؛ واعرضوا الفرق الفارغ بين التطوير والإنتاج.

نموذج نسخ-لصق — قاعدة مضبوطة + ملف dev الشخصي

# القاعدة : تطوير غني في اختيار، وإنتاج مقتصد افتراضيا.
services:
  api:
    build: ./api
    ports:
      - "${PORT:-3000}:3000"
    environment:
      DATABASE_URL: ${DATABASE_URL}
    networks:
      - appnet
  adminer:
    image: adminer:4.8
    profiles:
      - dev
    ports:
      - "8081:8080"
    networks:
      - appnet

networks:
  appnet:
# التطوير : docker compose --profile dev up -d
# الإنتاج : docker compose -f compose.yml -f compose.prod.yml up -d

مستقل

القاعدة + .env.example وكل عميل يصرف دون مساس الملف.

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

يوحد إدير التطوير والإنتاج : قاعدة واحدة، و .env اثنان، وصفر تباعد.

فريق منتج

افرضوا قاعدة دنيا + ملفات شخصية اختيارية + افتراضيات آمنة للإنتاج في الميثاق.

مبتدئ

هذا الأسبوع : متغير واحد ${PORT:-3000} + خدمة واحدة في ملف dev الشخصي.

حذر: ولا .env بأسرار مُلتزَم به أبدا : صَدِّروا .env.example وهميا، واحتفظوا بالقيم الحقيقية محليا (أو سر مُدار في الإنتاج). وتبقى الافتراضيات ${X:-…} آمنة للإنتاج — فالستاك دون متغير يبدأ مقتصدا، ولا مفتوحا أبدا.

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

  • أبقوا القاعدة دنيا، وضعوا الخيارات في ملفات شخصية اختيارية.
  • اختاروا افتراضيات آمنة للإنتاج بعد كل :- (${X:-…}).
  • صَدِّروا .env.example، ولا الأسرار الحقيقية أبدا.

✗ أخطاء شائعة

  • تكرار الملف كله حسب البيئة : فالنسخ تتباعد.
  • ملفات dev الشخصية نشطة افتراضيا : فلا يوجد اختيار بعد، وتتسرب وحدة التحكم إلى الإنتاج.
  • التزام .env بكلمات سر : سر مكشوف في السجل.

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

  • يجعل ${VAR:-افتراضي} كومبوز قابلا للضبط : ملف واحد وأوجه N.
  • التراكبات للفروق (-f، و override التطوير) : ولا تكرار أبدا.
  • الملفات الشخصية اختيارية للأدوات : غائبة افتراضيا، و --profile dev للتفعيل.
  • الافتراضي = إنتاج آمن ؛ و .env.example مُصدَر، والأسرار لا تُلتزَم أبدا.

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

ادمجوا كومبوز منسوخين اثنين في قاعدة واحدة + ملف dev شخصي واحد + تراكب واحد، وأثبتوا أن الإنتاج يبدأ مقتصدا.

قائمة الخروج من القسم
  • قاعدتي الوحيدة تخدم التطوير والإنتاج دون نسخ-لصق.
  • أدوات تطويري في اختيار، ومقتصدة افتراضيا.
  • أسراري خارج المستودع، وافتراضياتي آمنة للإنتاج.
تقييم ذاتي 1-5 : كم كومبوز شبه متماثل بقي عندي ؟هل يبدأ إنتاجي مقتصدا دون أي متغير ؟

أسئلة شائعة

أين نضع .env، وكيف نبقيه خارج المستودع ؟

بجانب compose.yml : يُحمَّل تلقائيا، وواحد لكل بيئة. وإذا احتوى أسرارا، فلا يُلتزَم به أبدا (أضيفوه إلى .gitignore) — وقدموا .env.example مُصدَرا بقيم وهمية توثق كل مفتاح. وفي الإنتاج، تأتي القيم من البيئة أو سر مُدار.

عدة -f، بأي ترتيب، و override أم prod ؟

من اليسار إلى اليمين : كل -f يتراكب على سابقه — القاعدة أولا، والنسخة بعدها (-f compose.yml -f compose.prod.yml). وcompose.override.yml هو الاستثناء : يُحمَّل تلقائيا (دون -f)، ويحمل التطوير (تركيبات ربط، وتنقيح). والقاعدة : التطوير = override تلقائي، والإنتاج = -f صريح، ولا يصف كل ملف سوى فرقه.

تحقّق من فهمك

يجب ألا يوجد Adminer إلا في التطوير. أي آلية ؟

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

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