Featured image of post أساسيات عالم الحاويات docker / docker-compose والحوسبة السحابية

أساسيات عالم الحاويات docker / docker-compose والحوسبة السحابية

السلام عليكم ورحمة الله وبركاته

اليوم سوف اتحدث عن اساسيات عالم الحاويات وسوف اركز على docker و docker-compose, لكن نفس الاساسيات تطبق على اي نظام حاويات موجود. هذا الموضوع سوف يركز على افكار الحاويات واساسيات التعامل معها, يشرح الاساسيات و بعض الميزات المخصصة في docker-compose. للحاويات.

عند انهائك للموضوع سوف تسطيع فهم أهم افكار الحاويات و فهم ملفات docker-compose.yml.

هذا الموضوع يستخدم المتغيرات بحيث يمكنك تغيير الامثلة مثال:

[wrap=placeholder key=“تجربة” description=“ضع قيمة هنا”][/wrap]

1
الرقم: =تجربة=

هذا الموضوع اخذ مني عدة اسابيع, ويتعدى 2000 3000 كلمة. ارجو ان تستفيدون منه, وان اكون عند حسن ظنكم. بامكانكم المساهمة في هذا الموضوع عبر الرد بتعديلات, واذا هناك حاجة, سوف افتح مستودع git للمساهمة.

كيفية تثبيت دوكر موجودة هنا: https://discourse.aosus.org/t/topic/2223

أساسيات عالم الحاويات

الحاوية

أول نقطة يجب فهمها في عالم الحاويات هي الحاويات نفسها. فهي أساس كل شيء. الحاويات الحديثة التي نعرفها تم اختراعها من Solomon Hykes وهو مؤسس شركة دوكر في عام 2008.

الحاوية هي شيء معياري تحتوي كل الكود وكل الاعتماديات بحيث البرمجية تعمل بشكل سريع و يمكن الاعتماد عليها انه سوف تعمل على عدة أجهزة, حتى لو كانت توزيعه مختلفة.

صورة حاوية دوكر هي عباره حزمة خفيفة, مستقلة, يمكن تنفيذها وتشمل كل شيء تحتاجة البرمجية لتعمل, الكود البرمجي, أدوات النظام, مكتبات التوزيعة, الإعدادات وغيرها.

صور الحاويات تصبح حاويات عند تشغيلها, وبما أنها معزولة سوف تعمل بنفس الطريقة دائما, بغض النظر عن البنية التحتية, والحاويات تعزل البرمجية عن البيئة خارجها, فستعمل بنفس الطريقة بغض النظر عن كونها بيئة تطوير او بيئة إنتاج.

كيف تختلف عن الأنظمة الوهمية؟

الأنظمة الوهمية تستهلك موارد كبيرة جدا, بحيث الجهاز يحتاج لمحاكاة كل شيء, من الكيرنل إلى التعريفات إلى أساس النظام.

أما الحاويات فتستخدم نفس كيرنل لينكس, فهي اخف بشكل كبير, وتقريبا لا يوجد فيها فرق أداء بتشغيل البرمجية داخل حاوية أو خارجها, مع اعطاء فوائد العزل و سهولة النقل والتكرار.

image|577x500

أهمية الحاويات للحوسبة السحابية

بسبب خفة الحاويات وسرعة تشغيلها, هي من بدئت ثورة الحوسبة السحابية, حيث الحاويات هي اساس عالم السحابة. خصوصا حاويات Docker / OCI, لان كانت هناك حاويات لينكس (LXC) سابقا, لكن لم تكن مصممة بنفس مرونة حاويات دوكر, لان حاويات دوكر يمكن بنائاها تلقائيا ويمكن تصميمها بحيث يمكن تخصيصيها وتجهيزها قبل ان تعمل اساسا عبر متغيرات البيئة(Environment variables) دون اي تدخل يدوي.

