كيفية مشاركة البيانات بين حاويات Docker


عبد اللطيف ايمش

تمهيد

بشكل عام، نستعمل حاويات Docker لمرة وحيدة فقط، وهي تعمل إلى أن ينتهي تنفيذ الأمر الموكل إليها. لكن في بعض الأحيان تحتاج التطبيقات إلى الوصول إلى بيانات أو حفظها بعد حذف الحاوية. أمثلة عن البيانات التي تحتاج التطبيقات إلى الوصول إليها تتضمن قواعد البيانات، والمحتوى المولّد من قِبل المستخدم لمواقع الويب، وملفات السجلات. يمكن الوصول إلى تلك البيانات بشكلٍ دائم باستخدام حجوم Docker (أي Docker Volumes).

main.png

المتطلبات المسبقة

  • خادوم أوبنتو 16.04 (أو 14.04) مضبوطٌ كما في درس «الإعداد الابتدائي لخادوم أوبنتو 14.04»، بما في ذلك إعداد حساب مستخدم عادي لكنه يملك امتيازات الجذر (root) عبر الأداة sudo.
  • برمجية Docker مثبّتة على حاسوبك

ملاحظة: صحيحٌ أننا نفترض أنَّنا سنستعمل Docker على أوبنتو 16.04، لكن أوامر docker التي تتعامل مع حجوم Docker والمذكورة في هذا الدرس يجب أن تعمل عملًا صحيحًا على بقية الأنظمة لطالما كانت Docker مثبّتةً عليها وأُضيف المستخدم sudo إلى المجموعة docker.
يمكن إنشاء حجوم Docker ووصلها بأمرٍ واحد ألا وهو الأمر المُستخدَم لإنشاء الحاوية، أو يمكن إنشاء الحجوم بشكل مستقلٍ عن أيّة حاوية ثم وصلها إليها لاحقًا. سنناقش في هذا الدرس أربع طرائق مختلفة لمشاركة البيانات بين الحاويات.

أولًا: إنشاء حجم مستقل

أتى الأمر docker volume create مع إصدار 1.9 من Docker والذي يسمح لك بإنشاء حجم دون ربطه بأية حاوية. سنستخدم هذا الأمر لإنشاء حجم باسم DataVolume1:

docker volume create --name DataVolume1

إذا عُرِض الاسم، فذلك يُشير إلى نجاح تنفيذ الأمر السابق:

DataVolume1

لكي نستعمل هذا الحجم، علينا إنشاء حاوية جديدة مبنية على صورة ubuntu مستعملين الخيار ‎--‎rm لحذف الحاوية تلقائيًا بعد خروجنا منها، وسنستخدم الخيار ‎-v لوصل الحجم الجديد. الخيار ‎-v يتطلب ذكر اسم الحجم متبوعًا بنقطتين رأسيتين : ثم المسار المطلق لمكان وصل الحجم داخل الحاوية. إذا لم يكن المجلد المذكور في المسار السابق موجودًا في صورة التوزيعة، فسيُنشَأ ثم سيُنفَّذ الأمر السابق؛ وفي حال كان المجلد موجودًا، فسيؤدي وصل الحجم إليه إلى إخفاء المحتوى الموجود في الصورة الأصلية.

docker run -ti --rm -v DataVolume1:/datavolume1 ubuntu

لنكتب بعض البيانات إلى الحجم قبل إغلاق الحاوية:

root@802b0a78f2ef:/# echo "Example1" > /datavolume1/Example1.txt

ولاستعمالنا الخيار ‎--rm عند إنشاء الحاوية، فستُحذَف الحاوية تلقائيًا عند خروجنا منها. لكن الحجم سيبقى متاحًا للوصول.

root@802b0a78f2ef:/# exit

يمكننا أن نتحقق أنَّ الحجم ما يزال موجودًا في النظام عبر الأمر docker volume inspect:

docker volume inspect DataVolume1

الناتج:

[
    {
        "Name": "DataVolume1",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/datavolume1/_data",
        "Labels": null,
        "Scope": "local"
    }
]

ملاحظة: يمكننا أيضًا تفحص البيانات الموجودة في المسار المذكور في سطر Mountpoint لكن لا يُستحسَن تعديلها، لأنَّ ذلك قد يؤدي إلى حدوث عطب في البيانات إن كانت الحاوية تعمل وتجري تعديلات على تلك الملفات.
لنبدأ الآن حاويةً جديدةً ونربط الحجم DataVolume1 إليها:

docker run --rm -ti -v DataVolume1:/datavolume1 ubuntu

سنُنفِّذ الأمر الآتي داخل الحاوية:

root@d73eca0365fc:/# cat /datavolume1/Example1.txt

الناتج:

Example1

لنخرج الآن من الحاوية بالأمر exit.

ثانيًا: إنشاء حجم مرتبط بحاوية لكن سيبقى موجودًا بعد حذفها

