لماذا تُعدّ `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).
بروتوكول التحديث — الخطوات الخمس
اقرأ ملاحظات الإصدار قبل السحب
أولاً، راجع ملاحظات الإصدار الجديد. ابحث عن كلمات
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 القديمة.
ثلاث دقائق من القراءة توفر عليك ساعات من استعادة البيانات.
احتفظ بنسخة احتياطية للأقراص قبل السحب
لا تسحب أبداً قبل أن يكون لديك نسخة احتياطية صالحة للاستخدام. بالنسبة للأقراص المسماة، هناك مقاربتان:
تصدير تطبيقي (موصى به لقواعد البيانات) — يجب أن تكون الخدمة في حالة
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 تالف يُكتشف أثناء الاستعادة هو أكثر السيناريوهات تكلفةً.
اسحب الصورة الجديدة واختبرها خارج الإنتاج
حدّث الوسم في
docker-compose.yml، ثم اسحب الصورة دون إعادة تشغيل الخدمة:docker compose pull meilisearchإذا أتاحت بيئتك ذلك، اختبر الصورة الجديدة على نسخة مستنسخة من القرص في بيئة ddev أو VM تجريبي قبل المساس بالإنتاج. تحقق من سجلات الإقلاع بحثاً عن أي أخطاء تهجير:
docker compose up -d meilisearch docker compose logs -f meilisearchانتظر حتى يصل healthcheck إلى حالة
healthyقبل التحقق من النجاح. خدمة تبدأ لكنها ليستhealthyبعد ليست خدمة جاهزة.تحقق من 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 — نفس المبدأ ينطبق على أي خدمة تحتاج وقتاً للتهيئة.التراجع في حال حدوث مشكلة
إذا فشل الإصدار الجديد في الإقلاع أو أنتج أخطاء، يجب أن يستغرق التراجع أقل من دقيقتين. الإجراء:
1. عُد إلى الوسم السابق في
docker-compose.yml(أوgit revertإذا حفظت الرفع).
2. أعِد تشغيل الخدمة المعنية فقط، دون إعادة إنشاء الأقراص:docker compose up -d --no-deps --force-recreate meilisearch3. تحقق من السجلات فوراً:
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 إنتاجية مع أقراص دائمة، الإخطار هو المستوى الصحيح من الأتمتة — الفعل يبقى يدوياً ومسبوقاً بالبروتوكول أعلاه.