السحابة تستخدم الحاويات وابرز ميزاتها التوسع التلقائي(auto scale) عبر برمجيات ادارة الحاويات أشهرهم Kubernetnes بحيث عند حصول ضغط على الموقع, يتم التواصل مع مستضيف الخوادم لأنشاء خوادم جديدة تلقائيا ويتم تشغيل الحاويات عليها لتكون خادم للموقع وتتحمل الضغط, وعند نزوله تتوقف هذه الخوادم بشكل تلقائي دون اي تدخل يدوي في عملية التوسع. وهذه القدرات في التوسع التلقائي و استخدام الحاويات هي الفرق بين مستضيف الخوادم العادي مثل VPS او خادم عادي وبين مستضيف خدمات حوسبة سحابية مثل AWS, Microsoft Azure, Google Cloud, Linode وغيرها وهناك شركات بدئت تدخل المجال بقوة, مثل شركة Hetzner الاوروبية, احد اكبر مقدمين الاستضافة الاوروبية بدئو بتغير بنيتهم ليكونو منافسين في سوق الحوسبة السحابية.

ويمكن تحديث الخدمة تلقائيا, عبر برمجيات ادارة الحاويات مثل Kubernetnes بحيث يوقف الحاويات ويحدثها تدريجيا دون اي تعطيل للخدمة, بالاضافة الى التاكد من حالة التحديث وتوقيفة في حالة حصول اي عطل. ابسط صورة لاداه ادارة حاويات هو docker-compose.

طريقة تسمية الصور

الصور طريقة تسميتها تتبع هذا الترتيب

1
اسم المطور/اسم الصورة:تاق

التاق عادة ما يستخدم لتحديد الاصدار ونوع الصورة مثلا:

nginx-proxy/nginx-proxy:latest او nginx-proxy/nginx-proxy تاق latest هو التاق الافتراضي في دوكر بحيث في حالة عدم تحديد اي تاق سوف يستخدم latest بعض المشاريع تستخدمة للنسخ التطويرية, فتاكد من طريقة تنظيم التاقات في الصورة التي تستخدمها.

نفس الحاوية لديها تاق alpine nginx-proxy/nginx-proxy:alpine عادة يتم استخدام alpine او تاق مشابة لاصدارات من الصورة مبنيه باستخدام توزيعة Alpine Linux وهي توزيعة خفيفة جدا وصغيرة الحجم, قد يصل فرق الحجم الى مئات الميجابايتات بينها وبين توزيعات عادية مثلا debian اذا كانت الصورة فيها العديد من التعديلات.

الصور المشهورة

الصور المشهورة جدا ومعتمدة من دوكر عادة لا يكون هناك خانة مطور لها مثال على هذا صورة Nginx الرسمية, تستخدمها عبر nginx فقط, او مع تحديد تاق nginx:alpine

مثال على استخدام صورة في docker-compose.yml

[wrap=placeholder key=“أسم_الحاوية” description=“أسم الخدمة” default=“nginx”][/wrap]

[wrap=placeholder key=“الصورة” description=“الصورة المستخدمة” default=“nginx:alpine”][/wrap]

1
2
3
4
5
6
version: '3.3' # docker compose اصدار ملف


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها

شبكات دوكر

لتتواصل الحاويات بين بعضها البعض دون الحاجه لنشرها للجهاز او للأنترنت, ننشئ شبكة دوكر. إذا تستخدم docker-compose كل مشروع تشغله سوف يكون له هناك شبكة افتراضيه default و كل الحاويات داخل المشروع/مِلَفّ docker-compose.yml تتصل بها إلا في حاله عدم تحديدها عند تحديد الشبكات لكل حاوية.

وبما أن في الأغلب جميعنا لديه عدة مشاريع docker-compose فدوكر يدعم انشاء عدة شبكات منفصلة داخل نفس الجهاز.

image|536x500 المصدر: https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/

طريقة عمل شبكات دوكر هي تشبه الشبكات المنزلية, فكر بكل حاوية كجهاز حاسب داخل شبكة منزلك. ولديك حاوية/جهاز لقاعدة البيانات وجهاز/حاوية أخرى لبرمجية تعتمد عليها.