سنُنشِئ في المثال الآتي حجمًا وحاويةً في آنٍ واحد، ومن ثم سنحذف الحاوية، ثم سنربط الحجم إلى حاويةٍ جديدة.
سنستخدم الأمر docker run لإنشاء حاوية جديدة بناءً على صورة ubuntu، وسيؤدي استخدام الخيار ‎-t إلى منحنا وصولًا إلى الطرفية، والخيار ‎-i سيسمح لنا بالتفاعل مع الحاوية. ولغرض التوضيح، سأستخدم الخيار ‎--name لتحديد اسم للحاوية، ثم سأستخدم الخيار ‎-v لإنشاء حجم جديد، وسنسميّه DataVolume2، وسنستخدم النقطتين الرأسيتين لفصل الاسم عن مسار وصل الحجم في الحاوية. وفي النهاية سنطلب إنشاء الحاوية لتبدأ تنفيذها بالأمر الافتراضي الموجود في ملف Docker لصورة Ubuntu (الذي هو الأمر bash) لكي نحصل على وصول إلى الصدفة (shell):

docker run -ti --name=Container2 -v DataVolume2:/datavolume2 ubuntu

ملاحظة: الخيار ‎-v هو خيارٌ مرنٌ جدًا، إذ يستطيع إنشاء وصل ترابطي، أو يمكنه إنشاء حجم جديد بتعديلٍ بسيط جدًا في شكله. فلو بدأ أوّل وسيطٍ بشرطة مائلة / أو ‎~/‎ فسيُنشِئ وصلًا ترابطيًا، لكن إن حذفت الشرطة في أوّل وسيط، فسيُنشِئ حجمًا.

  • ‎-v /path:/path/in/container وصل المسار ‎/path في الجهاز المضيف إلى ‎/path/in/container في الحاوية.
  • ‎-v path:/path/in/container إنشاء حجم باسم path دون علاقة بالمضيف.

ولمّا كنا داخل الحاوية، فلنكتب بعض البيانات إلى الحجم:

root@87c33b5ae18a:/# echo "Example2" > /datavolume2/Example2.txt
root@87c33b5ae18a:/# cat /datavolume2/Example2.txt

الناتج:

Example2

سنخرج من الحاوية باستخدام الأمر exit.
سنُعيد الآن تشغيل الحاوية مرةً أخرى، وسيتم وصل الحجم تلقائيًا.

docker start -ai Container2

لنتأكد من أنَّ الحجم قد وصِلَ إلى الحاوية وما تزال البيانات موجودةً فيه:

root@87c33b5ae18a:/# cat /datavolume2/Example2.txt

الناتج:

Example2

لنخرج مرةً أخرى من الحاوية بالأمر exit.
لن تسمح لنا Docker بحذف الحجم إذا كان مرتبطًا بحاوية، لننظر ماذا سيحدث لو جربنا ذلك:

docker volume rm DataVolume2

ستخبرنا الرسالة الآتية أنَّ الحجم ما يزال مستخدم وستعطينا المُعرِّف الكامل للحاوية:

Error response from daemon: Unable to remove volume, 
volume still in use: remove DataVolume2: volume is in use - 
[719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c]

يمكننا استخدام المُعرِّف السابق لحذف الحاوية:

docker rm 719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c

لن يؤثر حذف الحاوية على الحجم المرتبط بها، وما زال موجودًا في النظام، ونستطيع التحقق من ذلك باستخدام الأمر docker volume ls:

docker volume ls

الناتج:

DRIVER              VOLUME NAME
local               DataVolume2

نستطيع الآن استخدام الأمر docker volume rm لحذف الحجم بتمرير اسمه إلى الأمر السابق:

docker volume rm DataVolume2

أنشأنا في هذا المثال حجمًا فارغًا مع الحاوية الذي يرتبط بها في آنٍ واحد. أما في المثال القادم فسنرى ماذا سيحدث لو أنشأنا حجمًا ووصلناه إلى مجلدٍ فيه بيانات موجودة مسبقًا في الحاوية.

ثالثًا: إنشاء حجم وربطه بمجلدٍ فيه بيانات

عمومًا، لا يكون هنالك فرقٌ بين إنشاء حجم باستخدام الأمر docker volume create وبين إنشائه عند تشغيل الحاوية، لكن هنالك استثناءٌ وحيدٌ لهذه القاعدة، ويحدث عندما نُنشِئ حجمًا في نفس وقت إنشاء الحاوية وكان المسار الذي نريد ربط الحجم فيه مجلدًا موجودًا في الصورة الأصلية وفيه بيانات، وفي هذه الحالة ستُنسَخ البيانات الموجودة في ذاك المجلد إلى الحجم.
كمثال عن الحالة السابقة، سنُنشِئ حاويةً ونصل الحجم الجديد إلى المجلد ‎/var الموجود مسبقًا في صورة التوزيعة والذي يحتوي على بيانات:

docker run -ti --rm -v DataVolume3:/var ubuntu

جميع المحتوى الموجود في مجلد ‎/var في الصورة الأصلية سيُنسَخ إلى الحجم، ثم يمكننا وصل الحجم إلى الحاوية الجديدة. وفي هذه المرة، سنُنفِّذ الأمر ls بدلًا من الأمر الافتراضي bash، والذي سيُظهِر محتويات الحجم دون الحاجة إلى الدخول إلى الصدفة:

