السلام عليكم ورحمة الله وبركاته
اليوم سوف اتحدث عن اساسيات عالم الحاويات وسوف اركز على docker و docker-compose, لكن نفس الاساسيات تطبق على اي نظام حاويات موجود. هذا الموضوع سوف يركز على افكار الحاويات واساسيات التعامل معها, يشرح الاساسيات و بعض الميزات المخصصة في docker-compose. للحاويات.
عند انهائك للموضوع سوف تسطيع فهم أهم افكار الحاويات و فهم ملفات docker-compose.yml.
هذا الموضوع يستخدم المتغيرات بحيث يمكنك تغيير الامثلة مثال:
[wrap=placeholder key=“تجربة” description=“ضع قيمة هنا”][/wrap]
|
|
هذا الموضوع اخذ مني عدة اسابيع, ويتعدى 2000 3000 كلمة. ارجو ان تستفيدون منه, وان اكون عند حسن ظنكم.
بامكانكم المساهمة في هذا الموضوع عبر الرد بتعديلات, واذا هناك حاجة, سوف افتح مستودع git للمساهمة.
كيفية تثبيت دوكر موجودة هنا: https://discourse.aosus.org/t/topic/2223
أساسيات عالم الحاويات
الحاوية
أول نقطة يجب فهمها في عالم الحاويات هي الحاويات نفسها. فهي أساس كل شيء. الحاويات الحديثة التي نعرفها تم اختراعها من Solomon Hykes وهو مؤسس شركة دوكر في عام 2008.
الحاوية هي شيء معياري تحتوي كل الكود وكل الاعتماديات بحيث البرمجية تعمل بشكل سريع و يمكن الاعتماد عليها انه سوف تعمل على عدة أجهزة, حتى لو كانت توزيعه مختلفة.
صورة حاوية دوكر هي عباره حزمة خفيفة, مستقلة, يمكن تنفيذها وتشمل كل شيء تحتاجة البرمجية لتعمل, الكود البرمجي, أدوات النظام, مكتبات التوزيعة, الإعدادات وغيرها.
صور الحاويات تصبح حاويات عند تشغيلها, وبما أنها معزولة سوف تعمل بنفس الطريقة دائما, بغض النظر عن البنية التحتية, والحاويات تعزل البرمجية عن البيئة خارجها, فستعمل بنفس الطريقة بغض النظر عن كونها بيئة تطوير او بيئة إنتاج.
كيف تختلف عن الأنظمة الوهمية؟
الأنظمة الوهمية تستهلك موارد كبيرة جدا, بحيث الجهاز يحتاج لمحاكاة كل شيء, من الكيرنل إلى التعريفات إلى أساس النظام.
أما الحاويات فتستخدم نفس كيرنل لينكس, فهي اخف بشكل كبير, وتقريبا لا يوجد فيها فرق أداء بتشغيل البرمجية داخل حاوية أو خارجها, مع اعطاء فوائد العزل و سهولة النقل والتكرار.
أهمية الحاويات للحوسبة السحابية
بسبب خفة الحاويات وسرعة تشغيلها, هي من بدئت ثورة الحوسبة السحابية, حيث الحاويات هي اساس عالم السحابة. خصوصا حاويات Docker / OCI, لان كانت هناك حاويات لينكس (LXC) سابقا, لكن لم تكن مصممة بنفس مرونة حاويات دوكر, لان حاويات دوكر يمكن بنائاها تلقائيا ويمكن تصميمها بحيث يمكن تخصيصيها وتجهيزها قبل ان تعمل اساسا عبر متغيرات البيئة(Environment variables) دون اي تدخل يدوي.
السحابة تستخدم الحاويات وابرز ميزاتها التوسع التلقائي(auto scale) عبر برمجيات ادارة الحاويات أشهرهم Kubernetnes بحيث عند حصول ضغط على الموقع, يتم التواصل مع مستضيف الخوادم لأنشاء خوادم جديدة تلقائيا ويتم تشغيل الحاويات عليها لتكون خادم للموقع وتتحمل الضغط, وعند نزوله تتوقف هذه الخوادم بشكل تلقائي دون اي تدخل يدوي في عملية التوسع. وهذه القدرات في التوسع التلقائي و استخدام الحاويات هي الفرق بين مستضيف الخوادم العادي مثل VPS او خادم عادي وبين مستضيف خدمات حوسبة سحابية مثل AWS, Microsoft Azure, Google Cloud, Linode وغيرها وهناك شركات بدئت تدخل المجال بقوة, مثل شركة Hetzner الاوروبية, احد اكبر مقدمين الاستضافة الاوروبية بدئو بتغير بنيتهم ليكونو منافسين في سوق الحوسبة السحابية.
ويمكن تحديث الخدمة تلقائيا, عبر برمجيات ادارة الحاويات مثل Kubernetnes بحيث يوقف الحاويات ويحدثها تدريجيا دون اي تعطيل للخدمة, بالاضافة الى التاكد من حالة التحديث وتوقيفة في حالة حصول اي عطل. ابسط صورة لاداه ادارة حاويات هو docker-compose.
طريقة تسمية الصور
الصور طريقة تسميتها تتبع هذا الترتيب
|
|
التاق عادة ما يستخدم لتحديد الاصدار ونوع الصورة مثلا:
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]
|
|
شبكات دوكر
لتتواصل الحاويات بين بعضها البعض دون الحاجه لنشرها للجهاز او للأنترنت, ننشئ شبكة دوكر.
إذا تستخدم docker-compose
كل مشروع تشغله سوف يكون له هناك شبكة افتراضيه default
و كل الحاويات داخل المشروع/مِلَفّ docker-compose.yml
تتصل بها إلا في حاله عدم تحديدها عند تحديد الشبكات لكل حاوية.
وبما أن في الأغلب جميعنا لديه عدة مشاريع docker-compose
فدوكر يدعم انشاء عدة شبكات منفصلة داخل نفس الجهاز.
المصدر: 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]
|
|
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]
|
|
مثال
|
|
مثال على استخدام شبكة بنفس الاسم تم انشائها خارج docker-compose (يمكن استخدامها في عدة مشاريع/ملفات)
[details=“كيفية انشاء شبكة عابره لملفات docker-compose”]
[wrap=placeholder key=“custom_network” description=“أسم الشبكة”][/wrap]
|
|
[/details]
|
|
مثال على اتصال بشبكة خارج docker compose تحت اسم مختلف
[wrap=placeholder key=“أسم_الشبكة_الخارحية” description=“أسم الشبكة الخارجية” default=“nginx”][/wrap]
|
|
تغيير سيرفر ال 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]
مثال
|
|
مثال كامل
|
|
اضافة 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]
مثال:
|
|
مثال كامل
|
|
الان عندما تطلب الحاوية اسم =custom_hostname= عبر dns, سيتم ترجمتة الى =custom_hostname_ip=
كشف منافذ مخصصه داخل شبكة دوكر
بشكل افتراضي, دوكر سوف يكشف جميع المنافذ/ports التي تكشفها الحاوية للشبكة.
لتحديد المنافذ التي تريد كشفها للشبكة:
[wrap=placeholder key=“المنفذ_المكشوف” description=“المنفذ المكشوف للشبكة” default=“80”][/wrap]
|
|
مثال كامل
|
|
سيتم كشف منفذ =المنفذ_المكشوف= فقط للشبكة. وفي حاله لم يكن مكشوف من الحاوية نفسها من قبل, الان سيتم كشفه.
Ports/منافذ الشبكة
عندما تريد الوصول للبرمجية من خارج الحاوية, تحتاج ان تنشر منفذ(Port) من داخل الحاوية إلى خارجها, سواء الجهاز نفسه او شبكة داخليه او الأنترنت.
عمومًا المنافذ في الحاويات تعمل هكذا:
|
|
بحيث تحدد المنفذ الذي تريد نشرة داخل الحاوية, ثم المنفذ الذي سيتم استخدامة خارجها
[wrap=placeholder key=“المنفذ_المنشور” description=“المنفذ المنشور” default=“85”][/wrap] [wrap=placeholder key=“المنفذ_المنشور_داخل_الحاوية” description=“المنفذ المنشور داخل الحاوية” default=“80”][/wrap]
|
|
المقصود من هذا الكود أن منفذ =المنفذ_المنشور_داخل_الحاوية= داخل الحاوية, ينشر للجهاز الخارجي ك =المنفذ_المنشور= على كل الشبكات, سواء شبكة داخل الجهاز(localhost) وشبكة الأنترنت.
وبسبب طريقة عمل دوكر وتعامله مع IPtables, فبهذه الحالة سوف يتجاوز الجدار الناري داخل النظام إذا كان جدار ناري منفصل, فلن يمكن تجاوزه من طرف دوكر.
مثال كامل
|
|
نشر المنفذ على شبكة محددة
لنقل مثلا لديك شبكتين على الخادم/الجهاز, وهي 127.0.0.1
و 192.168.1.1
أريد ان انشر المنفذ(port) فقط على 127.0.0.1
كل الي عليك تحديد عنوان ال IP الذي سيتم نشر المنفذ عليه
|
|
مثال
|
|
ينصح باستخدام 127.0.0.1 دائما لكشف الحاويات لانه عنوان loopback, أي localhost ولا يمكن وصول له خارج الجهاز.
مثال كامل
[wrap=placeholder key=“عنوان_IP_المنفذ_المنشور” description=“المكشوف عليه المنفذ IP عنوان ال” default=“127.0.0.1”][/wrap]
|
|
في هذه الحالة سيتم نشر منفذ =المنفذ_المنشور= على عنوان IP محدد وهو =عنوان_IP_المنفذ_المنشور=
في حاله عدم تحديد منفذ لخارج الحاوية
|
|
في هذه الحالة, سوف يختار دوكر port عشوائي خارج الحاوية ويربطه بالحاوية سيبقى مكشوف للأنترنت ويتجاوز الجدار المحلي داخل الجهاز, لكنه سيكون منفذ(port) عشوائي.
تحديد عده منافذ(port-range)
|
|
في هذه الحالة سيتم نشر منافذ من 80 إلى 443 داخل الحاوية إلى 87-450 خارج الحاوية.
تحديد بروتوكول المنفذ
لدينا بروتوكولين في الشبكة, وهم TCP و UDP بشكل افتراضي دوكر سوف ينشر TCP فقط
لنشر UDP:
|
|
لنشر UDP و TCP لنفس المنفذ:
|
|
Data mount
الحاويات مصممة على ان يتم حذفها واعادة تشغيلها عند اي تحديث. بحيث ان اي تحديث يطرق على الحاوية هو نظام جديد, ولتطبيقه سوف تحذف الصورة/الحاوية القديمة.
وطبعا اذا كانت لديك اي معلومات داخل الحاوية, سيتم حذفها. لذلك في دوكر هناك شيء اسمه Data Mount, وله نوعين:
Bind mounts
Bind Mounts يصل محلد موجود على النظام بمجلد داخل الحاوية.
لنقول اننا نريد تخزين configs الخاصة ب NGINX داخل مجلد home/aosus/nginx/config/
الconfigs مخزنه داخل الحاوية في etc/nginx/conf.d/
|
|
[details=“لاعطاء صلاحية الكتابه مع استخدام selinux”] اضف :z لنهايه الmount
|
|
[/details]
لجعل ال mount فقط للقرائة دون تعديل:
|
|
انشاء المجلد بشكل تلقائي داخل نفس مجلد مشروع compose
|
|
سيتم انشاء مجلد config
مثال كامل
[wrap=placeholder key=“موقع_الملف_خارج_الحاوية” description=“موقع الملفات على النظام” default="/home/aosus/nginx/configs"][/wrap] [wrap=placeholder key=“موقع_الملف_داخل_الحاوية” description=“موقع الملفات داخل الحاوية” default="/etc/nginx/conf.d:ro"][/wrap]
|
|
Volumes
دوكر يحفز استخدام volumes عن bind mounts وذلك لعدة اسباب:
- Volumes أسهل للنسخ الاحتياطي من bind mounts
- بامكانك ادارة volumes عبر أوامر دوكر او Docker API
- Volumes تعمل على لينكس و ويندوز
- يمكن مشاركة ال volumes بين الحاويات بامان اكثر
- Volumes drivers تمكنك من تخزين ال Volumes على جهاز تخزين اخر او على السحابة, بالاضافة الى تشفيرها وميزات اكثر
- Volumes جديدة يمكن تحكم بمحتواها من الحاوية
- Volumes على تطبيق Docker desktop المغلق ادائها افضل
هذه اسباب دوكر الرسمية, لا اتفق معها كلها خاصة النقطة الاولى.
اضافة Volume في docker compose تعمل الاتي:
|
|
هنا تحدد كل ال Volumes التي سيتم استخدامها في المشروع
استخدام volume خارج المشروع
بامكانك انشاء Volume داخل دوكر العادي عبر:
[wrap=placeholder key=“VOLUME-NAME” description=“الخارجي Volume أسم ال”][/wrap]
|
|
لاستخدام Volume موجود مسبقا خارج المشروع بنفس الاسم
|
|
اذا تحت اسم مختلف
|
|
هنا كمثال اسم Volume الاصلي nginx
ربط Volume بحاوية
تحت قسم volumes داخل الحاوية, تحدد ال volume ومكان ربطة داخل الحاوية
|
|
وتطبق عليه نفس قواعد 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]
|
|
Restart policy
للتحكم بمتى يتم تشغيل الحاويات, دوكر يستخدم Restart policies, منها تتحكم باعادة التشغيل الحاوية, بحيث يتم اعادة تشغيل عند الاعطات, او عند اعادة تشغيل دوكر نفسه.
العلامة | وصف |
---|---|
no(الافتراضي) | لا تعيد تشغيل الحاوية(الخيار الافتراضي) |
on-failue[:عدد-المحاولات] | أعد تشغيل الحاوية عند توقفها في حاله عطل(non-zero exit code), واختيارايا وضع حد لمحاولات اعادة التشغيل عبر [:عدد-المحاولات] |
always | أعد تشغيل الحاوية دائما, وعنداقافها يدويا, سيتم اعادة تشغيلها عند اعادة تشغيل docker daemon او تشغيلها يدويا |
unless-stopped | مشابة ل always لكنه عند ايقاف الحاوية يدويا(يدويا او لسبب اخر( لن يتم اعادة تشغيلها عند اعادة تشغيل docker daemon |
تحديد restart policy للحاوية
|
|
مثال كامل
|
|
ربط الحاويات ببعض, وتشغيلها بترتيب محدد
عند تشغيل مشاريع اكثر تعقيدا, لنقل مثلا nextcloud. البرمجية الاساسيه قد تواجه مشاكل اذا تم تشغيلها قبل قاعدة البيانات مثلا.
لذلك في docker compose ودوكر العادي هناك خيار depends_on
لتحديد ان الحاوية تعتمد على حاوية أخرى.
عند تحديد اعتماديات الحاوية, عند تشغيلها, سيتم تشغيل كل الحاويات التي تعتمد عليها. وعند ايقافها سيتم ايقافها اولا ثم الحاويات التي تعتمد عليها.
تنبية, depends_on لاينتظر حتى الحاويه تكون جاهزة, بل حتى تبدء, اذا تحتاج ان تنتظر تجهز الحاوية تحتاج خطوات اكثر
تحديد الحاويات التي تعتمد عليها الحاوية
|
|
مثال كامل مثال مختلف هذه المره نظرا لان لحاجة حاوية اخرى.
في هذا المثال, وضحنا ان الحاوية =أسم_الحاوية= تعتمد على حاوية اخرى اسمها postgresql
موجودة داخل المشروع, اذ depends_on
يدعم حاويات داخل نفس المشروع فقط.
|
|
Healthcheck
للتاكد من حالة الحاوية, وانها تعمل بشكل صحيح. في دوكر هناك healthcheck, بمعنى اختبار الصحة. هذا الاختبار ينفذ امر داخل الحاوية, وينظر الى نتيجة هذا الامر. اذا كانت الحاوية ترد بشكل خاطئ, ستظهر الحاوية بحاله “Unhealthy” او بمعنى “غير صحية” أي لا تعمل بشكل صحيح
مثال:
|
|
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]
|
|
الترخيص
الموضوع تحت نفس الترخيص لكل المواضيع على مجتمع أسس, وهو 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