لو كانت هذه الأجهزة حقيقة متصله بشبكة منزلك, فسيكون لها عنوان IP, كل الي عليك وضع هذا العنوان في البرمجية المستخدمة وتحديد المنفذ/port وسوف تتصل بقاعدة البيانات.

لكن اذا اتصل جهاز اخر في الشبكة ليس له عَلاقة في البرمجية, قد يأخذ عنوان جهاز قاعدة البيانات. ويتعطل الاتصال بين البرمجية وقاعدة البيانات. في الشبكات العادية تستطيع تحديد عنوان IP ثابت لتجنب هذه المشكلة, أما في دوكر, فسوف نستخدم DNS بدلا من عناوين IP مباشرة.

مثال لاستخدام الشبكات في docker-compose

[wrap=placeholder key=“أسم_الشبكة” description=“أسم الشبكة” default=“web”][/wrap]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: '3.3' #اصدار ملف docker compose, هناك عدة اصدارات

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها

services: # الخدمات / الحاويات
    =أسم_الحاوية=:
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:

DNS داخل حاويات دوكر و أسم_الحاوية

[details=“ماهو DNS”] DNS أو نظام اسماء النطاقات, يترجم عناوين مثل aosus.org إلى عنوان IP يمكن للجهاز ان يتصل به. تفاصيل اكثر على ويكيبيديا https://ar.wikipedia.org/wiki/%D9%86%D8%B8%D8%A7%D9%85_%D8%A3%D8%B3%D9%85%D8%A7%D8%A1_%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82%D8%A7%D8%AA [/details]

لتجنب تثبيت عناوين ال IP, وحجزها لحاويات معينة. دوكر سوف يشغل خادم DNS داخلي يترجم اسماء الحاويات إلى عناوين IP غير ثابتة يعطيها للحاوية عند اتصالها بالشبكة أو عند تشغيلها, ويمرر طلبات ال DNS العادية لخادم الDNS المستخدم من قابل النظام المستضيف.

الان الحاويات تصبح تتصل ببعض عبر اسمها ويترجم دوكر الاسم إلى عنوان IP, بدلا من حجز العنوان لكل حاوية, واحتياج حفظ وتخطيط اي عنوان لأي حاويه وترتيبها.

تحديد اسم الحاوية

دوكر يضع اسماء للحاويات بشكل افتراضي, ويمكن تغيير هذا الاسم عبر تحديد container_name في قسم الحاوية داخل مِلَفّ docker-compose.yml

[wrap=placeholder key=“أسم_الحاوية” description=“أسم الحاوية” default=“nginx-proxy”][/wrap]

1
container_name: =أسم_الحاوية=

مثال

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
version: '3.3' #اصدار ملف docker compose, هناك عدة اصدارات

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها

services: # الخدمات / الحاويات
    =أسم_الحاوية=:
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:

مثال على استخدام شبكة بنفس الاسم تم انشائها خارج docker-compose (يمكن استخدامها في عدة مشاريع/ملفات)

[details=“كيفية انشاء شبكة عابره لملفات docker-compose”]

[wrap=placeholder key=“custom_network” description=“أسم الشبكة”][/wrap]

1
docker network create =custom_network=

[/details]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # شبكة خارج docker compose ? نعم


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:

مثال على اتصال بشبكة خارج docker compose تحت اسم مختلف

[wrap=placeholder key=“أسم_الشبكة_الخارحية” description=“أسم الشبكة الخارجية” default=“nginx”][/wrap]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
version: '3.3' # docker compose اصدار ملف


networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: =أسم_الشبكة_الخارحية= # =أسم_الشبكة_الخارحية= خارج المشروع تحت أسم


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:

تغيير سيرفر ال DNS التي تستخدمة الحاوية

بشكل افتراضي الحاوية تستخدم نفس سيرفر ال dns الذي يستخدمة النظام. بامكانك تعديل السيرفر يدويا عبر dns

[wrap=placeholder key=“سيرفر_DNS_1” description=“الاول DNS عنوان سيرفر” default=“9.9.9.11”][/wrap] [wrap=placeholder key=“سيرفر_DNS_2” description=“الثاني DNS عنوان سيرفر” default=“1.1.1.1”][/wrap]