docker run --rm -v DataVolume3:/datavolume3 ubuntu ls DataVolume3

كما توقعنا، سيحتوي الحجم DataVolume3 على نسخةٍ من محتويات مجلد ‎/var في الصورة الأصلية:

backups
cache
lib
local
lock
log
mail
opt
run
spool
tmp

من غير المرجّح أن نصل المجلد ‎/var بهذه الطريقة، لكن قد تستفيد من المعلومات السابقة إذا أردت إنشاء صورة خاصة بك وتريد طريقةً سهلةً للحفاظ على البيانات.
سنشرح في المثال الآتي كيفية مشاركة الحجم مع أكثر من حاوية.

رابعًا: مشاركة البيانات بين أكثر من حاوية Docker

كل ما فعلناه منذ بداية هذا الدرس هو وصل الحجم إلى حاوية واحدة فقط بنفس الوقت، لكننا نرغب عادةً بالسماح بمشاركة البيانات بين أكثر من حاوية عبر وصل الحجم إلى عدِّة حاوية معًا. وهذا سهلٌ جدًا، لكن هنالك مشكلة محورية: لا تدعم Docker حاليًا ميزة التعامل مع قفل الملفات (file locking)، فلو احتاجت أكثر من حاوية إلى الكتابة على الحجم، فيجب أن تكون البرمجيات الموجودة في تلك الحاويات مصممةً لكي تكتب إلى أماكن تخزين البيانات المشتركة، لتجنّب تلف البيانات.

إنشاء الحاوية Container4 والحجم DataVolume4

سنستخدم الأمر docker run لإنشاء حاوية جديدة باسم Container4 ووصل حجم جديد إليها:

docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu 

سنُنشِئ الآن ملفًا ونضع فيه بعض المحتوى النصي:

root@db6aaead532b:/# echo "This file is shared between containers" > /datavolume4/Example4.txt

ثم سنخرج من الحاوية بالأمر exit.
سنعود الآن إلى سطر الأوامر في الجهاز المضيف، حيث سنُنشِئ حاويةً جديدةً ونصل فيها الحجم DataVolume4.

إنشاء الحاوية Container5 ووصل الحجم الذي كان موصولًا في Container4

سنُنشِئ حاويةً جديدةً باسم Container5 ونصل فيها الحجم الذي كان موصولًا في Container4:

docker run -ti --name=Container5 --volumes-from Container4 ubuntu
root@81e7a6153d28:/# cat /datavolume4/Example4.txt
This file is shared between containers

لنضف بعض النصوص إلى أحد الملفات من الحاوية الثانية:

root@81e7a6153d28:/# echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt

ثم سنخرج من الحاوية بالأمر exit.
سنتأكد الآن أنَّ البيانات الجديدة أصبحت متاحةً للحاوية Container4.

رؤية التغييرات التي أجريناها في Container5

لنتحقق من أنَّ الحاوية Container5 قد كتبت البيانات على حجم DataVolume4 بإعادة تشغيل الحاوية Container4:

docker start -ai Container4
root@db6aaead532b:/# cat /datavolume4/Example4.txt
This file is shared between containers
Both containers can write to DataVolume4

بعد أن تأكدنا من إمكانية القراءة والكتابة إلى الحجم من كلا الحاويتين، فسنخرج من الحاوية بالأمر exit.
أكرِّر أنَّ Docker لا تملك ميزةً لقفل الملفات، لذا يجب أن تقفل التطبيقاتُ الملفاتَ بنفسها. لكن من الممكن وصل حجم Docker للقراءة فقط لكي نضمن عدم حدوث تلف في البيانات نتيجةً لخطأٍ ما، وذلك عبر إضافة الخيار ‎:ro.

تشغيل الحاوية Container6 ووصل الحجم للقراءة فقط

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

docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu

سنتحقق من أنَّ الحجم موصولٌ للقراءة فقط بمحاولتنا حذف الملف الذي أنشأناه سابقًا:

root@ab63aebe534c:/# rm /datavolume4/Example4.txt
rm: cannot remove '/datavolume4/Example4.txt': Read-only file system

بعد إغلاق هذه الحاوية (كالمعتاد، بالأمر exit) فيمكننا حذف الحاويات التي أنشأناها إضافةً إلى الحجم:

docker rm Container4 Container5 Container6
docker volume rm DataVolume4

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

الخلاصة

أنشأنا في هذا الدرس حجم بيانات الذي يسمح لنا بالاحتفاظ بالبيانات حتى بعد حذفنا للحاوية. وشاركنا حجمًا بين عدِّة حاويات، ونوهنا إلى أهمية أن تكون التطبيقات المستعملة في الحاويات قادرةً على قفل الملفات لمنع تلف البيانات. وفي النهاية شاهدنا كيف يمكن وصل الحجم للقراءة فقط.
إذا كنتَ مهتمًا بكيفية مشاركة البيانات بين الحاويات والنظام المضيف، فأنصحك بقراءة درس «كيفية مشاركة البيانات بين حاوية Docker والمضيف».

ترجمة -وبتصرّف- للمقال How To Share Data between the Docker Container and the Hostلصاحبته Melissa Anderson





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن