التخزين الدائم (Docker Volumes): كيف نمنع ضياع قواعد البيانات عند توقف الحاوية؟
أحد أكثر الأخطاء شيوعاً عند بناء بيئات تعتمد على Docker هو التعامل مع الحاوية وكأنها خادم دائم. الواقع أن الحاوية كيان مؤقت بطبيعته، وعند حذفها أو إعادة إنشائها يمكن أن تضيع البيانات المخزنة داخل نظام الملفات الخاص بها، خصوصاً إذا كانت تلك البيانات تخص MySQL أو PostgreSQL أو أي خدمة تخزين حالة Stateful.
لهذا السبب يُعد فهم Docker Volumes خطوة أساسية في أي مسار ما هو DevOps؟ ولماذا تدفع الشركات ثروات لمهندسي الأتمتة السحابية؟. فإذا كنت قد قرأت سابقاً مشكلة “الكود يعمل على جهازي فقط” وكيف يحلها Docker نهائياً؟، فاعلم أن حل مشكلة التوافق شيء، وحماية البيانات التشغيلية شيء آخر لا يقل أهمية.
ما المشكلة الفعلية عند تخزين قاعدة البيانات داخل الحاوية؟
عند تشغيل قاعدة بيانات داخل حاوية، يتم حفظ الملفات افتراضياً داخل طبقة الكتابة الخاصة بالحاوية Writable Layer. هذه الطبقة مرتبطة بعمر الحاوية نفسها، وليست مصممة كوسيط تخزين دائم طويل الأجل.
إذا نفذت أمراً مثل docker rm -f أو أعدت النشر عبر CI/CD دون ربط تخزين دائم، فغالباً ستنشأ حاوية جديدة نظيفة تماماً، وكأن قاعدة البيانات بدأت من الصفر.
هذه ليست مشكلة نظرية فقط، بل سبب مباشر في حوادث فقد بيانات داخل بيئات الاختبار والإنتاج، خصوصاً عند تحديث الصور أو تدوير الحاويات أو فشل العقدة المستضيفة Host.
ما هو Docker Volume ولماذا هو الخيار الصحيح؟
Volume هو آلية تخزين يديرها Docker Engine بشكل منفصل عن دورة حياة الحاوية. بمعنى آخر، يمكن حذف الحاوية وإعادة بنائها وربطها بنفس التخزين دون فقد الملفات الموجودة في قاعدة البيانات.
هذا النموذج يعزل البيانات عن التطبيق. الصورة Image تُستخدم لتشغيل الخدمة، بينما Volume يحتفظ بالحالة والملفات المتغيرة. هذا الفصل هو من أساسيات التصميم النظيف للحاويات.
- إمكانية إعادة إنشاء الحاويات دون ضياع البيانات.
- سهولة النسخ الاحتياطي أو الترحيل بين الخوادم.
- تحسين التكامل مع خطوط
Pipelinesوالنشر الآلي. - تقليل أخطاء التشغيل عند الترقية أو التراجع
Rollback.
الفرق بين Bind Mount و Volume
هناك طريقتان شائعتان لربط التخزين: Bind Mount و Named Volume. الأول يربط مساراً مباشراً من نظام التشغيل داخل الحاوية، أما الثاني فيُدار داخلياً من Docker.
في بيئات التطوير قد يكون Bind Mount مفيداً لمزامنة الملفات المحلية. لكن في قواعد البيانات، يظل Named Volume غالباً أكثر تنظيماً وأسهل إدارة ضمن البيئات القياسية.
تشغيل قاعدة MySQL مع تخزين دائم
إذا كنت قد اطلعت على أوامر Docker الأساسية للتحكم: تشغيل، إيقاف، فحص، وحذف الحاويات، فستلاحظ أن تشغيل قاعدة بيانات يحتاج فقط إلى إضافة ربط تخزين صحيح.
docker volume create mysql_data
docker run -d \
--name mysql-db \
-e MYSQL_ROOT_PASSWORD=StrongPassword123 \
-e MYSQL_DATABASE=appdb \
-p 3306:3306 \
-v mysql_data:/var/lib/mysql \
mysql:8
في هذا المثال، المسار /var/lib/mysql هو المكان الذي يخزن فيه MySQL بياناته. ربط هذا المسار بـ mysql_data يجعل البيانات مستقلة عن الحاوية نفسها.
يمكنك بعد ذلك حذف الحاوية وإعادة تشغيلها دون خسارة الجداول، بشرط إعادة استخدام نفس Volume.
اختبار بقاء البيانات بعد حذف الحاوية
docker rm -f mysql-db
docker run -d \
--name mysql-db \
-e MYSQL_ROOT_PASSWORD=StrongPassword123 \
-e MYSQL_DATABASE=appdb \
-p 3306:3306 \
-v mysql_data:/var/lib/mysql \
mysql:8
طالما أن اسم Volume نفسه أُعيد استخدامه، ستعود قاعدة البيانات ببياناتها السابقة. هذه هي الفكرة الجوهرية التي تمنع ضياع السجلات بعد إعادة النشر.
استخدام Docker Compose في المشاريع الحقيقية
في التطبيقات متعددة الخدمات، يُفضَّل تعريف التخزين داخل ملف docker-compose.yml بدلاً من الأوامر اليدوية. هذا يسهّل إعادة الإنتاج، ويجعل البنية قابلة للإدارة داخل المستودع البرمجي.
version: '3.9'
services:
db:
image: mysql:8
container_name: mysql-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: StrongPassword123
MYSQL_DATABASE: appdb
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
volumes:
mysql_data:
هذا النمط مثالي عند بناء منصات تعتمد على تطبيق Node.js أو Python. ويمكن ربطه بسهولة مع ما تعلمته في تحويل سيرفر Node.js متكامل إلى حاوية Docker قابلة للنقل أو كتابة أول Dockerfile: تحويل سكربت Python إلى صورة (Image) معزولة.
كيف ينعكس ذلك على CI/CD وعمليات النشر؟
عند استخدام Jenkins أو GitHub Actions، غالباً ستقوم خطوط النشر بإيقاف الحاوية القديمة وتشغيل نسخة جديدة من الصورة المحدثة. إذا كانت قاعدة البيانات داخل طبقة الحاوية فقط، فكل تحديث قد يتحول إلى كارثة بيانات.
أما عند فصل التخزين في Volume، تصبح عملية النشر أقرب إلى استبدال المحرك مع الإبقاء على الخزان. التطبيق يتغير، لكن البيانات تبقى. وهذه قاعدة ذهبية في تصميم الأنظمة القابلة للتحديث دون Downtime غير ضروري.
لا تعتمد على
Docker Volumesوحدها كبديل للنسخ الاحتياطي. التخزين الدائم يحميك من حذف الحاوية، لكنه لا يحميك من تلف البيانات المنطقي، أو الأوامر الخاطئة داخل قاعدة البيانات، أو فساد الملفات، أو اختراق الخادم.
أفضل الممارسات الأمنية والمعمارية
- أنشئ
Volumeمخصصاً لكل خدمة حالة، ولا تشارك نفس التخزين بين قواعد مختلفة دون مبرر معماري واضح. - استخدم حسابات محدودة الصلاحيات داخل قاعدة البيانات، ولا تعتمد دائماً على المستخدم
root. - نفّذ نسخاً احتياطية دورية عبر
cronأو عبر خط نشر منفصل. - راقب استهلاك القرص والمساحة الحرة على الخادم المستضيف.
- احتفظ بملفات التهيئة تحت إدارة إصدار
Gitلكن لا تخزن كلمات المرور بشكل صريح داخل المستودع.
في البيئات الحساسة، اجعل بيانات قواعد الإنتاج خارج الخوادم المؤقتة قدر الإمكان، وادرس استخدام خدمات تخزين مُدارة أو طبقات أقراص مشفرة. كما يجب تقييد الوصول عبر
SSHوFirewallوعدم كشف منافذ قواعد البيانات للإنترنت مباشرة.
ماذا عن Kubernetes؟
الفكرة نفسها تستمر في عالم Kubernetes ولكن عبر مفاهيم مثل PersistentVolume وPersistentVolumeClaim. أي أن المبدأ المعماري ثابت: الحوسبة مؤقتة، والبيانات يجب أن تُدار بشكل منفصل.
هذا مهم جداً عند تشغيل Pods قابلة للاستبدال على أكثر من عقدة. بدون تخزين دائم، لن تنجو قواعد البيانات من إعادة الجدولة أو فشل العقدة.
الخلاصة
Docker ممتاز لعزل التطبيقات وتسريع النشر، لكن قاعدة البيانات ليست مجرد عملية يمكن حذفها وإعادتها بلا أثر. الحل الصحيح هو فصل منطق التطبيق عن طبقة البيانات باستخدام Docker Volumes، ثم دعم ذلك بسياسات نسخ احتياطي ومراقبة وأمان.
إذا كنت قد بدأت رحلتك من تثبيت Docker وإعداد بيئة العمل على Linux و Windows أو من أول حاوية (Container) لك: تشغيل سيرفر ويب Nginx بكلمة واحدة، فهذه المرحلة هي النقلة الحقيقية من التجارب التعليمية إلى بنية تشغيل يمكن الوثوق بها في المشاريع الواقعية.
1 comment