مثال

1
2
3
dns:
    - =سيرفر_DNS_1=
    - =سيرفر_DNS_2=

مثال كامل

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
version: '3.3' # docker compose اصدار ملف


networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: =أسم_الشبكة_الخارحية= # =أسم_الشبكة_الخارحية= خارج المشروع تحت أسم


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=

اضافة hostnames مخصصة للحاوية

اذا تريد اضافه hostnames مخصصة للحاوية, بامكانك عبر extra_hosts [details=“ماهو ال hostname?”] يقصد بالhostname /اسم المستضيف اسماء يتم ترجمتها عبر DNS, وهذا يعني اسم الحاوية عباره عن hostname. مثلا يعتبر aosus.org كhostname, اذ يترجم عنوان أسس الى عنوان IP يمكن الاتصال به. تفاصل اكثر على ويكيبيديا [/details]

[wrap=placeholder key=“custom_hostname” description=“Hostname” default=“aosus”][/wrap] [wrap=placeholder key=“custom_hostname_ip” description=“Hostname ل IP عنوان ال” default=“127.0.0.1”][/wrap]

مثال:

1
2
extra_hosts:
    - "=custom_hostname=:=custom_hostname_ip="

مثال كامل

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: '3.3' # docker compose اصدار ملف


networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: =أسم_الشبكة_الخارحية= # =أسم_الشبكة_الخارحية= خارج المشروع تحت أسم


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=
        extra_hosts: #hostname الاضافية
            - "=custom_hostname=:=custom_hostname_ip="

الان عندما تطلب الحاوية اسم =custom_hostname= عبر dns, سيتم ترجمتة الى =custom_hostname_ip=

كشف منافذ مخصصه داخل شبكة دوكر

بشكل افتراضي, دوكر سوف يكشف جميع المنافذ/ports التي تكشفها الحاوية للشبكة.

لتحديد المنافذ التي تريد كشفها للشبكة:

[wrap=placeholder key=“المنفذ_المكشوف” description=“المنفذ المكشوف للشبكة” default=“80”][/wrap]

1
2
expose:
    - =المنفذ_المكشوف= 

مثال كامل

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
version: '3.3' # docker compose اصدار ملف


networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: =أسم_الشبكة_الخارحية= # =أسم_الشبكة_الخارحية= خارج المشروع تحت أسم


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        expose: # للشبكة =المنفذ_المكشوف= كشف منفذ
            - =المنفذ_المكشوف= 
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=
        extra_hosts: #hostname الاضافية
            - "=custom_hostname=:=custom_hostname_ip="

سيتم كشف منفذ =المنفذ_المكشوف= فقط للشبكة. وفي حاله لم يكن مكشوف من الحاوية نفسها من قبل, الان سيتم كشفه.

Ports/منافذ الشبكة

عندما تريد الوصول للبرمجية من خارج الحاوية, تحتاج ان تنشر منفذ(Port) من داخل الحاوية إلى خارجها, سواء الجهاز نفسه او شبكة داخليه او الأنترنت.

عمومًا المنافذ في الحاويات تعمل هكذا:

1
منفذ داخل الحاوية:منفذ خارج الحاوية

بحيث تحدد المنفذ الذي تريد نشرة داخل الحاوية, ثم المنفذ الذي سيتم استخدامة خارجها

[wrap=placeholder key=“المنفذ_المنشور” description=“المنفذ المنشور” default=“85”][/wrap] [wrap=placeholder key=“المنفذ_المنشور_داخل_الحاوية” description=“المنفذ المنشور داخل الحاوية” default=“80”][/wrap]

1
2
ports:
    - =المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية=

المقصود من هذا الكود أن منفذ =المنفذ_المنشور_داخل_الحاوية= داخل الحاوية, ينشر للجهاز الخارجي ك =المنفذ_المنشور= على كل الشبكات, سواء شبكة داخل الجهاز(localhost) وشبكة الأنترنت.

وبسبب طريقة عمل دوكر وتعامله مع IPtables, فبهذه الحالة سوف يتجاوز الجدار الناري داخل النظام إذا كان جدار ناري منفصل, فلن يمكن تجاوزه من طرف دوكر.

