دليل عملي

تحديث stack Docker Compose في الإنتاج بأمان

النشر9 دقائق للقراءةعدد الخطوات: 5

أمر `docker compose pull` متبوعاً بـ `up -d` كان يعمل دائماً — حتى اليوم الذي توقف فيه. التغييرات الجذرية الأخيرة في Meilisearch‏ v1.54، وSupabase‏ PostgreSQL 15→17، وLangfuse‏ v3→v4، وNocoDB 2026.09 أثبتت ذلك بشكل مؤلم — خوادم إنتاج مستقرة منذ أشهر، تعطلت بعد تحديث غير مُعدَّ له. يمنحك هذا الدليل بروتوكولاً قابلاً للتكرار: احتفظ بنسخة احتياطية قبل السحب، تحقق من ملاحظات الإصدار قبل إعادة التشغيل، وارجع إلى الصورة السابقة في أقل من دقيقتين إذا حدث خطأ.

المحتويات· لماذا تُعدّ `latest` المشكلة الحقيقية1/9
  1. 01لماذا تُعدّ `latest` المشكلة الحقيقية
  2. 02ما يغطيه هذا الدليل — وما لا يغطيه
  3. 03الخطوة 1 — ثبّت جميع صورك
  4. 04بروتوكول التحديث — الخطوات الخمس
  5. 05احتفظ بالإصدار السابق متاحاً محلياً
  6. 06التغييرات الجذرية الأخيرة التي أوقفت تشغيل الخوادم
  7. 07استراتيجيات التحديث: مقارنة
  8. 08دمج هذا البروتوكول في سير عملك
  9. 09الأتمتة دون فقدان التحكم

لماذا تُعدّ `latest` المشكلة الحقيقية

عندما تُحدَّث صورة Docker المُوسَمة بـ latest في سجل الصور، يقوم docker compose pull بتنزيلها بصمت. لا تحذير، لا فرق. تُعيد تشغيل الـ stack فتكتشف أن الحاوية الجديدة لا تستطيع قراءة البيانات التي تركتها القديمة.

هذا بالضبط ما حدث مع Meilisearch‏ v1.54. قدّم هذا الإصدار تنسيق تخزين متجهات جديداً افتراضياً (الانتقال من arroy إلى HNSW) يجعل مجلد البيانات غير متوافق مع الإصدارات السابقة. عند بدء التشغيل، يرفض Meilisearch فتح قاعدة البيانات ويدخل في حلقة تعطل مستمرة. المسار الوحيد للخروج النظيف هو إنشاء dump قبل التحديث — وهو أمر مستحيل بمجرد أن تتوقف الحاوية.

وسم latest لا يحل إلى نفس الصورة بحسب وقت السحب. مطوران يُشغّلان docker compose pull بفارق اثنتي عشرة ساعة قد يسحبان إصدارين مختلفين. على stack إنتاجية، هذا الغموض غير مقبول. الحل ليس تجنب التحديثات: بل التحكم الصريح في الإصدار الذي يعمل والقرار الواعي بموعد الانتقال إلى الإصدار التالي.

ما يغطيه هذا الدليل — وما لا يغطيه

  • ما يغطيه هذا الدليل: بروتوكول خطوة بخطوة لتحديث stack‏ Docker Compose على VPS — تثبيت الإصدار، نسخ احتياطي للأقراص، مراجعة ملاحظات الإصدار، التراجع السريع، healthchecks كشبكة أمان.
  • مُغطى في أدلة أخرى: قائمة التدقيق الأولية (docker-compose-production-checklist)، وإعداد depends_on وservice_healthy (docker-compose-depends-on-healthcheck)، ومقارنة أدوات التحديث التلقائي كـ Watchtower أو Diun.
  • ما لا يوصي به هذا الدليل: Watchtower أو أي أداة auto-pull في الإنتاج — هذا هو بالضبط النمط المضاد الذي توضحه حالات التغييرات الجذرية.
  • الجمهور المستهدف: المطورون والوكالات التي تدير stack‏ واحدة أو أكثر من Docker Compose في الإنتاج على VPS، مع وصول root وأقراص بيانات دائمة.

