لماذا قائمة تحقق قبل الإنتاج
صُمِّم Docker Compose للتطوير: قيمه الافتراضية تفضِّل البساطة على المتانة. في التطوير لا تشكِّل هذه الإعدادات أي مشكلة. في الإنتاج تتحول إلى حوادث: قرص ممتلئ الساعة الثالثة فجرًا، قاعدة بيانات ضائعة بعد docker compose down، خدمة غير متاحة بعد انقطاع الكهرباء. البشرى: تقوية حزمة Compose لا تتطلب إعادة كتابة، بل عشر إضافات مستهدفة فحسب. مرر كل نقطة في هذه القائمة قبل الإطلاق وستصمد خدمتك أمام الأحمال وعمليات إعادة التشغيل بلا مراقبة مستمرة.
النقاط العشر بلمحة
- restart: unless-stopped — تُعاد الحاوية بعد إقلاع المضيف أو انهيارها
- healthcheck — يكتشف Docker حاوية عالقة ويتيح إعادة التشغيل التدريجي
- حدود المعالج والذاكرة — خدمة جامحة لا يمكنها خنق جيرانها
- الأسرار عبر .env أو Docker secrets — لا كلمة مرور بنص صريح
- وحدات تخزين مُسمَّاة — تنجو البيانات من
docker compose down - تدوير السجلات —
max-sizeوmax-fileيمنعان امتلاء القرص - عزل الشبكة — افصل
frontendوbackend - ربط المنافذ —
127.0.0.1:PORTخلف وكيل عكسي، لا0.0.0.0 - وسوم صور مثبَّتة — نسخة أو بصمة، لا
latest - depends_on مع شرط —
service_healthyيتجنب سباقات الإقلاع
المتطلبات المسبقة
تحتاج إلى خادم VPS عليه Docker Engine وإضافة Compose v2. الأمر هو docker compose بلا شرطة: تحقق منه عبر docker compose version، لأن صيغة deploy.resources خارج Swarm تتطلب Compose v2 (أما docker-compose القديم فنتناوله أدناه). افحص المحرك أيضًا عبر docker version. يصحِّح Docker Engine 29.7.2 الثغرة CVE-2026-17106 (CopyEscape)، وهي حالة تسابق في docker cp أُفصح عنها في 10 أغسطس 2026: تستطيع حاوية غير موثوقة عبرها الكتابة فوق ملف على المضيف، بما في ذلك الملف التنفيذي runc. على أجهزة العمل، وصل التصحيح في Docker Desktop 4.86.0. وإلى أن تُحدِّث، لا تشغِّل docker cp من حاوية لا تتحكم في محتواها. ضع المشروع في مجلد مخصص (/opt/myapp) مع ملف .env بصلاحيات chmod 600. خطِّط لوكيل عكسي في المقدمة — Traefik أو Caddy أو Nginx — لأن ربط المنافذ يفترض ألا تصل الحركة العامة إلى حاوياتك مباشرة، واحفظ ملف Compose تحت إدارة الإصدارات.
الخطوات العشر المفصَّلة
1. سياسة إعادة التشغيل
أضف
restart: unless-stoppedإلى كل خدمة. تُعاد الحاوية بعد انهيار أو إقلاع المضيف، لكنها تبقى موقوفة إذا أوقفتها بإرادتك. تجنَّبrestart: alwaysالذي يُعيد تشغيل حتى حاوية أردتَ إيقافها، وفضِّلunless-stoppedللخدمات التطبيقية وon-failureللمهام الوقتية.2. الفحص الصحي
أعلن كتلة
healthcheck:معtestوinterval(مثلاً30s) وtimeout(مثلاً10s) وretries(مثلاً3). أضفstart_period: 40sللخدمات البطيئة في الإقلاع حتى لا تُعدَّunhealthyأثناء التهيئة. يُعلِّم Docker الحاوية بـhealthyأوunhealthyمما يتيح لـdepends_on: condition: service_healthyانتظار الجاهزية الفعلية.3. حدود الموارد
تحت
deploy.resources.limits، حدِّدcpusوmemory(مثلاًmemory: 512M). بلا حد تستطيع خدمة نازفة استهلاك كل الذاكرة وتُفعِّل قاتل OOM. أضفreservationsلضمان حد أدنى عند الإقلاع.4. الأسرار خارج الملف
لا تضع أبدًا كلمة مرور بنص صريح في YAML. أرجع إليها عبر
env_fileأوsecrets:الذي يُحمِّل الأسرار كملفات تحت/run/secrets/داخل الحاوية، بعيدًا عنdocker inspect. أضف.envإلى.gitignore.5. وحدات التخزين المُسمَّاة
أعلن بياناتك في وحدات تخزين مُسمَّاة بمشغِّل صريح. وحدة التخزين المسمَّاة تنجو من
docker compose down؛ يمحوها فقطdown -v. وثِّق كل وحدة تخزين واربطها باستراتيجية استرداد مختبَرة.6. تدوير السجلات
أضف
logging:معdriver: json-fileوخياريَّيmax-sizeوmax-file. بلا هذا تملأ سجلات حاوية ثرثارة القرص حتى العطل. طبِّقه على كل خدمة.7. عزل الشبكة
أنشئ شبكات مُسمَّاة
frontendوbackendوأرفق كل خدمة فقط بما تحتاجه. أضفinternal: trueعلى شبكةbackendلمنع أي وصول من المضيف أو الإنترنت.8. ربط المنافذ
انشر على
127.0.0.1:8080:8080لا8080:8080خلف وكيل عكسي. Docker يعدِّل قواعد iptables مباشرة وقد يتجاوز UFW — ربط127.0.0.1هو الضمان الوحيد الموثوق.9. وسوم الصور المثبَّتة
استبدل
latestبنسخة محددة أو بصمة. استخدمpull_policy: missingلسلوك متوقع: لا يسحب Compose صورة جديدة إلا إذا كانت غائبة محليًا.10. ترتيب الإقلاع
استخدم
depends_onمعcondition: service_healthy. للخدمات التي لا تدعم فحصًا صحيًا أصليًا، استخدمcondition: service_startedمع سكريبت انتظار مثلwait-for-it.sh.
إعدادات التطوير مقابل الإنتاج
مرّر الجدول أفقيًا
| الإعداد | افتراضي التطوير | موصى به للإنتاج |
|---|---|---|
| restart | no | unless-stopped |
| healthcheck | غائب | مُعرَّف بفترة ومحاولات |
| الذاكرة | بلا حد | حد محدد |
| الأسرار | نص صريح ممكن | .env أو Docker secrets |
| وحدات التخزين | مجهولة | مُسمَّاة |
| السجلات | بلا حد | max-size + max-file |
| الشبكة | الجسر الافتراضي | frontend / backend |
| المنافذ | 0.0.0.0 | 127.0.0.1 خلف وكيل |
| الصورة | latest | نسخة أو بصمة |
| depends_on | الإطلاق فقط | condition: service_healthy |
docker-compose أم docker compose: قطيعة Ubuntu 26.04
أداتان تحملان الاسم نفسه تقريبًا. docker-compose بالشرطة هي Compose v1 المكتوبة بلغة Python: يعلن مستودعها انتهاء عمرها منذ الإتاحة العامة لـCompose v2 التي أعلنتها Docker في 26 أبريل 2022. وdocker compose بمسافة هي Compose v2 المكتوبة بلغة Go والمدمجة في واجهة Docker كإضافة. يُكمل Ubuntu 26.04 هذا الانتقال: الحزمة docker-compose لم تعد في الأرشيف منذ Ubuntu 25.10، والحزمة docker-compose-v2 لا تثبِّت سوى الإضافة في /usr/libexec/docker/cli-plugins/. بعد الترقية، يتوقف كل سكربت ما زال يستدعي الاسم القديم عند الرسالة docker-compose: command not found. وفي التكامل المستمر، أخرجت GitHub إصدار Compose v1 من مشغلاتها المستضافة في 9 يوليو 2024، وتنقل ubuntu-latest إلى Ubuntu 26.04 بين 19 أكتوبر و19 نوفمبر 2026: سير العمل الذي كان يثبِّت docker-compose يدويًا يحتاج إلى مراجعة. هناك فرقان موثَّقان في السلوك. أسماء الحاويات تستعمل الشرطة بدل الشرطة السفلية (myapp-web-1 مقابل myapp_web_1)، إلا مع --compatibility. والمفتاح version: يُتجاهَل مع التحذير «the attribute version is obsolete, it will be ignored».
ترحيل السكربتات وإضافة shim
- الجرد — الأمر
grep -rnE 'docker-compose( |$)' /opt /etc/cron* /etc/systemd ~/.bashrcيسرد الاستدعاءات التي يجب تصحيحها. - السكربتات وMakefile — استبدل الشرطة بمسافة (
docker compose up -d)؛ الأوامر الفرعية المعتادة لا تتغير. - cron وsystemd — استدعِ
/usr/bin/docker composeبمسار مطلق، لأن cron يعمل بمتغيرPATHمختصر. - GitHub Actions — اختبر سير العمل عبر
runs-on: ubuntu-26.04قبل التحويل، أو ثبِّتubuntu-24.04ريثما تصحِّحه، كما توصي GitHub. - Shim مؤقت — ملف تنفيذي
/usr/local/bin/docker-composeمن سطرين،#!/bin/shثمexec docker compose "$@"، يلتقط الاستدعاءات المنسية. وتصون Docker أيضًا الأداةcompose-switchالتي تترجم صيغة v1 إلى v2. - أسماء الحاويات — استبدل
docker exec myapp_web_1المكتوب يدويًا بـdocker compose exec webالذي لا يعتمد على الفاصل. - التحقق —
docker compose versionيجيب، وdocker compose configيمر بلا تحذير، وcommand -v docker-composeلا يشير إلا إلى الـshim.
الفحوصات الصحية المتقدمة: مراقبة الحالة الفعلية للخدمة
فحص صحي جيد التهيئة يتجاوز curl البسيط: يقيس الحالة الوظيفية للخدمة لا مجرد التوافر الشبكي. لواجهة برمجية HTTP اختبر نقطة نهاية خفيفة (/health أو /ready) تُعيد 200 فقط إذا كان اتصال قاعدة البيانات قائمًا. لـPostgreSQL استخدم pg_isready -U postgres. لـRedis يكفي redis-cli ping. تحقق من حالة حاوياتك بـdocker compose ps: العمود STATUS يعرض healthy أو unhealthy أو starting. حاوية عالقة في starting لأطول من start_period تشير إلى مشكلة تهيئة — راجع docker compose logs service لمعرفة السبب. المعامل start_period مستقل عن interval: يحدد نافذة سماح لا تُحسب فيها الإخفاقات ضمن retries، وهو ضروري للخدمات التي تحتاج وقتًا للترحيل أو التعبئة.
Docker secrets بدون Swarm: تحميل الملفات في /run/secrets/
خارج Swarm، يقبل Compose الأسرار من نوع الملف. أعلن السر في قسم secrets: بمستوى الجذر مشيرًا إلى ملف محلي (file: ./secrets/db_password.txt)، ثم أشر إليه في الخدمة عبر secrets: [db_password]. يُحمِّل Docker هذا الملف للقراءة فقط في /run/secrets/db_password: يقرؤه التطبيق كملف عادي، ولا تظهر قيمته في متغيرات البيئة التي يعرضها docker inspect ولا في السجلات. للتدوير، أعطِ السر رقم إصدار: أنشئ db_password_v2 بجانب db_password_v1، واجعل الخدمة تقرأ v2، وأعد نشرها وحدها عبر docker compose up -d --no-deps service، ثم احذف v1 بعد التحقق من النشر. يقتصر الانقطاع على إعادة إنشاء هذه الحاوية، ويبقى السر القديم متاحًا للتراجع.
التراجع: العودة إلى الوراء بعد نشر فاشل
التراجع عن حزمة Compose يُجهَّز قبل النشر لا بعد الحادثة. احتفظ بالصورة السابقة موسومة ومتاحة محليًا: أضف وسمًا صريحًا myapp:stable قبل كل تحديث. للتراجع، أعد الوسم القديم في ملف Compose (أو في ملف .env إن كان الإصدار متغيرًا)، ثم أعد تشغيل docker compose up -d. لا تتأثر وحدات التخزين بتغيير الصورة، مما يجعل التراجع التطبيقي سريعًا؛ أما ترحيل المخطط فيحتاج إلى ترحيل عكسي جاهز قبل النشر. للإصدارات الحرجة، افصل بين docker-compose.yml (النسخة المستقرة) وdocker-compose.override.yml (النسخة المرشحة): الأمر docker compose -f docker-compose.yml up -d يتجاهل ملف التجاوز ويعود إلى الحالة المستقرة.
اختبر دائمًا حزمتك المقوَّاة محليًا: docker compose config للتحقق من البنية، ثم محاكاة الإقلاع بـdocker compose restart. تأكد أن الحاويات تعود healthy وأن البيانات تستمر بعد down يعقبه up.
استكشاف الأخطاء: 6 أخطاء شائعة وحلولها
docker: unknown command: docker compose: إضافة Compose غير مثبتة. على Ubuntu، ثبِّت docker-compose-v2 من الأرشيف، أو docker-compose-plugin إن كان Docker مثبتًا من المستودع الرسمي لـDocker، ثم تحقق عبر docker compose version. network not found: بعد docker compose down تُحذف الشبكات المسمَّاة. الحل: أعلن الشبكات المشتركة بـexternal: true أو زامن إعادة تشغيل الحزم التابعة. port is already in use: عملية أخرى تشغل المنفذ. حدِّدها بـss -tlnp | grep :PORT ثم أوقفها. OOM: النواة تقتل حاوية بلا إنذار — ابحث عن OOMKilled: true في docker inspect container_id. ارفع حد الذاكرة أو حدِّد التسريب بـdocker stats. permission denied on volume: العملية تعمل بـUID لا يملك صلاحية الوصول. تحقق من UID بـdocker compose exec service id ثم عدِّل الأذونات. حاوية تُعاد في حلقة: docker compose logs --tail=50 service يكشف خطأ الإقلاع. الأسباب الشائعة: متغير بيئة مفقود، ملف إعداد غير موجود، أو تبعية غير جاهزة.
نسخ الأحجام احتياطيًا دون تلف
نسخ ملفات حجم PostgreSQL أو MySQL أثناء تشغيلها بـrsync أو tar ينتج نسخة تالفة. القاعدة: دائمًا pg_dump أو mysqldump قبل لقطة الحجم. أدوات مثل Restic وOffen Docker Backup تُنظِّم هذا تلقائيًا.
الخاتمة
تحوِّل هذه الإعدادات العشرة ملف Compose تطويريًا إلى حزمة تصمد أمام إعادة التشغيل وذروات الحمل والليالي بلا مراقبة. الفحوصات الصحية، والأسرار المحمَّلة كملفات، والتراجع المجهَّز مسبقًا، والانتقال الكامل إلى docker compose تُكمل هذا الأساس. لا يتطلب شيء من ذلك أداة إضافية: كل شيء في ملفات YAML والسكربتات التي لديك بالفعل. راجع القائمة قبل كل إطلاق، مثلًا عبر مراجعة docker compose config مدمجة في النشر. يمكنك بعدها إضافة وكيل عكسي مثل Traefik أو Caddy، أو طبقة تنسيق مثل Coolify.