مثال كامل

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # ؟ نعم docker compose شبكة خارج


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        ports: # المنافذ المفتوحة
            - =المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية= # منفذ داخل الحاوية:منفذ خارج الحاوية
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=
        extra_hosts: #hostname الاضافية
            - "=custom_hostname=:=custom_hostname_ip="

نشر المنفذ على شبكة محددة

لنقل مثلا لديك شبكتين على الخادم/الجهاز, وهي 127.0.0.1 و 192.168.1.1 أريد ان انشر المنفذ(port) فقط على 127.0.0.1 كل الي عليك تحديد عنوان ال IP الذي سيتم نشر المنفذ عليه

1
IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان

مثال

1
2
ports: # المنافذ المفتوحة
    - 127.0.0.1:85:80 # IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان

ينصح باستخدام 127.0.0.1 دائما لكشف الحاويات لانه عنوان loopback, أي localhost ولا يمكن وصول له خارج الجهاز.

مثال كامل

[wrap=placeholder key=“عنوان_IP_المنفذ_المنشور” description=“المكشوف عليه المنفذ IP عنوان ال” default=“127.0.0.1”][/wrap]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # ؟ نعم docker compose شبكة خارج


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        ports: # المنافذ المفتوحة
            - =عنوان_IP_المنفذ_المنشور=:=المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية= # IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=
        extra_hosts: #hostname الاضافية
            - "=custom_hostname=:=custom_hostname_ip="

في هذه الحالة سيتم نشر منفذ =المنفذ_المنشور= على عنوان IP محدد وهو =عنوان_IP_المنفذ_المنشور=

في حاله عدم تحديد منفذ لخارج الحاوية

1
2
ports:
    - 80

في هذه الحالة, سوف يختار دوكر port عشوائي خارج الحاوية ويربطه بالحاوية سيبقى مكشوف للأنترنت ويتجاوز الجدار المحلي داخل الجهاز, لكنه سيكون منفذ(port) عشوائي.

تحديد عده منافذ(port-range)

1
2
ports:
    - 127.0.0.1:87-450:80-443

في هذه الحالة سيتم نشر منافذ من 80 إلى 443 داخل الحاوية إلى 87-450 خارج الحاوية.

تحديد بروتوكول المنفذ

لدينا بروتوكولين في الشبكة, وهم TCP و UDP بشكل افتراضي دوكر سوف ينشر TCP فقط

لنشر UDP:

1
2
ports:
    - 80:80/udp

لنشر UDP و TCP لنفس المنفذ:

1
2
3
ports:
    - 80:80/udp
    - 80:80/tcp

Data mount

الحاويات مصممة على ان يتم حذفها واعادة تشغيلها عند اي تحديث. بحيث ان اي تحديث يطرق على الحاوية هو نظام جديد, ولتطبيقه سوف تحذف الصورة/الحاوية القديمة.

وطبعا اذا كانت لديك اي معلومات داخل الحاوية, سيتم حذفها. لذلك في دوكر هناك شيء اسمه Data Mount, وله نوعين:

Bind mounts

image|501x255 Bind Mounts يصل محلد موجود على النظام بمجلد داخل الحاوية. لنقول اننا نريد تخزين configs الخاصة ب NGINX داخل مجلد home/aosus/nginx/config/ الconfigs مخزنه داخل الحاوية في etc/nginx/conf.d/

1
2
    volumes:
        - /home/aosus/nginx/configs:/etc/nginx/conf.d

[details=“لاعطاء صلاحية الكتابه مع استخدام selinux”] اضف :z لنهايه الmount

1
2
    volumes:
        - /home/aosus/nginx/configs:/etc/nginx/conf.d:z

[/details]

لجعل ال mount فقط للقرائة دون تعديل:

1
2
    volumes:
        - /home/aosus/nginx/configs:/etc/nginx/conf.d:ro

انشاء المجلد بشكل تلقائي داخل نفس مجلد مشروع compose

