الوحدة 3 · بيئات محلية مع Docker Compose
الـ Volumes: بيانات تبقى
16 دقراءة 4 داختر بحكمة
الدرس في لمحة
احفظ بيانات Postgres عبر إعادات التشغيل باستخدام named volume، وجهّز قاعدة البيانات ببيانات أولية عبر سكربت تهيئة مربوط بـ bind mount، واعرف أي أوامر Compose تحفظ بياناتك وأيها يدمّرها.
- 1الـ Named volumes لملفات قاعدة البيانات
- 2الـ Bind mounts للملفات التي تعدّلها
- 3الـ tmpfs للبيانات المؤقتة
- 4الـ Volumes وإصدارات قاعدة البيانات
- 5أي mount لأي مهمة
لا فيديو هنا، بل الشيء الحقيقي: درس مكتوب وأمثلة قابلة للتشغيل واختبار وتدريب.
في الأسبوع الذي أضفنا فيه Compose إلى أحد مشاريع Skylane، شغّل مطوّر docker compose down -v «لينظّف» قبل عرض تقديمي. فنظّف ثلاثة أيام من بيانات الاختبار المُدخلة بعناية. الـ containers مصمَّمة ليُتخلَّص منها، لذا يجب أن يعيش كل ما تريد الاحتفاظ به خارجها، ويجب أن تعرف بالضبط أي أمر يمحوه.
الـ Named volumes لملفات قاعدة البيانات
أضف volume إلى خدمة db وصرّح به في المستوى الأعلى:
services:
# api: …as before
db:
image: postgres:17
environment:
POSTGRES_USER: notes
POSTGRES_PASSWORD: notes
POSTGRES_DB: notes
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:الـ named volume (وحدة تخزين مسمّاة) تخزين ينشئه Docker ويديره. يضيف Compose اسم المشروع كبادئة له، فيصبح اسم هذا notes_pgdata. إنه ليس جزءًا من أي container، لذا فإن حذف db وإعادة إنشائه يتركان البيانات في مكانها:
docker compose down # containers and network removed, pgdata kept
docker compose up -d # notes are still there
docker volume ls # notes_pgdata
docker volume inspect notes_pgdataالـ named volumes هي الخيار الافتراضي الصحيح لملفات قاعدة البيانات. يضبط Docker الملكية بشكل صحيح للـ container، ولا تواجه غرائب نظام ملفات المضيف، وعلى Docker Desktop هي أسرع بكثير من الـ bind mounts لأنها تعيش داخل آلة Linux الافتراضية.
الاستعادة هي الأنبوب نفسه في الاتجاه المعاكس: docker compose exec -T db psql -U notes notes < backup.sql. الخيار -T يعطّل الطرفية الوهمية (pseudo-TTY) حتى يمكن تمرير الملف إلى الداخل. جرّب ذلك مرة في وقت هادئ، حتى لا تكون أول استعادة لك في اليوم الذي تحتاج إليها فيه.
الـ Bind mounts للملفات التي تعدّلها
الـ bind mount يربط مسارًا على جهازك بداخل الـ container. التعديلات على أي جهة تظهر على الأخرى فورًا. هذا ما تريده للملفات التي تعيش في مستودعك، مثل سكربت المخطّط:
db:
image: postgres:17
volumes:
- pgdata:/var/lib/postgresql/data
- ./db/init:/docker-entrypoint-initdb.d:roتشغّل image Postgres كل ملف .sql و.sh في /docker-entrypoint-initdb.d، بترتيب الأسماء، فقط حين يكون مجلد البيانات فارغًا. في أول up على الإطلاق، ينشئ db/init/001-schema.sql الجدول notes. وفي كل تشغيل لاحق يُتجاهل المجلد، لأن الـ volume يحتوي أصلًا على قاعدة بيانات مهيّأة. حين تغيّر المخطّط بعد ذلك، اكتب migration يشغّلها التطبيق، أو امسح volume التطوير عن قصد.
اللاحقة :ro تجعل الـ mount للقراءة فقط داخل الـ container. أعطِ الـ containers أقل صلاحية تكفي.
للـ bind mounts عيبان مزعجان. على Linux تكون الملفات مملوكة لـ UID مستخدم المضيف، الذي قد لا يطابق المستخدم داخل الـ container، فتفشل الكتابة بـ EACCES. وعلى macOS وWindows يعبر الوصول إلى الملفات حدود الآلة الافتراضية فيكون أبطأ، ولهذا يجب ألا تُربط المجلدات الثقيلة مثل node_modules من المضيف أبدًا. ستستخدم أداة أفضل لتعديل الكود الحيّ، Compose watch، في الدرس 3.4.
الـ tmpfs للبيانات المؤقتة
الـ mount من نوع tmpfs يعيش في الذاكرة ويختفي حين يتوقّف الـ container. إنه مفيد للملفات المؤقتة التي لا تريدها على القرص أبدًا، أو لقاعدة بيانات اختبار تُحذف بعد الاستخدام حيث تهمّ السرعة أكثر من البقاء:
db-test:
image: postgres:17
tmpfs:
- /var/lib/postgresql/dataالـ Volumes وإصدارات قاعدة البيانات
الـ volume يخزّن صيغة قاعدة البيانات على القرص، وهي تخصّ إصدارًا رئيسيًا واحدًا. إذا رفعت postgres:17 إلى postgres:18 وأبقيت الـ volume نفسه، فسيرفض الخادم الجديد البدء على الملفات القديمة. كما أن image Postgres 18 نقلت موقع البيانات الافتراضي: فهي تتوقّع mount واحدًا في /var/lib/postgresql (وتحفظ البيانات في مجلد فرعي يحمل رقم الإصدار) بدلًا من .../data. وإذا وجدت نقطة دخولها بيانات أو mount في المسار القديم، فإنها تتوقّف برسالة خطأ تشرح هذا التغيير. اقرأ ملاحظات الإصدار الخاصة بالـ image قبل رفع إصدار رئيسي.
أي mount لأي مهمة
| الحاجة | الاستخدام |
|---|---|
| ملفات قاعدة بيانات تصمد بعد إعادة التشغيل | named volume |
| سكربتات بيانات أولية أو إعدادات من المستودع | bind mount مع :ro |
| مساحة مؤقتة سريعة تُحذف بعد الاستخدام | tmpfs |
| الكود المصدري أثناء التطوير | Compose watch (الدرس 3.4) |
بياناتك الآن تعيش أطول من الـ containers. لكن شغّل البيئة من البداية الباردة، وقد ترى الـ API يفشل في أول بضعة طلبات: إنه يبدأ قبل أن يصبح Postgres جاهزًا لقبول الاتصالات. ترتيب الإقلاع هو التالي.
أهم النقاط
- الـ named volumes يديرها Docker وتعيش أطول من الـ containers؛ استخدمها لملفات قاعدة البيانات.
- الـ bind mounts تربط مسارًا على المضيف بداخل الـ container؛ استخدمها للملفات التي تعدّلها على المضيف، مثل سكربتات البيانات الأولية، وركّبها للقراءة فقط متى استطعت.
- الأمر
docker compose downيحتفظ بالـ named volumes؛ أماdocker compose down -vفيحذفها مع كل بياناتها. - السكربتات في
/docker-entrypoint-initdb.dلا تعمل إلا حين يكون مجلد بيانات Postgres فارغًا، أي عند أول تشغيل على الإطلاق. - صيغة تخزين قاعدة البيانات على القرص مرتبطة بإصدارها الرئيسي؛ والترقية بين إصدارات Postgres الرئيسية تحتاج إلى dump واستعادة أو
pg_upgrade، لا إلى tag جديد.