لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 04/12/15 في كل الموقع
-
مقدّمةتُمثِّل الحاويّات حلًّا أنيقًا لمن يبحث عن تصميم ونشر تطبيقات تعمل على نطاق واسع. يُوفّر Docker التّقنيّة المسؤولة عن إعداد الحاويّات، وتُساعده مشاريع أخرى عديدة عبر تطوير الأدوات المطلوبة لتحضير النّشر في بيئة العمل وللتّواصل بين مختلف مكوّناته. استكشاف الخدمة Service discovery هي إحدى التّقنيّات المركزيّة الّتي تعتمد عليها العديد من بيئات Docker. تُمكّن هذه التّقنيّة التّطبيقاتِ أو العناصرَ المُكوّنةَ لها من معرفة معلومات عن بيئة عملها. يُستعان عادةً بمخازن تعتمد صيغة مفتاح-قيمة key-value لهذا الغرض. تُستخدَم هذه المخازن أيضًا لإملاء تفاصيل حول ضبط الإعدادات. يُتيح ضبطُ أداة استكشاف الخدمة الاحتفاظَ بإعداد تشغيل الحاويّة خارجها وهو ما يُساعد من إعادة استخدام نفس الحاويّة في عدّة بيئات عبر إنشاء صورة منها. يهدف هذا المقال إلى عرض فوائد استخدام آليّة استكشاف الخدمة في بيئة عنقوديّة Clustered من مستضيفات Docker. سنُركّز على المفاهيم العامّة مع إعطاء أمثلة مُحدَّدة عندما يكون ذلك مناسِبًا. استكشاف الخدمة ومخازن الإعداد العامّة Global Configuration Storesتقوم تقنيّة استكشاف الخدمة على فكرة أساسيّة تتمثّل في أنّه يجب أن تكون لدى أي نظير من التّطبيق Instance القُدرة على التّعرف برمجيًّا على تفاصيل البيئة التي يعمل فيها. هذا الأمر ضروري لتمكين "زرع" النّظير الجديد في بيئة التّطبيق دون الحاجة للتّدخل اليدوي. تُنَفَّذ أدوات استكشاف الخدمة في العادة على هيئة سجلّات تُخزّن معلوماتٍ عن التّطبيقات أو الخدمات العاملة حاليًّا ضمن بيئة العمل، ويُمكن الوصول إليها من جميع عناصر البيئة. تُوزَّع هذه السّجلّات بين عدّة مُستضيفات لجعلها قابلةً للتّوسّعScalable وقادرةً على العمل عند حصول أخطاء. يُمكِن استخدام منصّات استكشاف الخدمة لحفظ أيّ نوع من معلومات الإعداد، رغم أنّ الهدف الأوليّ من إنشائها هو تقديم بيانات الاتّصال لربط العناصِر في ما بينها. تستفيد العديد من عمليّات النّشر من هذه الميزة عن طريق حفظ بيانات الإعداد لدى أداة الاستكشاف؛ حيثُ إن الحاويّات تستطيع تغيير سلوكها اعتمادًا على ما تعثُر عليه من إعدادات، إذا كانت مضبوطةً للقيّام بذلك. كيف تعمل أداة استكشاف الخدمة؟تُوفِّر كل أداة استكشاف واجهةَ تطبيقات برمجيّة API يُمكن للعناصِر استخدامُها لضبط إعداداتها أو الحصول على بيانات. لهذا السّبب نجد أنّ كل تطبيق يُضمِّن عنوانَ استكشاف الخدمة مُباشرةً في المصدَر Source أو يُوفّره كخيّار أثناء التّشغيل. تُتيح أدوات استكشاف الخدمة الوصول إلى القيّم الّتي تحتفِظ بها عن طريق طلبات Http. تسجيلُ التّطبيق لنفسه لدى أداة الاستكشاف مباشرةً بعد بدْء عمله، هو أولى خطوات عمل خدمة الاستكشاف؛ فيُسجّل كل المعلومات الّتي ستحتاجها بقيّة العناصر عند محاولتها الاستفادة من الخدمة الّتي يُقدِّمها.يجب على قاعدة بيانات MySQL مثلًا، تسجيلُ عنوان IP ومنفَذ Port الوصول للبرنامج؛ يُمكن أن تُضيف أيضًا اسمَ المُستخدِم واعتمادات Credentials الحساب المطلوبة لتسجيل الدّخول. أول ما يقوم به تطبيق يُريد الاستفادة من خدمةٍ مّا عند بدْء تشغيله، هوّ طلب أداة الاستكشاف لإعطائه معلومات عن نقطة اتّصال مُعرَّفة مُسبَقًا للارتباط بالخدمة. يُمكنه بعد ذلك التّفاعل مع العناصِر الّتي يحتاجها وفقًا للمعلومات الّتي يعثُر عليها. مُوزِّع الحِمل Load balancer مثالٌ جيّد، حيثُ بإمكانه - عن طريق أداة الاستكشاف - العثور على معلومات عن كل الخواديم الخلفيّّة Backend servers حتّى يُوجِّهَ إليها حركة الاتّصالات حسب إعداداتِها والمعلومات الّتي تُغذّي بها (أي الخواديم) أداةَ الاستكشاف. ينتُج عن استخدام أداة استكشاف وضعُ تفاصيل الإعداد خارجَ إطار الحاويّة. يجعل هذا الأمر الحاويّات أكثر مرونة وأقل ارتهانًا لإعدادات مُعيَّنة؛ كما أنّه يُسهِّل على عناصِر التّطبيق التفاعلَ مع نظائر جديدة من نفس الخدمة متيحًا بذلك إمكانيّة الإعداد الدّيناميكي. كيف يُؤثِّر تخزين الإعدادات؟تُعدّ القُدرة على تخزين أي نوع من بيانات الإعداد، بما فيها بياناتٌ تطلُبها أجزاء التّطبيق أثناء تنفيذها، إحدى المزايا الأساسيّة في أي نظام عمومي موزَّع لاستكشاف الخدمة. يعني هذا أنّه بالإمكان وضع بيانات إعدادٍ أكثر خارج الحاويّة، ضمن بيئة تنفيذ أوسع. يجب أن تُصمّم التّطبيقات - حتّى تعمل هذه الطّريقة بشكل فعّال - بعدد معقول من الخيّارات الافتراضيّة Defaults على أن يكون من الممكن إبدالُها بقيّم أخرى يُتَحصَّل عليها من مخزن الإعدادات أثناء التّنفيذ. تجعل هذه الطّريقة من استخدام مخزن الإعداد مُماثِلًا لاستخدام خيّارات سطر الأوامر Command line flags (أو Command line options) مع فرق أنّ استخدام مخزن إعدادات متاح للعموم يسمح بإنشاء وتشغيل نظائر أخرى من نفس العُنصر دون جهدٍ زائد. كيف يُساعِد مخزن الإعدادات في إدارة العُنقود؟لا يظهر للوهلة الأولى، العونُ الّذي يُقدّمه مخزنٌ مُوزَّع للإعدادات يستخدم صيغة مفتاح-قيمة، في حفظ وإدارة عُضويّات Membership العنقود. مخازن الإعدادات هي في الواقع البيئة المُثلى لحفظ آثار عضويّات المُستضيفات ووضعها تحت تصرّف أدوات إدارة العنقود. في ما يلي بعض معلومات المُستضيفات الّتي يُمكن حفظها على شكل مفتاح-قيمة في مخازن إعدادات مُوزَّعة: عناوين IP المُستضيفات. معلومات الاتّصال بالمُستضيفات. بيانات وصفيّة Metadata ومُلصقات Labels يُمكِن التّحكم بها من أجل اتّخاذ قرارت تتعلّق بالجدولة Scheduling. الدّور Role داخل العنقود (في حال استخدام نموذج قائد/تابِع Leader/follower model). لن تضطّر في الظّروف الاعتياديّة إلى الاهتمام بهذه التّفاصيل عند استخدام أداةٍ لاستكشاف الخدمة؛ ولكنّها وسيلة تُوفّر لأدوات الإدارة إمكانية الاستعلام أو التّعديل على معلوماتٍ تتعلّق بالعنقود. ماذا عن التّعرّف على الإخفاق Failure detection أثناء التّنفيذ؟يُمكن وضع آليّة للتّعرّف على إخفاق التّطبيقات عبر عدّة وسائل. السّؤال الّذي يجب طرحُه هنا هل ستُحدَّث خدمة الاستكشاف عند توقّف تطبيق عن العمل لتعكس حالة التّطبيق من حيثُ إنه لم يعُد يعمل؟ هذا النّوع من المعلومات حيوي للتّقليل من إخفاق الخدمة. تُتيح العديدمن أدوات استكشاف الخدمة تعيينَ قيّم مع مهلة زمنيّة يُمكِن ضبطُها Configurable Timeout. في هذه الحالة يضبُط العنصُر قيمةً ويُرفق معها مهلة زمنيّة، ثم يُعلِم أداة الاستكشاف بانتِظام بوجوده وفي نفس الوقت يُعيد تعيين المُهلة. يُعتبر العُنصُر خارج الخدمة وتُسحب معلوماته من مخزن الإعدادات عند بلوغ المُهلة الزّمنيّة المُحدَّدَة دون أن يتّصل بأداة الاستكشاف لإعلامها بوجوده وإعادة تعيين المُهلة. يتغيَّر طول المُهلة حسب التّطبيق والمُدّة الّتي يحتاجها للتّعامل مع إخفاق أحد العناصِر المُكوّنة له. توجد طريقة أخرى تعتمد على إنشاء حاويّة مُساعدة مع كل عنصُر، تقتصر مهمّة الحاويّة المُساعِدة على التّحقق من سلامة العنصُر دورِيًّا ثمّ تحديث السّجل في حال توقّف العنصُر عن العمل. نقطة ضعف هذه الطّريقة هي الحاويّة المُساعدة الّتي يُمكن أن تتوقّف عن العمل وهو ما قد ينتُج عنه معلومات خاطئة في مخزن الإعدادات. تتغلّب بعض النُّظُم على هذه المسألة عن طريق إضافة إمكانيّة التحقّق من سلامة الحاويّة إلى أداة الاستكشاف. يُمكن لخدمة الاستكشاف بهذه الطّريقة فحصُ العناصِر المُسجَّلة لديها دوريًّا للتّأكد من حالتها. ماذا عن إعادة ضبط الخدمة عند التّعديل على بيانات الإعدادات؟تُمثّل إعادة الضّبط ديناميكيًّا إحدى التّحسينات الأساسيّة على نموذج استكشاف الخدمة الأصلي. تعني إعادةُ الضّبط ديناميكيًّا قدرةَ أداة الاستكشاف على التّفاعل مع التّغييرات في مخزن الإعداد وضبط عناصِر التّطبيق حسب التّعديلات الجديدة؛ عكسَ النّموذج الأصلي الذي يقتصِر تأثيره على الإعداد الابتدائي للعُنصُر(عند بدْء تشغيله). على سبيل المثال، حينَ يفحص مُوزِّع حِمل الخواديمَ الخلفية ويجد أنّ أحدها توقّف عن العمل؛ فإنّه سيحتاج لأخذ ذلك بالحُسبان من أجل تعديل إعداداتِه لتُناسِب الوضعيّة الجديدة. توجد عدّة مشاريع تُركِّز على موزّع الحِمل نظرًا لكونه أحد التّطبيقات الأكثر احتيّاجًا لهذه الخاصيّة. يتميّز HAProxy بأنّه أحد أكثر هذه المشاريع شُهرةً لما يتمتّع به من شعبيّة بين المُهتمّين بآليّات توزيع الحِمل، في حين أنّ مشاريع أخرى تتمتّع بمرونة أكبر حيثُ بالإمكان استخدامُها لإحداث تغييرات في كل أنواع البرامج. تستعلم هذه الأدوات بانتظام خدمةَ الاستكشاف بحثًا عن تغييرات، وفي حال وجودها تستخدم نظام قوالب لتوليد ملفّاتِ إعداد جديدةً تُدمِج القيّم الّتي أرسلتها خدمة الاستكشاف. في الأخير يُعاد تشغيل التّطبيق لأخذ التّغييرات الجديدة في الحسبان. يحتاج هذا النّوع من الإعداد الدّيناميكي إلى تخطيط أكبر أثناء عمليّة بناء التّطبيق إذ أنّ كل هذه الآليّات يجب أن تتواجد في الحاويّة الّتي تُمثّل العُنصر، وهو ما يجعل من الحاويّة مسؤولةً عن تعديل إعداداتِها. يُمثِّل استخراج القيّم المطلوبِ كتابتُها في سجلّ استكشاف الخدمة، وتصميم بنية بيانات Data structure تسهُل الاستفادة منها تحدِّيًا آخر في بناء نظام إعداد ديناميكي. مع ذلك يُمكن لهذا النّظام أن يُقدّم مرونةً كبيرةً في الإعداد. ماذا عن الأمان؟يطرح كثيرٌ من المبتدئين مسألة الأمان عند الحديث عن مخازن الإعدادات المتاحة للعموم. هل من المُناسِب حقًّا حفظُ بيانات الاتّصال في أماكن يُتاح الوصول إليها للعموم؟ تختلف الإجابة على هذا السؤال كثيرًا حسب ما تُريد حفظَه في مخزن الإعدادات وحسب عدد طبقات الأمان الّتي ترى أنّها مناسِبة لتأمين بياناتك. تسمح أغلب أدوات استكشاف الخدمة بتعميّة Encryption الاتّصالات عن طريق SSL/TLS. يكفي وضعُ بعض أدوات الاستكشاف الّتي لا تهتم كثيرًا بالخصوصيّة Privacy في شبكة خاصّة، لكن وجود تأمين إضافي سيُفيد على الأرجح الكثير من التّطبيقات. يكمُن أحد الحلول الأمنيّة في إتاحة الوصول العموميّ إلى أداة الاستكشاف ولكن تُعمَّى (تُشَفَّر) البيانات المكتوبة ضمن سجل الأداة بحيثُ يتوجَّب على أي تطبيق يُريد الاستفادة من معلومة متاحة في السّجلّ امتلاكُ المفتاح السّري الخاص بهذه المعلومة حتّى يستطيعَ فكّ تعميّة Decrypty البيانات. تلجأ أدوات أخرى إلى مُقاربة مختفلة أساسُها إدخال قوائم تحكّم في الوصول Access control lists (أو ACL اختصارًا) لتقسيم فضاء المفاتيح إلى عدّة مناطِق، تُعرّف كل واحدة منها مُتطلّبات مُحدَّدة ويُعتَمَد عليها لإدارة مُلكيّة وإمكانيّة الوصول إلى المعلومات. تُؤسّس هذه المُقاربة لطريقة بسيطة تُوفّر لبعض الأطراف إمكانيّة الحصول على معلومات بينما تُبقيها خارج مُتناوَل أطراف أخرى. يُمكن ضبط كل عنصُر ليُتاح له الوصول إلى المعلومات الّتي يحتاجها فقط. ما هيّ أدوات استكشاف الخدمة الأكثر انتِشارًا؟نعرِض في الفقرات التّاليّة لبعض المشاريع الّتي تعمل على تنفيذ المبادئ العامّة المذكورة في الفقرات السّابقة. من أكثر هذه المشاريع رواجًا: etcd: أنشأها مطوّرو توزيعة CoreOS لتوفير أداة استكشاف خدمة وإعداد عموميّ مُوزَّع لكل من الحاويّات والأنظمة المُستضيفة. تمتلك هذه الأداة واجهةَ تطبيقات برمجيّة API يُتوَصَّل إليها عن طريق Http إضافةً إلى سطر أوامر على كل مُستضيف. consul: تتميّز هذه الأداة بالخصائص المتقدّمة الّتي توفّرها، مثل التحقّق من صلاحيّة الإعداد، قوائم التّحكّم في الوصول ACL، إعداد HAProxy، ...إلخ zookeeper: وهيّ أداة أقدم من السّابقتيْن. تتميّز بمنصّة أكثر ثباتًا، وذلك على حساب نقص بعض الوظائف الحديثة. المشاريع التّاليّة تعمل على تمديد وظيفة الأداة القاعديّة لاستكشاف الخدمة: Crypt: يُعطي التّطبيقات إمكانيّة تعميّة المعلومات التّي تحتفِظ بها في مخزن الإعدادات عن طريق مفتاح تعميّة عمومي Public key. يُمكِن للتّطبيقات الّتي لديها مفتاح فك التّعميّة Decryption key فقط قراءةُ هذه المعلومات. Confd: ويهدِف إلى إضافة قابليّة إعادة الضّبط ديناميكيًّا والتّحكّم في التّطبيقات حسب التّغييرات في خدمة الاستكشاف. يتضمّن هذا المشروع عدّة وظائف أهمّها مراقبَة مخزن الإعدادات بحثًا عن تعديلات، ونظامًا للقوالب يُستخدم لإنشاء ملفّات إعداد جديدة اعتمادًا على المعلومات المُمجمَّعة وقابليّة إعادة تحميل التّطبيقات عند تغيير إعداداتِها. vulcand: يعمل Vulcand كموزِّع حِمل بين مجموعات من العناصِر. يتعرّف هذا المشروع على أداة etcd ويُمكنه العمل وفقًا للتّغيرات في مخزن الإعدادات. marathon: وهو في الأساس مُجدوِل Scheduler (المقال الأخير من هذه السّلسلة يتناول المُجدوِلات)، ولكنّه يُضمّن آليّة بسيطة لإعادة تحميل HAProxy عند التّغيير على خدمات يجب توزيع الحِمل بينها. frontrunner: يُلحق بmarathon لتقديم آليّة متقدّمة لتحديث HAProxy. synapse: يُضمِّن HAProxy لتوجيه تدفّق البيانات بين مختلف عناصِر التّطبيق. nerve: يُستخدَم بالتّوازي مع synapse للتحقّق من صلاحيّة الإعداد لكل واحد من نظائر العُنصُر. عند توقّف أحد العناصِر عن العمل يُعلِم nerve أداة synapse لأخذ ذلك بالحسبان. خاتمةيسمح استكشاف الخدمة والمخازن العموميّة للإعدادات لحاويّات Docker بالتكيّف مع البيئة المُحيطَة وتغيير سلوك العناصِر الموجودة فيها، وهي مُتطلَّبات أساسيّة لتوفير قابليّة التوسّع والانتشار بسهولة ودون تدخّل يديوي. ترجمة -وبتصرّف- للمقال The Docker Ecosystem: Service Discovery and Distributed Configuration Stores1 نقطة
-
مقدِّمةتوجد دائمًا العديدُ من العوائق التي تقِف في طريقك أثناء الانتقال بين مختلف مراحل دورة التّطوير حتى الوصول إلى مرحلة الإنتاج. فإضافة إلى التّأكّد من سلامة عمل التّطبيق في بيئات مختلفة، فقد تُواجهك مشاكلَ مع تتبّع الاعتماديّات Dependencies، التوسّع Scaling، وتحديث كل واحد من العناصر المكوِّنة للتّطبيق دون أن يُؤثِّر ذلك على التطبيق ككلّ. يُحاول Docker التغلّب على العديد من هذه المشاكل عن طريق الحاويّات Containers وأسلوب التّصميم خَدَميّ التّوجّه Service-oriented الّذي يعتمده. تُقسَّم التّطبيقات إلى عناصِر وظيفيّة، تُحَزَّم منفردةً مع كامل اعتماديّاتها، يُمكن إدارتُها ونشرُها بسهولة على مِعماريّات Architectures مُتباينة. تمنح هذه الطّريقة أيضًا سهولةً أكبر أثناء التّوسّع أو التّحديث. نستعرِض في هذا المقال فوائدَ استخدام الحاويّات، وكيفَ يُساعد Docker في حلّ بعض المشاكل المذكورة أعلاه. Docker هو العنصر المركزي في النّشر المُوزَّع للحاويّات، حيثُ يوفِّر سهولةً في الإدارة وقابليةً للتّوسّع. تاريخ مُختصَر لإعداد الحاويّات على Linuxتدعمُ بعض أنظمة التّشغيل الشّبيهة بيونيكس Unix-like OS تقنيّات إعداد الحاويّات منذُ أكثر من عقد من الزّمن، فمفهومَا الحاويّة Container والعزل Isolation ليسَا جديديْن في عالم الحواسيب. على سبيل المثال، أُضيفَت بيئة LXC، التّي شكّلت قاعدةً لتقنيات تاليّة في إعداد الحاويّات، إلى النّواة Kernel في العام 2008. مَزَجت LXC بين استخدام مجموعات التّحكم Control groups (تسمح بعزل وتتبّع استخدام موارد الجهاز، يُشار إليها بـ cgroups اختصارًا) الموجودة في النّواة وفضاءات الأسماء Namespaces (عزل المجموعات بحيثُ لا تشعُر كل مجموعة بوجود أخرى) لإجراء عمليّة عزل بسيطة. قُدِّم Docker في ما بعد بوصفه طريقةً لتبسيط الأدوات المطلوبة لإنشاء وإدارة الحاويّات، فاستخدَم أوّلًا LXC كتعريف Driver للتّنفيذ، قبل أن ينتقل إلى استخدام مكتبة Library تُدعَى libcontainer أُعدَّت خصّيصًا لهذا الغرض. لم يُضِف Docker العديد من الأفكار غير الموجودة أصلًا، إلّا أنّه جعل إنجازَ هذه الأفكار متاحًا لشريحة أكبر من المُطوِّرين ومديري الأنظمة عن طريق تبسيط العمليّة وتوحيدها عبر نفس الواجهة وهوّ ما أدّى إلى تحفيز الاهتمام بإعداد الحاويّات على Linux بين المطوِّرين. تجدُر الإشارة إلى أنّه رغم تركيزنا هنا على حاويّات Docker التّي أوصلتْها شعبيّتُها المتناميّة إلى مرتبة المعيار Standard، إلّا أنّ بعضَ ما سنذكُره ينطبِق على الحاويّات بشكل عامّ. ما الّذي تُضيفه الحاويّات؟تأتي الحاويّات بالعديد من الفوائد الّتي تجذِب إليها كلًّا من المطوِّرين، مديري الأنظِمة، وفِرق العمليّات. في ما يلي بعضٌ من هذه الفوائد. 1- عزل نظام التّشغيل المُستضيف عن التّطبيق الموجود في الحاويّةتهدِف الحاويّات إلى أن تكون معياريّةً بالكامل؛ يعني هذا أنّ الحاويّة تتّصل بالمستضيف وبكل ما يوجد خارج الحاويّة عن طريق واجهات مُعرَّفة. يجب ألّا ينشغل تطبيقٌ يعمل عبر حاويّة بمعرفة تفاصيل موارد المُستضيف أو معماريّته. يُسهِّل هذا الأمر من افتراضات المطوِّر عن بيئة عمل التّطبيق. بالمثل، يتعامل المُستضيف مع كلّ حاويّة على أنّها صندوق أسود؛ فلا يهتمّ بتفاصيل التّطبيق الموجود بداخلها. 2- سهولة التّوسّعوهوّ أحد فوائد عزل المُستضيف عن التّطبيق. يُصبِح التوسّع سهلًا للغاية عند استخدام أسلوب تصميم جيّد أثناء تطوير التّطبيق. يُشكّل التّصميم خدميّ-التّوجّه (سنناقشه لاحقًا) عند دمجه بإعداد الحاويّات؛ اللّبنة الأساسيّة لسهولة التّوسّع . يُمكن -مثلًا - لنظام مُكوَّن من عدّة حاويّات أنشأه مطوّر على حاسوبه الشّخصي أن يتوسَّع أفقيًّا ضمن منطقة الإدراج Staging أو الاختبار Testing، وعند نقل الحاويّات إلى بيئة الإنتاج يستمرّ في التّوسّع مجدّدًا. ملحوظة: المقصود بالتّوسّع الأفقي Horizontal scaling هو استعمال عدّة خواديم وتشغليها بحيث تظهر وكأنّها خادوم واحد، أما التّوسّع العمودي Vertical scaling فيُقصَد به إضافة موارد جديدة لنفس الجهاز (زيادة حجم ذاكرة الوصول العشوائي RAM على سبيل المثال). لا يحتاج التّوسّع الأفقي في الغالب لإعادة تشغيل الجهاز أو الخادوم. 3- إدارة سهلة لاعتماديّات وإصدارات التّطبيقتُمكِّن الحاويّات المُبرمجين من تجميع تطبيق - أو عنصُر منه - مع كامل اعتماديّاته والتّعامل معه كوحدة مستقلّة. لا يهتمّ النّظام المُستضيف بالاعتماديّات الخاصّة بتطبيق معيَّن، فكل المطلوب منه هوّ أن تكون لديه القدرة على تشغيل حاويّات Docker. تجعل هذه الطّريقة من إدارة الاعتماديّات أمرًا سهلًا؛ كما أنّها تُسهّل من إدارة إصدارات البرنامج Versions، فالأنظمة المُستضيفة وفرق العمليّات ليست مسؤولة عن إدارة الاعتماديّات المطلوبة من طرف التّطبيق، فكل ما يحتاجه التّطبيق - إذا استثنينا علاقته بالحاويّات الأخرى - موجود داخل الحاويّة. 4- بيئات تنفيذ Execution معزولة وخفيفة جدَّاعلى الرّغم من أن الحاويّات لا توفّر نفس المستوى من العزل الّذي توفّره الحوسبة التّخيّلية Virtualization إلّا أنّها تفضُلُها من ناحية خفّة بيئة التّنفيذ. تُعزَل الحاويّات على مستوى العمليّات Process Level وتشترك في نواة المُستضيف. يعني هذا أنّ الحاويّة لا تتضّمّن نظامَ تشغيل كاملًا وهو ما يؤدّي إلى بدْء تشغيل يكاد يكون لحظيًا. يُمكن للمطوّرين تشغيل مئات الحاويّات على حواسيبهم الشّخصيّة دون أيّة مشاكل. 5- طبقات مُشتركة Shared layeringجانب آخر تتجلّى فيه خفة الحاويّات هو تقاسمُها لنفس الطّبقات الأساسيّة. يعني اشتراكُ عدّة حاويّات في نفس الطّبقة، الحدَّ من الاستنساخ/التّضاعف Duplication؛ أي استخدامًا أقلّ لمساحة القرص الصّلب والموارِد بشكل عامّ عند إنشاء حاويّات جديدة. 6- قابليّة التّجميع والتّنبّؤ Composability and Predictabilityتُعرِّف ملفّات Docker بالضّبط الإجراءاتِ المطلوبةَ لإنشاء صورة جديدة من حاويّة، وهو ما يُمكِّن من كتابة بيئة التّنفيذ كما لو كنتَ تكتب أسطُرًا برمجية وحفظها عن طريق نظام لإدارة الإصدارات Version Control System (أو VSC اختصارًا) إذا رغبتَ في ذلك. يُنتِج نفس ملف Docker عند إنشائه في نفس البيئة، يُنتِج دائمًا صورةً لنفس الحاويّة. استخدام ملفّات Dockerfiles لعمليّات البناء المُتكرّرة المُتماثِلةيُمكن بناء صوّر Images من حاويّات Docker بطريقة تفاعليّة ولكن من الأفضل غالبًا وضع خطوات الإعداد بعد الانتهاء من تحديدها في ملف Dockerfiles. ملفّات Dockerfiles هيّ ملفّات بناء بسيطة تُعرِّف آليةَ بناء حاويّة انطلاقًا من نقطة بدْء معروفة. استخدام هذه الملفّات بسيطٌ جدًّا ولديها العديد من الفوائد، نذكر منها: سهولة إدارة الإصدارات: يُمكِن حفظ ملفّات Dockerfiles ضمن برنامج لإدارة الإصدارات لتتبّع التّغييرات والتّراجع عن أي أخطاء عند اكتشافها. قابليّة التّنبّؤ: بناء الحاويّات انطلاقًا من ملفات Dockerfiles يُساعِد في التّقليل من الأخطاء البشريّة أثناء عمليّة إنشاء الحاويّات. قابليّة المُحاسبة Accountability: من الجيّد عند التّخطيط لمشاركة صوّر الحاويّات، توفيرُ ملف Dockerfile المُستخدَم لإنشاء الحاويّة لاستخدامه كوسيلة للتّدقيق في عمليّة البناء، حيثُ يُمكن النّظر إليه باعتباره سجِلًّا للأوامر التي نُفِّذَت لإنشاء الحاويّة. المرونة Flexibility: يسمح إنشاءُ حاويّات انطلاقًا من ملفّات Dockerfiles بتجاوز الخيّارات الافتراضيّة المُعطاة في عمليّات البناء التّفاعليّة. يعني هذا أنّك عند استخدام Dockerfiles لن تحتاج لتغيير كل الإعدادت الافتراضيّة الّتي لا تُناسِب احتيّاجاتِك. من هذا المُنطَلَق فإن ملفّات Dockerfiles أداة رائعة لأتمتة Automate إنشاء الحاويّات والتّأسيس للعمليّات المتكرّرة. بُنية التّطبيقات الّتي تعمل عبر الحاويّاتبُنية التّطبيق هيّ أحد أهم المشاغِل الّتي يجب أخذها بالاعتبار عند تصميم تطبيقات مُعدّة للنّشر عبر حاويّات.عمومًا، تعمل الّطبيقات المنشورة عبر حاويّات بشكل أفضل عند تنفيذ تصميم خَدَمي التّوجّه. تُقسِّم التّطبيقات الّتي تتبع تصميمًا خَدَمي التّوجّه وظيفتَها بين عدّة عناصر متمايِزة تتواصَل في ما بينها عبر واجهات مُعرَّفة جيّدًا. تُشجّع تقنيّة الحاويّات بذاتها هذا النّوع من التّصميم إذ أنّه يسمح لكلّ عنصُر بالتّوسّع والتّرقية بشكل منفصل عن بقيّة العناصِر. يجب أن تتوفّر الخصائص التّاليّة في التّطبيقات الّتي تتبع طريقة التّصميم خَدَمي التّوجّه: لا تعتمد على أي وظيفة خاصّة بنظام تشغيل مُستضيف مُحدّد. يُوفّر كل عنصُر واجهة تطبيقات برمجيّة API مُتجانِسة يُمكن للزّبائن عبرها الاتّصال بالخدمة. يجب أن تأخذ الخدمةُ متغيّراتِ البيئة Environmental variables الّتي تعمل بها أثناء الإعداد الابتدائي. يجب أن تُحفَظ بيانات التّطبيق خارج الحاويّة في تجزئات مُرَكَّبة Mounted volumes على النّظام أو في حاويّات خاصّة بالبيانات. تُمكِّن هذه الإستراتيجيّات من استبدال أي عنصُر أو تحديثه بشكلٍ مستقل شرطَ الحفاظ على واجهته البرمجيّة، كما أنّها تُساعد في التّركيز على التّوسّع الأفقي حيثُ يُوَّسَّع العنصُر الذي يُعرقل أداء التّطبيق (نقطة ضعف).يُمكن لكل عنصر تعريفُ قيّم افتراضيّة يُمكن الإقلاع باستخدامها في فترة معقولة، بدلًا من برمجة قيّم خاصّة مباشرَةً في التّطبيق. يُمكن للعنصُر استخدامُ هذه القيّم في الحالات الطّارئة مع تفضيل قيّم يُمكن الحصول عليها عن طريق بيئة العمل. يُتَحصَّل على قيّم من بيئة العمل عادةً عن طريق أدوات مُساعدة على استكشاف الخدمة، يستطيع العُنصر إرسال استعلامات إليها أثناء بدْء التّشغيل. يُسهِّل إخراج بيانات الإعداد من الحاويّة ووضعُها في بيئة العمل من إجراء تعديلات على سلوك التّطبيق دون الحاجة لإعادة بناء الحاويّة، إضافةً إلى إمكانيّة التّأثير على نماذج عدّة من نفس العُنصُر عن طريق إعداد واحد. على العموم فإنّ أسلوب التّصميم خَدَمي التّوجّه يندمج جيّدًا مع إستراتيجيّات الإعداد عن طريق بيئة العمل، فكلّ منهما يسمح بعمليّات نشر مرنة وتوسّع أكثر مباشرة. استخدام سجلّ Docker Registry لإدارة الحاويّاتتحدّثنا عن الخطوة الأولى المُتمثِّلة في تقسيم التّطبيق إلى عناصر وظيفية مُعدَّة للتّواصل بشكل صحيح مع بقيّة الحاويات وقيّم الإعداد الموجودة في بيئة العمل. نأتي الآن للخطوة الثّانية وهي جعل صوّر الحاويّات مُتاحة عبر سجل. رفع صوّر الحاويّات إلى سجل يُعطي مستضيفات Docker إمكانيّة تنزيل هذه الصوّر بمجرَّد معرفة أسمائها ثم إنشاء حاويّات مُماثلة لها بعد ذلك (نظائر Instances). توجد العديد من سجلّات Docker متوفّرة لهذا الغرض؛ بعضُها عمومي يُمكن للجميع عرض واستخدام الصّوّر الموجودة فيها، والآخر خاص. يُمكن أيضًا إضافة وسوم Tags لتسهيل الوصول إلى وتحديث الحاويّات. خاتمةيضع Docker القواعدَ الأساسيّة اللّازمة للنّشر الموزَّع للحاويّات. يجعل عزل عناصر التّطبيق في حاويّات خاصّة بها من التّوسّع الأفقي عمليّةً سهلة تقتصِر على إطلاق نظائر جديدة لنفس العُنصُر أو إيقاف أخرى. يُوفِّر Docker الأدوات المطلوبة ليس فقط لبناء حاويّات بل أيضًا لإدارتها وتشاركها مع مستخدمين أو مُستضيفين جُدُد. في المقال التّالي من هذه السّلسلة سنتطرّق للكيفيّة الّتي تُساهِم بها استكشاف الخدمة ومخازن الإعداد المُوزَّعة عمومًا في نشر الحاويّات عبر عنقود من المُستضيفات. ترجمة -وبتصرّف- للمقال The Docker Ecosystem: An Overview of Containerization1 نقطة
-
لغات لازمة لعمل مواقع بشكل متقن هي: Html Css JavaScript و هذه اللغات تحت بند تصميم واجهات مواقع Front-end، و يجب تعلم مكتبة JQuery فهي تسهل عملك مع JavaScript، كما يجب عليك تعلم أحد لغات برمجة جهة سيرفر و هي: Php Ruby on rails Python و غيرها و هذه اللغات تحت بند برمجة جهة السيرفر كما قلت سابقاً Back-end،1 نقطة
-
لا قيمة لمدوّنتنا إن لم يكن باستطاعتنا كتابة التّدوينات الجديدة ونشرها، لذا علينا إنشاء صفحة تُتيح لنا (لنا فقط) كتابة تدوينة جديدة وحفظها في قاعدة البيانات. لكن أوّل ما يتبادر إلى الذّهن تساؤل عن الكيفيّة الّتي نستطيع أن نمنع فيها الزّائر من إضافة التّدوينات، إذ كيف يستطيع المتصفّح والخادوم التّفريق بين صاحب المدوّنة وزائرها؟ ملايين المواقع على الويب تقدّم محتوىً مخصّصًا لكلّ مستخدم، إذا عدنا لمثال فيس بوك وطرحنا السؤال ذاته: كيف يعرض فيس بوك نشرة أخبار خاصّة بكلّ مستخدم؟ بالطّبع لكلّ مستخدم حساب في الموقع محميّ بكلمة مرور، لكن ما الذي يحدث بين المتصفّح والخادوم ويجعل الخادوم يُرسل الصّفحة الخاصّة بالمستخدم إليه دون غيره؟ إن كنت سمعت من قبل بالكعكات (cookies) ولم تعرف ما علاقتها بالويب، فقد حان الوقت لنعرف ما هي وكيف تستخدم. الكعكات (Cookies)الكعكات هي أجزاء صغيرة من البيانات تخزّن في المتصفّح وتنتقل بينه وبين الخادوم مع كلّ طلب إلى هذا الخادوم (كترويسة Heading في طلب HTTP)، يمكن للخادوم أن يأمر المتصفّح بحفظ بيانات جديدة ضمن الكعكات، ويمكن للمتصفّح منع تخزين هذه البيانات بأمر المستخدم أو حذفها متى شاء. تُستخدم الكعكات بشكل شائع لتخزين "الجلسة" (session)، وهي الطّريقة الّتي يتذكّر بها الخادوم هذا المتصفّح بين الطّلب والآخر بحيث يستطيع تمييزه من بين الطّلبات الّتي تصله من حواسيب مختلفة حول العالم. من المهمّ أن نعرف أنّ طلبات HTTP هي طلبات مستقلّة بذاتها وعديمة الحالة (stateless)، بمعنى أن كلّ طلب يصدر من المتصفّح للخادوم نفسه لا يعرف أيّ شيء عن الطّلبات السّابقة أو اللاحقة، وكذلك الخادوم؛ إلا إذا تمّ إرفاق معرّف مُميّز (session ID) يتّفق عليه الطّرفان وينتقل مع كلّ طلب بين الجهتين. بدون الجلسات كنت ستحتاج إلى إدخال اسم مستخدمك وكلمة المرور في كلّ مرة تنتقل فيها إلى صفحة جديدة على فيس بوك! من المهمّ إذًا أن يكون معرّف الجلسة (session ID) مُميّزًا للمتصفّح ولا يتطابق مع معرّف جلسة أي متصفّح آخر، وهذا يتمّ بتوليد معرّف الجلسة بشكل عشوائي على الخادوم أولًا ثمّ إرساله للمتصفّح لحفظه ضمن الكعكات، وسيقوم المتصفّح بنقل الكعكات مع كلّ طلب، ممّا يسمح للخادوم بمعرفة تتابع الطّلبات من نفس المتصفّح. من الاستخدامات الأخرى للكعكات تتبّع المستخدمين بين المواقع عن طريق استضافة محتوى من طرف ثالث ضمن صفحة الموقع (third-party cookies) وهي حيلة تستخدم لمعرفة ذوق المستخدم وتوجّهه من خلال أنواع المواقع الّتي يزورها وبالتّالي استهدافه بالإعلانات أو مراقبة نشاطه. لا غرابة أن تعطينا المتصفّحات وسيلة لمنع كعكات الطّرف الثّالث، أو لمنع الكعكات بالكامل! لنلخّص الأمر: تسمح الجلسات بربط طلبات HTTP المتتالية بحيث يتعرّف الخادوم على كونها صادرة من جهة واحدة، مما يسمح له بتخصيص الإجابة على هذه السلسلة من الطّلبات دون غيرها، سنستفيد من هذا في حفظ تسجيل الدّخول المستخدم بحيث لا نطلب منه كلمة المرور عندما ينتقل من صفحة لأخرى. لنعد الآن إلى شيفرة تسجيل الدّخول ولنفكّر، ما الذي نحتاجه لحفظ الجلسة؟ عندما يُسجّل المستخدم دخوله للمرّة الأولى، نحتاج إلى حفظ مُعرّف الجلسة على الخادوم ليكون بإمكاننا مقارنته مع الطّلبات التّالية، وهذا يعني أنّنا بحاجة لوسيلة لحفظ معرّف الجلسة لكل مستخدم. في Express يتوفّر البرنامج الوسيط express-session الذي يتولّى هذه المهمّة كاملةً. قم بتثبيت هذه الوحدة، ثم لنقم باستيرادها: var express = require('express'); // ... var session = require('express-session');نريد استخدام express-session على مستوى التّطبيق بالكامل، ما يعني أنّنا نريد لها أن تتعقّب كلّ الطّلبات على جميع الرّوابط المسجّلة مما يسمح بمتابعة الجلسة، تسمّى هذه الوحدات البرامج الوسيطة على مستوى التّطبيق (Application-level middleware) بعكس الأسلوب الّذي استخدمناه في body-parser لتفسير متن الطّلب في نماذج إنشاء المستخدم وتسجيل الدّخول (برامج وسيطة على مستوى المُوجّه Router-level middleware). يمكن للوحدة أن تُستعمل بالأسلوبين. تستخدم الوحدات على مستوى التّطبيق باستدعاء الوظيفة use() لتطبيقنا: app.use(session({ secret: "my top secret", resave: false, saveUninitialized: true })); تستقبل وحدة session كائن الإعدادات الذي يتضمّن: secret: كلمة سرّيّة تسمح بتجزئة معرّف الجلسة لحمايته، ضع ما تشاء هنا.resave: هل يجب كتابة الجلسة مع كلّ طلب حتّى وإن لم تتغيّر؟saveUninitialized: هل يجب حفظ الجلسات الجديدة تلقائيًّا إلى الخادوم؟لا تقلق إن كانت هذه الإعدادات غامضة، ستتعرّف على فائدتها مع مرور الوقت. تذكّر أنّ ترتيب استدعاءات البرامج الوسيطة مهمّ، يجب أن نضيف الشّيفرة السّابقة قبل تسجيل الروابط لنتمكّن من متابعة الجلسة عبر كلّ الرّوابط المسجّلة. حسنًا من المفترض الآن أن يقوم المتصفّح بحفظ معرّف الجلسة ثم نقله مع كلّ طلب، لنتحقّق من هذا؛ شغّل البرنامج ثم زر الصفحة الرئيسية للمدوّنة، افتح أدوات المطوّرين (Ctrl + Shift + K في فيرفكس)، ثم انتقل إلى تبويب الشّبكة واضغط زر إعادة تحميل الصّفحة، سيبدأ المتصفّح بمراقبة الطّلبات، سيظهر طلب للصفحة الرئيسيّة مع بداية تحميلها، انقر عليه وابحث عن ترويسة Cookie في الجانب، لاحظ أنّها تحوي قيمة connect.sid، وهذا هو المعرّف المميّز الذي سينتقل بين الطّلبات، للتأكد من ذلك انتقل إلى صفحة أخرى مثل /posts/hello-world وكرّر العمليّة، ستجد أن معرّف الجلسة ثابت لا يتغيّر. عظيم! أصبح بإمكاننا الآن تمييز الطّلبات ومتابعتها، لكن ما الفائدة التي جنيناها إلى الآن! في الحقيقة لا شيء، نحتاج إلى الاستفادة من كون معرّف الجلسة مميّزًا بحيث نعلم أن المستخدم الذي تحمل طلباته هذا المعرّف قد سجّل دخوله فلا نطلب منه كلمة المرور في كلّ طلب، وسنستفيد من ذلك أيضًا في تخصيص محتوى الصّفحة وإتاحة وصول الكُتَّاب إلى صفحة إنشاء التّدوينات فيما بعد. نحتاج إلى حفظ معرّف الجلسة في جدول بقاعدة البيانات لنتمكّن من طلبه لاحقًا ومقارنته مع الطّلبات القادمة، لنُنشئ جدولاً يحفظ معرّفات الجلسات لكلّ مستخدم: CREATE TABLE `sessions` (session_id VARCHAR(100) NOT NULL PRIMARY KEY, username VARCHAR(50) NOT NULL, FOREIGN KEY (username) REFERENCES `users` (username), INDEX (username));من المهمّ أن نفهم أنّ معرّف الجلسة يحلّ محلّ كلمة المرور واسم المستخدم معًا، لهذا من الضّروري أن يكون مميّزًا (PRIMARY KEY) بحيث لا يتطابق معرّفان لمستخدمين مختلفين، من المهمّ، للسبب ذاته، حماية الجلسة وتوليدها بطريقة عشوائية، وهذا هو سبب استخدامنا للكلمة السّريّة secret في إعدادات express-session، من إجراءات الأمان الشّائعة إضافة مهلة تنتهي بعدها صلاحيّة الجلسة، وهذا هو السّبب الذي تطالبك لأجله بعض المواقع بإعادة تسجيل دخولك بعد فترة من الزّمن؛ لكنّنا لن نُشغل بالنا بهذه التّفاصيل الآن. حسنًا لدينا الآن معرّف الجلسة وجدول لحفظه، كل ما نحتاجه عند تسجيل الدّخول بشكل صحيح حفظ معرّف الجلسة إلى الجدول، لنعد إذًا إلى شفرة تسجيل الدّخول الّتي تركناها في الفقرة السّابقة: /* ... */ var cookieParser = require("cookie-parser"); app.use(cookieParser()); /* ... */ app.post("/sessions", parseBody, function(request, response, next) { var username = request.body.username; var password = request.body.password; if (!username || !password) { response.status(400); response.send("يجب توفير اسم المستخدم وكلمة المرور"); return; } connection.query("SELECT username, password FROM `users` WHERE username=?", [ username ], function(err, rows) { var user = rows[0]; if (!user) { response.status(400); response.send("لا يوجد مستخدم يطابق اسمه اسم المستخدم المطلوب"); return; } bcrypt.compare(password, user.password, function(err, result) { if (err) { response.status(500); response.send("وقع خطأ من جهة الخادم، حاول تسجيل الدخول لاحقًا"); return; } if (result == true) { connection.query("INSERT INTO `sessions` (session_id, username) VALUES (?, ?)", [ request.cookies["connect.sid"], username ], function(err) { if (err) return next(err); // تعامل مع الخطأ response.status(200); response.send("تم تسجيل الدّخول"); }) } else { response.status(401); response.send("كلمة المرور التي أرسلتها خاطئة"); } }) }); }) توفّر لنا express-session معرّف الجلسة ضمن الكعكة تحت الاسم connect.sid والذي يمكن تغييره بضبط القيمة name في إعدادات الوحدة. استخدمنا الوحدة cookie-parser التي تقوم بما يوحي به اسمها وتوفّر لنا الكعكات ضمن كائن الطّلب للحصول على معرّف الجلسة. نكاد ننتهي من إنشاء نظام المستخدمين، بقي علينا فقط إرفاق معلومات المستخدم مع كلّ دالّة توجيه لنتمكّن من عرض اسم المستخدم في الصّفحة وإتاحة تسجيل الخروج، بل يمكننا أيضًا توجيهه إلى صفحات خاصّة به أو منعه من الوصول إلى صفحات أخرى، سنقوم بإضافة دالّة توجيه تسبق جميع روابطنا وتقوم بإرفاق بيانات المستخدم (بعد جلبها من قاعدة البيانات) وإضافتها إلى كائن الطّلب: app.use(function(request, response, next) { var session_id = request.cookies["connect.sid"]; if (session_id) { connection.query("SELECT users.id, users.username, full_name, is_author FROM `users` JOIN `sessions` ON users.username=sessions.username WHERE session_id=?", [ session_id ], function(err, rows) { if (!err && rows[0]) { request.user = rows[0]; } next(); }) } else { next(); } }) في الحقيقة، ما كتبناه للتوّ ليس سوى برنامج وسيط، لا يختلف في شيء عن البرامج الوسيطة التي استعملناها مثل express-session عدا أنّ الأخيرة يوفّرها مطوّرون آخرون كحزمة على npm يمكن استيرادها. في دوال التّوجيه التّالية، سيتوفّر لدينا كائن request.user يتضمّن معلومات المستخدم الحالي، لنجرّب ذلك بإنشاء صفحة الملفّ الشّخصي للمستخدم (views/profile.jade): doctype html html(lang="ar", dir="rtl") head title الملف الشخصي body style :css body { font-family: Arial, sans-serif; } if (user) h1 #{ user.full_name } (#{ user.username }) hr else p لم تقم بتسجيل دخولك app.get("/profile", function(request, response) { response.render("profile", { user: request.user }) }) سنقوم بتوفير الكائن request.user للقالب، والذي سيكون غير معرّف إن لم يُوجد في قاعدة البيانات أو إن لم يسجل المستخدم دخوله، سيتولى القالب هذه الحالة ويعرض الرسالة المناسبة. لاحظ دعم Jade للجمل الشّرطيّة. حسنًا، لنجرّب الآن ما كتبناه، شغّل البرنامج ثم زر الصفحة http://localhost:3000/login، سجّل الدّخول باسم المستخدم admin وكلمة المرور 123456، من المفترض أن تنتقل إلى صفحة تخبرك بنجاح العملية، الآن انتقل إلى http://localhost:3000/profile لتشاهد الملف الشّخصيّ (حسنًا لا يبدو عظيمًا جدًّا، لكنّنا سنحسّنه لاحقًا): تهانينا! لقد أنشأنا نظامًا للمستخدمين وأصبح بإمكاننا عرض محتوى مخصّص لكلّ مستخدم! في الجزء القادم سنتيح لأنفسنا كتابة التّدوينات، وللمستخدمين إضافة التعليقات، وستكون أعظم مدوّنة في التّاريخ!1 نقطة