1
2
    volumes:
        - ./config:/etc/nginx/conf.d:ro

سيتم انشاء مجلد config

مثال كامل

[wrap=placeholder key=“موقع_الملف_خارج_الحاوية” description=“موقع الملفات على النظام” default="/home/aosus/nginx/configs"][/wrap] [wrap=placeholder key=“موقع_الملف_داخل_الحاوية” description=“موقع الملفات داخل الحاوية” default="/etc/nginx/conf.d:ro"][/wrap]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # ؟ نعم docker compose شبكة خارج


services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        ports: # المنافذ المفتوحة
            - =عنوان_IP_المنفذ_المنشور=:=المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية= # IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان
        volumes: # data mount استخدام
            - =موقع_الملف_خارج_الحاوية=:=موقع_الملف_داخل_الحاوية=:ro # Bind mount استخدام
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=
        extra_hosts: #hostname الاضافية
            - "=custom_hostname=:=custom_hostname_ip="

Volumes

image|502x255 دوكر يحفز استخدام volumes عن bind mounts وذلك لعدة اسباب:

  • Volumes أسهل للنسخ الاحتياطي من bind mounts
  • بامكانك ادارة volumes عبر أوامر دوكر او Docker API
  • Volumes تعمل على لينكس و ويندوز
  • يمكن مشاركة ال volumes بين الحاويات بامان اكثر
  • Volumes drivers تمكنك من تخزين ال Volumes على جهاز تخزين اخر او على السحابة, بالاضافة الى تشفيرها وميزات اكثر
  • Volumes جديدة يمكن تحكم بمحتواها من الحاوية
  • Volumes على تطبيق Docker desktop المغلق ادائها افضل

هذه اسباب دوكر الرسمية, لا اتفق معها كلها خاصة النقطة الاولى.

اضافة Volume في docker compose تعمل الاتي:

1
2
volumes:
    cache:

هنا تحدد كل ال Volumes التي سيتم استخدامها في المشروع

استخدام volume خارج المشروع

بامكانك انشاء Volume داخل دوكر العادي عبر:

[wrap=placeholder key=“VOLUME-NAME” description=“الخارجي Volume أسم ال”][/wrap]

1
docker volume create =VOLUME-NAME=

لاستخدام Volume موجود مسبقا خارج المشروع بنفس الاسم

1
2
3
volumes:
    cache:
        external: true

اذا تحت اسم مختلف

1
2
3
volumes:
    cache:
        external: nginx

هنا كمثال اسم Volume الاصلي nginx

ربط Volume بحاوية

تحت قسم volumes داخل الحاوية, تحدد ال volume ومكان ربطة داخل الحاوية

1
2
volumes:
    cache:/etc/nginx/cache

وتطبق عليه نفس قواعد bind mount, مثل جعله للقرائه فقط عبر :ro وكتابة عبر :rw و :z لحل مشكلة صلاحيات مع SELinux.

مثال كامل

[wrap=placeholder key=“اسم_ال_volume_الخارجي” description=“الخارجي Volume أسم ال” default=“nginx”][/wrap] [wrap=placeholder key=“اسم_ال_volume” description=“موقع الملفات على النظام” default=“cache”][/wrap] [wrap=placeholder key=“موقع_ال_volume_داخل_الحاوية” description=“موقع الملفات داخل الحاوية” default="/etc/nginx/conf.d:ro"][/wrap]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # ؟ نعم docker compose شبكة خارج

services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        ports: # المنافذ المفتوحة
            - =عنوان_IP_المنفذ_المنشور=:=المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية= # IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان
        volumes: # data mount استخدام
            - =موقع_الملف_خارج_الحاوية=:=موقع_الملف_داخل_الحاوية=:ro # Bind mount استخدام
            - =اسم_ال_volume=:=موقع_ال_volume_داخل_الحاوية= # Volume استخدام
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=
        extra_hosts: #hostname الاضافية
            - "=custom_hostname=:=custom_hostname_ip="


volumes:
    =اسم_ال_volume=:
        external: =اسم_ال_volume_الخارجي=