الخطوة 1 — ثبّت جميع صورك

الإجراء الأول قبل أي تحديث هو استبدال كل image: meili/meilisearch:latest أو image: supabase/postgres بإصدار محدد.

شكلان مقبولان:

- وسم الإصدار: image: getmeili/meilisearch:v1.53.0 — مقروء، قابل للتتبع في git، سهل التصحيح.
- ملخص SHA256: image: getmeili/meilisearch@sha256:abc123… — ثابت، يضمن سحب نفس القطعة بالضبط في كل نشر، حتى لو أُعيدت كتابة الوسم.

للحصول على ملخص صورة تعمل بالفعل:

docker inspect --format='{{index .RepoDigests 0}}' getmeili/meilisearch:v1.53.0

بعد تثبيت صورك، احفظ ملف docker-compose.yml في git. كل رفع إصدار يصبح commit واحداً — سجل واضح وتراجع سهل (git revert + docker compose up -d).

بروتوكول التحديث — الخطوات الخمس

  1. اقرأ ملاحظات الإصدار قبل السحب

    أولاً، راجع ملاحظات الإصدار الجديد. ابحث عن كلمات breaking، migration، incompatible، pg_upgrade، dump. هذا ليس اختيارياً: وثّق Supabase صراحةً أن الترقية من PostgreSQL 15 إلى 17 تستلزم pg_upgrade يدوياً — حاوية PG 17 ترفض الإقلاع على قرص PG 15، وعملية التهيئة لا تُهجّر البيانات تلقائياً.

    بالنسبة لـ Langfuse‏ v4 (الإصدار العام بتاريخ 17 أغسطس 2026)، تُرفض SDK‏ Python v2 والإصدارات الأقدم عند الاستيعاب من طرف الـ stack الجديدة — تغيير جذري يؤثر على جميع الخدمات العميلة التي تتتبع عبر الـ API القديمة.

    ثلاث دقائق من القراءة توفر عليك ساعات من استعادة البيانات.

  2. احتفظ بنسخة احتياطية للأقراص قبل السحب

    لا تسحب أبداً قبل أن يكون لديك نسخة احتياطية صالحة للاستخدام. بالنسبة للأقراص المسماة، هناك مقاربتان:

    تصدير تطبيقي (موصى به لقواعد البيانات) — يجب أن تكون الخدمة في حالة healthy قبل التصدير:

    docker compose exec db pg_dump -U postgres -Fc mydb > backup_$(date +%Y%m%d_%H%M%S).dump

    لقطة قرص خام — مفيدة للتخزينات الثنائية (Meilisearch،‏ Redis، MinIO):

    docker run --rm \
      --volumes-from $(docker compose ps -q meilisearch) \
      -v $(pwd)/backups:/backup \
      alpine tar czf /backup/meili_$(date +%Y%m%d_%H%M%S).tar.gz /meili_data

    تحقق من أن النسخة الاحتياطية قابلة للقراءة قبل المتابعة. ملف dump تالف يُكتشف أثناء الاستعادة هو أكثر السيناريوهات تكلفةً.

  3. اسحب الصورة الجديدة واختبرها خارج الإنتاج

    حدّث الوسم في docker-compose.yml، ثم اسحب الصورة دون إعادة تشغيل الخدمة:

    docker compose pull meilisearch

    إذا أتاحت بيئتك ذلك، اختبر الصورة الجديدة على نسخة مستنسخة من القرص في بيئة ddev أو VM تجريبي قبل المساس بالإنتاج. تحقق من سجلات الإقلاع بحثاً عن أي أخطاء تهجير:

    docker compose up -d meilisearch
    docker compose logs -f meilisearch

    انتظر حتى يصل healthcheck إلى حالة healthy قبل التحقق من النجاح. خدمة تبدأ لكنها ليست healthy بعد ليست خدمة جاهزة.

  4. تحقق من healthchecks

    healthcheck مُهيَّأ جيداً هو خط الكشف الأول. يجب أن يكون موجوداً على كل خدمة حيوية في الـ stack، بصيغة Compose‏ v2:

    healthcheck:
      test: ["CMD-SHELL", "curl -sf http://localhost:7700/health || exit 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

    حقل start_period حاسم للخدمات التي تستغرق وقتاً في الإقلاع (قواعد البيانات، محركات البحث): يمنع Docker من إعلان الحاوية unhealthy أثناء مرحلة التهيئة وتشغيل إعادة تشغيل مبكرة.

    راجع docker-compose-depends-on-healthcheck للإعداد الكامل لـ service_healthy على PostgreSQL — نفس المبدأ ينطبق على أي خدمة تحتاج وقتاً للتهيئة.

  5. التراجع في حال حدوث مشكلة

    إذا فشل الإصدار الجديد في الإقلاع أو أنتج أخطاء، يجب أن يستغرق التراجع أقل من دقيقتين. الإجراء:

    1. عُد إلى الوسم السابق في docker-compose.yml (أو git revert إذا حفظت الرفع).
    2. أعِد تشغيل الخدمة المعنية فقط، دون إعادة إنشاء الأقراص:

    docker compose up -d --no-deps --force-recreate meilisearch

    3. تحقق من السجلات فوراً:

    docker compose logs -f meilisearch

    علامة --no-deps ضرورية: تُعيد تشغيل الخدمة المستهدفة دون المساس بالحاويات الأخرى (قاعدة البيانات، الذاكرة المؤقتة، الوكيل). بدونها، قد يُعيد docker compose up -d إنشاء الـ stack بأكملها.

    ⚠️ إذا هاجر الإصدار الجديد تنسيق البيانات على القرص (Meilisearch‏ v1.54، Supabase‏ PG17)، فإن التراجع عن الصورة وحده لا يكفي — وهذا بالضبط لماذا النسخة الاحتياطية للقرص شرط مسبق لا خيار.

احتفظ بالإصدار السابق متاحاً محلياً

قبل سحب الصورة الجديدة، قم بوسم الصورة الحالية في الإنتاج باسم احتياطي:

docker tag getmeili/meilisearch:v1.53.0 getmeili/meilisearch:rollback

يتيح لك ذلك العودة إلى الحالة الدقيقة للإنتاج في حالات الطوارئ، حتى إذا لم يعد لديك وصول إلى السجل أو كان الاتصال بطيئاً. على VPS بعرض نطاق ترددي محدود، يوفر لك هذا الوسم المحلي دقائق عدة من التنزيل في أسوأ وقت ممكن.

التغييرات الجذرية الأخيرة التي أوقفت تشغيل الخوادم

هذه الأمثلة الأربعة توضح لماذا البروتوكول أعلاه ليس نظرياً.

Meilisearch‏ v1.53 ‎→‎ v1.54 (2026): إدخال مخزن متجهات HNSW كتنسيق افتراضي. يرفض Meilisearch فتح فهرس أُنشئ بالتنسيق القديم arroy. يدخل الإقلاع في حلقة تعطل مع رسالة Your database version is incompatible with your current engine version. المخرج الوحيد النظيف هو تصدير dump قبل التحديث — استيراده في الإصدار الجديد يستعيد بياناتك.

Supabase‏ Docker PostgreSQL 15 ‎→‎ 17 (التهجير نشط منذ 17 يونيو 2026): حاوية supabase/postgres:17 لا تستطيع قراءة قرص أُهيِّئ بواسطة PG‏ 15. وثّق Supabase صراحةً أن هذه القفزة تستلزم pg_upgrade عبر سكريبت مخصص — عملية تهيئة الحاوية لا تفعل ذلك تلقائياً. دون تهجير مسبق، لا تبدأ قاعدة البيانات.

Langfuse‏ v3 ‎→‎ v4 (الإصدار العام 17 أغسطس 2026): تتخلى v4 عن نقاط النهاية القديمة لاستيعاب الدفعات لصالح OpenTelemetry. تُرفض SDK‏ Python v2 والأقدم وSDK‏ JS/TS v3 والأقدم عند الاستيعاب منذ لحظة إقلاع الـ stack‏ v4. إذا لم تُهجَّر خدماتك العميلة قبل تحديث الخادم، تفقد جميع تتبعاتها بصمت.

NocoDB‏ 2026.09.x: تُعيد سلسلة 2026.09 بناء صور Docker للتخلص من الاعتماديات الضعيفة. التثبيتات التي تستخدم bind-mounts (./postgres، ./nocodb) بدلاً من أقراص مسماة قد تبدأ على قاعدة بيانات فارغة بعد السحب — لا يجد NocoDB بياناته إذا تغير مسار التحميل بين الإصدارات. يُنصح بالترحيل إلى الأقراص المسماة قبل التحديث.

استراتيجيات التحديث: مقارنة

مرّر الجدول أفقيًا

الاستراتيجيةأمان البياناتوقت التحضيرالتراجع
`docker compose pull` + `up -d` مباشرةلا ضمان — التغييرات الجذرية غير مكتشفةأقل من دقيقةصعب في حال هجرة البيانات
رفع وسم مُصدَّر + نسخة احتياطية للأقراصعالٍ — البيانات محفوظة قبل أي تغيير10 إلى 20 دقيقةسهل: تراجع الوسم + `up -d --no-deps`
اختبار على بيئة تجريبية قبل الإنتاجأقصى مستوى — التغييرات الجذرية مكتشفة خارج الإنتاجمتغير حسب البيئةغير ضروري إذا نجح الاختبار
صورة مثبتة بملخص SHA256عالٍ — محصّن ضد إعادة كتابة الوسممثل وسم الإصدارمثل وسم الإصدار

دمج هذا البروتوكول في سير عملك

بروتوكول يبقى في دليل لا فائدة منه. لتطبيقه بشكل منهجي، أخرج الإصدار إلى ملف .env مُصدَّر في git:

# .env
MEILISEARCH_VERSION=v1.53.0
POSTGRES_VERSION=15.6
# docker-compose.yml
services:
  meilisearch:
    image: getmeili/meilisearch:${MEILISEARCH_VERSION}

تحديث إصدار يصبح حينئذٍ commit واحد على .env — مقروء في git log، قابل للعكس بـ git revert، وقابل للنشر عبر CI/CD دون تعديل ملف Compose الرئيسي.

بالنسبة للوكالات التي تدير stacks متعددة لعملاء مختلفين، أنشئ ملف CHANGELOG_INFRA.md لكل عميل: كل تحديث موثق بالإصدار السابق، والتاريخ، والنسخة الاحتياطية المنجزة، والنتيجة. هذا أيضاً ما يحميك تعاقدياً في حال حدوث حادث لاحق.

الأتمتة دون فقدان التحكم

إذا أردت الإخطار بالإصدارات الجديدة دون السحب التلقائي، تراقب Diun (Docker Image Update Notifier‏) سجلك وترسل لك إشعاراً (Slack، بريد إلكتروني، webhook) عند توفر صورة جديدة. تظل صاحب قرار موعد التحديث.

هذا هو الفرق الجوهري عن Watchtower: Diun‏ تُخطر، Watchtower‏ تتصرف. على stack إنتاجية مع أقراص دائمة، الإخطار هو المستوى الصحيح من الأتمتة — الفعل يبقى يدوياً ومسبوقاً بالبروتوكول أعلاه.

VPS بوصول root لتطبيق هذا البروتوكول

تصدير كامل، لقطات قبل التحديث، تراجع إلى صورة سابقة: هذا البروتوكول يستلزم وصول root وتخزين محلي قابل للتحكم. الاستضافة المشتركة لا تمنحك هذا المستوى من التحكم في أقراص Docker.

بحاجة إلى مساعدة؟

تصفّح مركز المساعدة والأسئلة الشائعة، أو تواصل مع فريقنا — معاودة اتصال أو WhatsApp أو بريد إلكتروني. الدعم بـالعربية والفرنسية والإنجليزية.

راسلنا على WhatsAppيُفتح في علامة تبويب جديدة