Restart policy

للتحكم بمتى يتم تشغيل الحاويات, دوكر يستخدم Restart policies, منها تتحكم باعادة التشغيل الحاوية, بحيث يتم اعادة تشغيل عند الاعطات, او عند اعادة تشغيل دوكر نفسه.

العلامةوصف
no(الافتراضي)لا تعيد تشغيل الحاوية(الخيار الافتراضي)
on-failue[:عدد-المحاولات]أعد تشغيل الحاوية عند توقفها في حاله عطل(non-zero exit code), واختيارايا وضع حد لمحاولات اعادة التشغيل عبر [:عدد-المحاولات]
alwaysأعد تشغيل الحاوية دائما, وعنداقافها يدويا, سيتم اعادة تشغيلها عند اعادة تشغيل docker daemon او تشغيلها يدويا
unless-stoppedمشابة ل always لكنه عند ايقاف الحاوية يدويا(يدويا او لسبب اخر( لن يتم اعادة تشغيلها عند اعادة تشغيل docker daemon

تحديد restart policy للحاوية

1
restart: unless-stopped

مثال كامل

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # ؟ نعم docker compose شبكة خارج

services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        ports: # المنافذ المفتوحة
            - =عنوان_IP_المنفذ_المنشور=:=المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية= # IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان
        volumes: # data mount استخدام
            - =موقع_الملف_خارج_الحاوية=:=موقع_الملف_داخل_الحاوية=:ro # Bind mount استخدام
            - =اسم_ال_volume=:=موقع_ال_volume_داخل_الحاوية= # Volume استخدام
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        dns: # المستخدمة DNS سيرفرات ال
            - =سيرفر_DNS_1=
            - =سيرفر_DNS_2=
        extra_hosts: #hostname الاضافية
            - "=custom_hostname=:=custom_hostname_ip="
        restart: always # اعادة تشغيل الحاوية دائما


volumes:
    =اسم_ال_volume=:
        external: =اسم_ال_volume_الخارجي=

ربط الحاويات ببعض, وتشغيلها بترتيب محدد

عند تشغيل مشاريع اكثر تعقيدا, لنقل مثلا nextcloud. البرمجية الاساسيه قد تواجه مشاكل اذا تم تشغيلها قبل قاعدة البيانات مثلا. لذلك في docker compose ودوكر العادي هناك خيار depends_on لتحديد ان الحاوية تعتمد على حاوية أخرى.

عند تحديد اعتماديات الحاوية, عند تشغيلها, سيتم تشغيل كل الحاويات التي تعتمد عليها. وعند ايقافها سيتم ايقافها اولا ثم الحاويات التي تعتمد عليها.

تنبية, depends_on لاينتظر حتى الحاويه تكون جاهزة, بل حتى تبدء, اذا تحتاج ان تنتظر تجهز الحاوية تحتاج خطوات اكثر

تحديد الحاويات التي تعتمد عليها الحاوية

1
2
depends_on:
    - postgresql

مثال كامل مثال مختلف هذه المره نظرا لان لحاجة حاوية اخرى.

في هذا المثال, وضحنا ان الحاوية =أسم_الحاوية= تعتمد على حاوية اخرى اسمها postgresql موجودة داخل المشروع, اذ depends_on يدعم حاويات داخل نفس المشروع فقط.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # ؟ نعم docker compose شبكة خارج

services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        ports: # المنافذ المفتوحة
            - =عنوان_IP_المنفذ_المنشور=:=المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية= # IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان
        volumes: # data mount استخدام
            - =موقع_الملف_خارج_الحاوية=:=موقع_الملف_داخل_الحاوية=:ro # Bind mount استخدام
            - =اسم_ال_volume=:=موقع_ال_volume_داخل_الحاوية= # Volume استخدام
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        depends_on: # =أسم_الحاوية=  قبل تشغيل قاعدة البيانات قبل تشغيل 
            - postgresql
        restart: always # اعادة تشغيل الحاوية دائما


    postgresql:
        image: postgresql:14-alpine
        restart: always
        volumes:
            - ./postgresql:/var/lib/postgresql/data:z
        environment:
            - POSTGRES_PASSWORD=aosus


volumes:
    =اسم_ال_volume=:
        external: =اسم_ال_volume_الخارجي=

Healthcheck

للتاكد من حالة الحاوية, وانها تعمل بشكل صحيح. في دوكر هناك healthcheck, بمعنى اختبار الصحة. هذا الاختبار ينفذ امر داخل الحاوية, وينظر الى نتيجة هذا الامر. اذا كانت الحاوية ترد بشكل خاطئ, ستظهر الحاوية بحاله “Unhealthy” او بمعنى “غير صحية” أي لا تعمل بشكل صحيح

مثال:

1
2
3
4
5
6
healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost"]
    interval: 1m30s
    timeout: 10s
    retries: 3
    start_period: 40s

test: الاوامر التي تشكل الاختبار interval: الفترة بين كل اختبار timeout: وقت الانتظار حتى ينتهي الاختبار, اذا اطول من الوقت المحدد سيعتبر فشل retries: عدد المحاولات في الاختبار قبل اعتبار الحاوية “غير صحية” start_period: وقت الانتظار لتشغيل الحاوية

مثال كامل

[wrap=placeholder key=“interval” description=“الفترة بين التجارب” default=“30s”][/wrap] [wrap=placeholder key=“timeout” description=“وقت الانتظار حتى انتهاء الاختبار” default=“10s”][/wrap] [wrap=placeholder key=“retries” description=“عدد المحاولات” default=“3”][/wrap] [wrap=placeholder key=“start_period” description=“وقت الانتظار حتى تشغيل الحاوية” default=“40s”][/wrap]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
version: '3.3' # docker compose اصدار ملف

networks: # الشبكات التي سيتم انشائها
    =أسم_الشبكة=: # شبكة اسمها
        external: true # ؟ نعم docker compose شبكة خارج

services: # الخدمات / الحاويات
    =أسم_الحاوية=: # أسم الحاوية داخل المشروع
        image: =الصورة= #الصورة المستخدمة:التاق الخاص بها
        container_name: =أسم_الحاوية= #اسم الحاوية
        ports: # المنافذ المفتوحة
            - =عنوان_IP_المنفذ_المنشور=:=المنفذ_المنشور=:=المنفذ_المنشور_داخل_الحاوية= # IP منفذ داخل الحاوية:منفذ خارج الحاوية:عنوان
        volumes: # data mount استخدام
            - =موقع_الملف_خارج_الحاوية=:=موقع_الملف_داخل_الحاوية=:ro # Bind mount استخدام
            - =اسم_ال_volume=:=موقع_ال_volume_داخل_الحاوية= # Volume استخدام
        networks: # الشبكة المتصلة بها الحاوية
            =أسم_الشبكة=:
        depends_on: # =أسم_الحاوية=  قبل تشغيل قاعدة البيانات قبل تشغيل 
            - postgresql
        restart: always # اعادة تشغيل الحاوية دائما
        healthcheck:
            test: ["CMD", "curl", "-f", "http://localhost"]
            interval: =interval=
            timeout: =timeout=
            retries: =retries=
            start_period: =start_period=

    postgresql:
        image: postgresql:14-alpine
        restart: always
        volumes:
            - ./postgresql:/var/lib/postgresql/data:z
        environment:
            - POSTGRES_PASSWORD=aosus


volumes:
    =اسم_ال_volume=:
        external: =اسم_ال_volume_الخارجي=

الترخيص

الموضوع تحت نفس الترخيص لكل المواضيع على مجتمع أسس, وهو CC-BY-SA 4.0

المصادر

https://www.docker.com/resources/what-container https://docs.docker.com/config/containers/container-networking/ https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/ https://docs.docker.com/storage/volumes/ https://docs.docker.com/config/containers/start-containers-automatically/ https://docs.docker.com/compose/compose-file/compose-file-v3/ https://docs.docker.com/engine/reference/builder/#healthcheck

FarisZR
مبني بستخدام Hugo
قالب Stack مصمم من Jimmy