-
المساهمات
46 -
تاريخ الانضمام
-
تاريخ آخر زيارة
آخر الزوار
1774 زيارة للملف الشخصي
إنجازات أروى عفان
![الرتبة: عضو نشيط (3/3) عضو نشيط](https://academy.hsoub.com/uploads/set_resources_28/84c1e40ea0e759e3f1505eb1788ddf3c_default_rank.png)
عضو نشيط (3/3)
5
السمعة بالموقع
-
يُعَدّ التوثيق التقني أمرًا ضروريًا في تحسين تجربة المستخدم، حيث يوفر إرشادات واضحة حول كيفية استخدام منتج أو تطبيق ويشجعهم على استخدامه وتجربته، يقدم هذا المقال نظرة عامة على المبادئ الأساسية لكتابة التوثيقات التقنية، ويسلّط الضوء على أفضل الممارسات لإنشاء وثائق واضحة وسهلة الفهم. وسواء كنتم بحاجة لتوثيق مشاريعكم أو منتجاتكم البرمجية، أو كتابة أي محتوى تقني آخر، سيساعدكم تطبيق المبادئ التي سنشرحها في الفقرات التالية على كتابة التوثيقات التقنية بجودة عالية. ما هو التوثيق التقني التوثيق التقني هو بمثابة دليل استخدام أو كتيب إرشادات خاص بتقنية ما، حيث يركز على توفير معلومات تفصيلية للمطورين والمستخدمين، ويتضمن وصفًا تفصيليًا حول طريقة التعامل معها، وشرحًا للتفاصيل الفنية الخاصة بها من دوال وواجهات برمجية، ومعلومات عن صيانتها وحل المشكلات الشائعة التي قد تواجههم عند التعامل معها. لنتعرف على أهم النصائح الواجب اتباعها لكتابة التوثيقات التقنية بوضوح واحترافية. أولًا: الالتزام بالوضوح والإيجاز والاتساق تشكل هذه العناصر الثلاثة المبادئ الأساسية لكتابة التوثيقات التقنية، وتساعد في إنشاء وثائق عالية الجودة، ولنوضح كل عنصر من هذه العناصر بمزيد من التفصيل. الوضوح كي يحقق التوثيق التقني سمة الوضوح، يتوجب علينا تطبيق الإرشادات التالية: استخدام كلمات بسيطة ولغة واضحة ووضع الجمهور المستهدف في الحسبان الوضوح عند كتابة تعليمات لتنفيذ دالة ما، ويفضل استخدام الأفعال المبنية للمعلوم لتوضيح الفاعل وتحديد هل ستُشَغّل الدالة بواسطة حدث معين، أم على المستخدم استدعاؤها بشكل صريح شرح المصطلحات الجديدة بوضوح، حيث يساعد ذلك في وضع أساسيات للمفاهيم التي سنتحدث عنها لاحقًا استبدال الضمائر بأسماء علم إن كانت تشير لأكثر من شيء واحد في السياق المحدد تقديم فكرة واحدة في كل جملة لتحسين المقروئية، والالتزام بفكرة رئيسية واحدة في كل فقرة ربط كل جملة منطقيًا بالجمل التي قبلها، كما لو أن كل جملة في الفقرة هي حلقة في سلسلة، فإن فهمنا الحلقة الأولى، فيجب أن تتبعها الحلقات الأخرى في السلسلة، لتشكل سلسلة مترابطة تتدفق فيها الأفكار بسلاسة الإيجاز من الجيد إبقاء الجمل قصيرة وموجزة قدر المستطاع لتعزز وضوح المستند وسهولة قراءته، وتساعد على الفهم السريع، فقد يكون فهم الجمل الطويلة أصعب بسبب بنيتها المعقدة. وبناءً على معايير سهولة القراءة الشائعة، من الأفضل كتابة 15 إلى 20 كلمة وسطيًا في كل جملة. وللحصول على معلومات إضافية حول هذا المعيار ننصح بمطالعة صفحة المقروئية على ويكيبيديا. الاتساق يتوجب علينا استخدام نفس المصطلحات في التوثيق البرمجي لضمان تجربة قراءة سلسة. على سبيل المثال، إذا استخدمنا مصطلح وكلاء المستخدم user agents للإشارة إلى المتصفحات browsers، فعلينا الالتزام بهذا المصطلح في كل السياق، إذ يجنبنا ذلك الالتباس الذي قد ينشأ نتيجة لاستخدام مصطلحات عدة، حتى لو كان لها المعنى نفسه. كما ينبغي اتباع أسلوب تنسيق موحد في جميع الوثائق، والحفاظ على تناسق الكلمات، من حيث استخدام الأحرف الكبيرة والصغيرة -في حال استخدام اللغة الإنجليزية في التوثيق- إذ تُحَسّن هذه الممارسات مقروئية المستند، وتظهره بشكل احترافي. ثانيًا: تنظيم المحتوى ينبغي أن نطبّق نفس القواعد المستخدمة لتنظيم الشيفرات البرمجية عند تنظيم المحتوى التقني، وذلك من خلال تحديد هدف واضح للمحتوى، والتفكير في البنية التي نريد اعتمادها في التوثيقات. والحرص على أن تساهم كلّ الأقسام الفرعية في تحقيق هذا الهدف تدريجيًا، ولنوضح أهم الأقسام التي تساعدنا على تنظيم محتوانا التقني. مقدمة التوثيق أولاً، علينا وصف الميزة التقنية التي سنوثّقها في المقدمة، ونوضّح لماذا سيكون التعرف على تلك الميزة مفيدًا كأن نذكر حالات عملية مفيدة لاستخدامها. فكلما أضفنا حالات واقعية ذات أهمية، سَهُلَ على القراء فهم المحتوى والتفاعل معه. التسلسل المنطقي ستساعدنا الأسئلة التالية في تنظيم المحتوى وفق تسلسل منطقي صحيح: هل التوثيق مصمم لتوجيه القراء بدايةً من المفاهيم الأساسية إلى المفاهيم المتقدمة هل توجد أقسام مخصصة للتعريف بالأساسيات النظرية وكل ما يلزم، قبل الانتقال إلى كيفية التنفيذ هل تُماثِل بنية المستند مسار التعلم الطبيعي للموضوع، فهذا يساعد على بناء المعلومات خطوة خطوة ويعزز تجربة التعلم هل توجد أدلة إرشادية وأمثلة كافية تعزز الأقسام النظرية والمفاهيمية هل يتبع المحتوى تسلسلاً منطقيًا من حيث الجمل والفقرات والأقسام وهل يعتمد كل قسم على المعلومات السابقة، مع تجنب الفجوات في المحتوى استخدام الأمثلة استخدام الأمثلة في التوثيق البرمجي أمر بالغ الأهمية ويساعدنا على توصيل الفكرة بوضوح وسهولة، يمكن أن نتخيل أننا نجلس بجوار شخص ما ونشرح له المفاهيم، كما يمكن أن نستبق أسئلته ونعالجها في الكتابة، ونستخدم هذا الأسلوب لإضافة أكبر عدد ممكن من الأمثلة الواضحة ذات الصلة بما نشرحه. وعند كتابة التوثيق البرمجي، ليس بالضرورة أن نقتصر على تقديم الأمثلة البرمجية فقط بل يمكننا أيضًا تضمين أمثلة عملية وحالات غير برمجية تساعد في توضيح فائدة الميزة وكيفية استخدامها وتطبيقها عمليًا. هذا سيساعد القراء على استيعاب المفاهيم بصورة أفضل ويلبي أيضًا أنماط التعلم المختلفة. ثالثًا: تحسين بنية التوثيق من الضروري تقييم بنية مستندات التوثيق للتأكد من أنها تحافظ على تسلسل هرمي منطقي ومتوازن باتباع الإرشادات التالية: يجب أن يكون لكل قسم رئيسي ولكل قسم فرعي غرض واضح، ولا يجب أن يكون هناك أقسام بلا هدف محدد أو بلا محتوى كافٍ التعامل مع الأقسام اليتيمة Orphan Sections وهي الأقسام الرئيسية التي تحتوي على قسم فرعي واحد فقط، كأن يكون لدينا قسم فرعي واحد من المستوى الثالث H3 ضمن قسم رئيسي من المستوى الثاني H2، هذا يشير لضرورة إعادة توسيع هذا القسم أو دمجه مع قسم آخر التحقق من عدم وجود الكثير من العناوين من المستوى الرابع H4، فكثرة الأقسام الفرعية قد يكون مرهقًا للقراء، وقد يُصعّب عليهم فهم المعلومات الانتباه للطول الإجمالي لكل قسم فإذا كان أحد الأقسام طويلًا جدًا، فقد يشتت القارئ، لذا نقسّم الأقسام الكبيرة لأقسام فرعية منطقية متعددة، أو نعيد هيكلة المحتوى تدقيق المحتوى من أكثر الخطوات أهمية في التوثيق البرمجي هي المراجعة الذاتية وتدقيق المحتوى، سواء كنا بصدد إنشاء مستند كبير أو فقرة قصيرة، فهذه الخطوة ضرورية جدًا. لذا نحتاج لأن نخصص وقتًا مناسبًا لمراجعة العمل كاملًا ونحدد الأقسام التي يمكن تحسينها وتوضيحها أكثر، ونزيل الحشو من الأفكار التي لا تضيف قيمة، ونتخلص من الكلمات والعبارات المكررة. ستضمن هذه التعديلات وضوح النص وتماسكه ووصول الأفكار على النحو المطلوب. كما نحتاج لتدقيق المحتوى لغويًا ويفضل أن نستريح قليلًا قبل مراجعته مرة أخرى، ونبحث عن أي تناقضات في الأسلوب أو أزمنة الأفعال أو التنسيق ثم نعدّل ما يلزم فالمراجعة بعد فترة من الاستراحة تمكننا من ملاحظة الأخطاء التي قد تفوتنا أول مرة. نصائح إضافية نختم بجملة من النصائح التالية لتحسين وضوح الوثائق التقنية: استخدام القوائم ذات التعداد الرقمي عندما يتوجب علينا اتباع الخطوات بترتيب محدد، أو التعداد النقطي عندما لا يكون للعناصر ترتيب محدد، ونسبق القائمة دائمًا بجملة أولية توضح السياق استخدام الفواصل وعلامات الترقيم المناسبة لتحسين المقروئية وتوضيح بنية الجملة وضع نص بديل Alternative text للصور، وإرفاق ملفات الفيديو والصوت بنصوص وصفية لجعل الوثائق مناسبة للجميع الحرص على أن تكون جميع نصوص الروابط واضحة وتشير بوضوح إلى وجهة الرابط لمساعدة الأشخاص الذين يستخدمون برامج قراءة الشاشة على فهم وجهة الروابط. مثلًا، نستخدم الجملة التالية اطلع على بعض الأدوات مجانية لتحسين محركات البحث بدلاً من جملة انقر هنا استخدام لغة مناسبة ومفردات تحترم تنوع الجمهور، وتجعل من الوثائق موضع ترحيب للجميع الخاتمة بهذا وصلنا إلى نهاية مقالنا الذي قدمنا فيه نصائح مفيدة للمطورين والكتّاب التقنيين المهتمين بتحسين جودة التوثيقات التقنية والبرمجية. ولنتذكر في الختام أن إنشاء توثيقات تقنية فعالة وسهلة الاستخدام عملية مهمة تبدأ بفهم الجمهور المستهدف والهدف من الوثائق التي نكتبها، مع الحرص على تطبيق المبادئ التي تعلمناها لتحسين جودة الوثائق وفهمها. ترجمة، وبتصرّف، للمقال Creating effective technical documentation لكاتبته Dipika Bhattacharya. اقرأ أيضًا كيف تكتب كود برمجي مثل مهندسي البرمجيات هل تحتاج لمراجعات تقنية مستقلة قائمة مراجعة المشروع البرمجي أسس القيادة التقنية قواعد البرمجة ببساطة للمبتدئين
-
تتقدم التقنيات بسرعة في أيامنا، ويأتي الذكاء الاصطناعي وتعلم الآلة في طليعة الابتكار التقني، إذ تُطوَّر أدوات الذكاء الاصطناعي الجديدة بانتظام، وتتغير طريقة تنفيذنا للمهام في مختلف الصناعات، وتتنوع الأساليب التي يتبعها المطورون لابتكار الحلول الحلول البرمجية. فالذكاء الاصطناعي وتعلم الآلة اليوم من الأدوات القوية التي يمكنها أن تساعدنا في حل المشكلات المختلفة، وتحسن كفاءة عملنا، وتكشف عن قراءات مهمة من بيانات كان من المستحيل اكتشافها في السابق. لكن تنوع الأدوات المتاحة وكثرتها قد تشعر المبتدئين بالارتباك، لذا سنساعدك في مقالنا هذا على اختيار الأدوات المناسبة لشحذ وتحسين مهاراتك في التعامل مع أدوات الذكاء الاصطناعي المختلفة وتنفيذ حلول عملية مثل إنشاء روبوتات الدردشة، والتعرف على الصور، وتحليل المشاعر، وأنظمة التوصية وغيرها من المهام. وقد اخترنا الأدوات التي سنذكرها أدناه بناءً على مميزاتها وبساطتها ووجود مجتمع داعم لها، لتشكل أساسًا متينًا يمكن البدء منه. أولًا: منصة Paperspace تُعد منصةPaperspace منصة ممتازة لبدء رحلتك في مجال الذكاء الاصطناعي وتعلم الآلة. فهي توفر موارد وحدة معالجة رسوميات سحابية cloud-based GPU على آلات تعلم عميق منخفضة التكلفة وجاهزة للاستخدام، مما يسهل بدء التعلم دون القلق بشأن الحاجة لتوفير العتاد الملائم. كما يمكن الاستفادة من Paperspace Gradient، وهي مجموعة أدوات مصممة لتسريع الذكاء الاصطناعي السحابي وتعلم الآلة، وتشتمل على أداة قوية لإدارة المهام، ودعم للحاويات ومنصة Jupyter notebook التفاعلية، ومجموعة جديدة من عمليات تكامل اللغات. كما توفر منصة Paperspace أيضًا إمكانية الوصول إلى أطر عمل التعلم العميق الشائعة مثل تنسرفلو TensorFlow وباي تورش PyTorch مما يجعل التجريب والتطوير أمرًا سهلًا وسلسًا. ومع استحواذ شركة DigitalOcean مؤخرًا على منصة Paperspace أصبحت الشركات تتمتع بفرصة كبيرة للاستفادة من الذكاء الاصطناعي ونشر نماذج التعلم الآلي من خلال استخدام وحدات معالجة الرسوميات NVIDIA H100 GPUs ذات التكلفة المنخفضة، والتي تعد من أقوى وحدات معالجة الرسوميات لتدريب نماذج الذكاء الاصطناعي وتعلم الآلة. ثانيًا: منصة Papers with code توفر منصة Papers with Code أحدث الأوراق البحثية مع شيفرتها البرمجية على Github، ومجموعات بياناتها datasets التي ساهم بها المجتمع. يعطي اسم المنصة فكرة واضحة عن الغرض منها، وقد اكتسبت مؤخرًا شعبية كبيرة، ووسعت نظامها لدعم أبحاث تعلم الآلة بصورة شاملة أكثر. فهي توفر بيئة كاملة للمساهمات مفتوحة المصدر تسهل على مهندسي الذكاء الاصطناعي، وعلماء البيانات، والباحثين والطلاب تبادل الأفكار وتعزيز تطوير تعلم الآلة. تتمثل مهمة منصة Papers with Code في إنشاء مورد مجاني يحتوي على أوراق بحثية في مجال تعلم الآلة مع أكوادها البرمجية ومجموعات البيانات والدوال، وجداول التقييم المستخدمة. ويمكن تصفح نماذجها State of the Art models للاطلاع على أحدث تطورات هذا المجال. والتي تُعدّ بداية ممتازة لمطوري الذكاء الاصطناعي وتعلم الآلة. ثالثًا: مكتبة TensorFlow تُعدّ مكتبة تنسرفلو TensorFlow التي طورتها Google، إحدى المكتبات مفتوحة المصدر الأكثر انتشارًا في مشاريع تعلم الآلة والتعلم العميق. إذ تجعلها واجهتها سهلة الاستخدام خيارًا مثاليًا للمستخدمين الجدد. تتميز مكتبة TensorFlow ببيئة واسعة الموارد، وتتضمن برامج تعليمية وتوثيقات ومجتمع داعم يضم الكثير من المستخدمين وهو خيار مثالي لبدء رحلة تعلم الذكاء الاصطناعي وتعلم الآلة باستخدام واجهة برمجة التطبيقات عالية المستوى كيراس Keras، والتي تبسط إنشاء الشبكات العصبية وتدريبها. رابعًا: إطار باي تورش PyTorch يُعدّ باي تورش PyTorch من أطر العمل المفضلة بلغة البرمجة بايثون في مجال التعلم العميق، وهز يشتهر بمرونته ورسوماته البيانية الديناميكية. كما يمتاز بسهولة استخدامه بين الباحثين والمطورين وقدرته الممتازة على تصحيح الأخطاء. ويمتاز مجتمع PyTorch بأنه نشط جدًا، ويقدم الكثير من الموارد والبرامج التعليمية لتسهيل تعلم مجال التعلم العميق. خامسًا: مكتبة Scikit-Learn مكتبة ساي كيت ليرن Scikit-Learn هي إحدى مكتبات لغة بايثون القوية المصممة بدقة لتطبيقات تعلم الآلة البسيطة والفعالة. وهي خيار ممتاز للمبتدئين وتوفر واجهة برمجة تطبيقات API واضحة ومتسقة. تقدم مكتبة Scikit-Learn مجموعة خوارزميات ذكاء اصطناعي قوية أبرزها خوارزميات التصنيف classification، وخوارزميات الانحدار أو التوقع regression، وخوارزميات العنقدة clustering وغيرها، ويمكن مطالعة التوثيقات الرسمية والأمثلة التوضيحية للمكتبة لفهم هذه الخوارزميات وتنفيذها بفاعلية. سادسًا: منصة Jupyter Notebook منصة Jupyter Notebook هي بيئة تطوير تفاعلية تتيح إنشاء ونشر مستندات تجمع بين الشيفرة البرمجية المباشرة live code والمعادلات equations والتمثيل المرئي visualization، والنصوص texts. وهي أداة مناسبة لاستكشاف وتجريب مشاريع الذكاء الاصطناعي وتعلم الآلة، ويمكنها التعامل مع لغات برمجية عدة، بما في ذلك لغة بايثون Python ولغة R. سابعًا: منصة IBM Watson Studio منصة IBM Watson Studio هي منصة سحابية تقدم أدوات وخدمات لعلماء البيانات ومطوري الذكاء الاصطناعي. فهي تبسِّط عملية تطوير تطبيقات وخدمات الذكاء الاصطناعي وتعلم الآلة من خلال تقديم بيئات معّدة مسبقًا، وميزات تعاونية، وإمكانية وصول لخدمات الذكاء الاصطناعي الخاصة بشركة IBM. تُعد منصة IBM Watson Studio خيارًا مناسبًا لمن يرغب في تجربة الذكاء الاصطناعي دون تعقيدات. ثامنًا: منصة Hugging Face تقدم منصة Hugging Face مجموعة أدوات ذكاء اصطناعي، بما في ذلك مكتبة المحولات Transformers، وهي مكتبة مخصصة لأحدث نماذج معالجة اللغات الطبيعية NLP. وهي تتميز ببساطتها وسهولة استخدامها، مما يجعلها خيارًا أوليًا للمبتدئين الذين يستكشفون طريقهم في مجال معالجة اللغة الطبيعية NLP. كما يُسهّل الدعم الواسع الذي تقدمه Hugging Face والنماذج المُدَربة التجربة والتعلم. نصائح لبدء تعلم الذكاء الاصطناعي وتعلم الآلة بعد أن تعرّفنا على مجموعة منتقاة من أفضل أدوات الذكاء الاصطناعي وتعلم الآلة، سنقدم لك بعض النصائح لتحسين رحلتك في تعلم الذكاء الاصطناعي وتعلم الآلة كمبتدئ. تعلم الأساسيات يتوجب البدء بتعلم أساسيات الذكاء الاصطناعي وتعلم الآلة، بما في ذلك التعلم الخاضع للإشراف supervised learning، والتعلم غير الخاضع للإشراف unsupervised learning، والشبكات العصبية neural networks. هنالك العديد من الدورات التدريبية والبرامج التعليمية المتاحة عبر الإنترنت والتي تساعد على تعلم هذه المفاهيم. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن التدريب العملي لا تكفي القراءة فقط عن الذكاء الاصطناعي وتعلم الآلة والتركيز على المفاهيم النظرية، بل يتوجب تطبيق كل ما نتعلمه. يمكن أن ننفّذ مشاريع صغيرة ثم نزيد تعقيدها تدريجيًا. إذ يُعدّ التجريب مفتاحًا لفهم هذه التقنيات، وللاطلاع على مشاريع عديدة تناسب المبتدئين ننصحكم بكتاب عشرة مشاريع عملية عن الذكاء الاصطناعي من أكاديمية حسوب. استكشاف مجموعات البيانات Datasets من المفيد أيضًا التعرف على مجموعات البيانات ذات الصلة باهتمامنا. على سبيل المثال تُعدّ منصة Kaggle كنزًا لمجموعات البيانات وهي تستضيف مسابقات في علوم البيانات يمكنها أن صقل مهاراتنا. الانضمام إلى المجتمعات التقنية يفيد التفاعل مع مجتمعات الذكاء الاصطناعي وتعلم الآلة على المنصات والمجتمعات المتخصصة مثل PaperSpace وGitHub وStack Overflow وReddit وقسم الأسئلة في أكاديمية حسوب، ومجتمع حسوب IO إذ يؤدي التعلم من المطورين المهتمين والمشاركة في المناقشات إلى تسريع رحلتك التعليمية. الاطلاع على كل جديد يتطور مجال الذكاء الاصطناعي وتعلم الآلة بسرعة ولذا لا بد لك من متابعة أحدث المستجدات عبر الإنترنت، وقراءة الأخبار والتقارير التقنية، والاطلاع على الأوراق البحثية للبقاء على اطلاع بأحدث التطورات في هذا المجال. الخاتمة يمكن أن تكون رحلتنا في مجال الذكاء الاصطناعي وتعلم الآلة كمبتدئين تجربة مثيرة ومثمرة. يمكننا بناء أساس متين من خلال استخدام الأدوات التي تعرفنا عليها في مقالنا. ولنتذكر أن التعلم عملية مستمرة، لذا علينا الحفاظ على حماسنا والتدرب بجد والاستمتاع برحلة التعلم. ترجمة وبتصرّف للمقال Top AI and ML Tools for New Developers to Get Started With لكاتبه Anish Singh Walia. اقرأ أيضًا تعرف على أفضل دورات الذكاء الاصطناعي تعرف على أهم كتب الذكاء الاصطناعي المجانية مكتبات وأطر عمل الذكاء الاصطناعي: القوة الكامنة خلف الأنظمة الذكية لغات برمجة الذكاء الاصطناعي اكتشف بدائل ChatGPT مفتوحة المصدر
-
سنغطي في هذا المقال أسئلة واسعة حول تعلم الآلة Machine Learning، ومعالجة اللغات الطبيعية Natural Language Processing، والذكاء الاصطناعي Artificial Intelligence بهدف توسيع المهارات حول هذه التقنيات الحديثة، سنحاول الإجابة على مجموعة من الأسئلة المهمة بدءًا من أساسيات هذا المجال، والتقنيات الموصى بها، وصولًا إلى النماذج اللغوية المتقدمة مثل GPT 4، كما سنتناول التحديات التي تواجه المنتجات والأعمال المرتبطة بمعالجة اللغات الطبيعية ونناقش مستقبل هذا المجال. أسئلة حول أساسيات معالجة اللغات الطبيعية فيما يلي مجموعة أسئلة وإجابات حول أساسيات معالجة اللغات الطبيعية. ما خطوات الانتقال من تطوير التطبيقات التقليدية لاحتراف مجال تعلم الآلة ML في مجال تعلم الآلة، يحتاج المطور إلى استيعاب المفاهيم النظرية أولًا فهي تشكل الأساس الذي يبنى عليه كل شيء. ولكن من المهم أيضًا أن يتعرف على التقنيات واللغات الحديثة التي تدعم هذا المجال ويمكن تحقيق ذلك بحضور دورات تدريبية حول الذكاء الاصطناعي وتعلم الآلة وتنفيذ ما يتعلمه بشكل عملي. أما بالنسبة للغات البرمجة، فلغة بايثون هي الخيار الأمثل للمطورين المبتدئين في تعلم الآلة فهي لغة برمجة عالية المستوى، وتحظى بشعبية واسعة، وتتميز بوجود مجتمع كبير يدعمها، كما تحتوي بايثون على مكتبات قوية في مجال تعلم الآلة مثل تنسرفلو TensorFlow وساي كت ليرن Scikit-learn التي تسهّل الوصول إلى الأدوات اللازمة لتطبيق مفاهيم تعلم الآلة. دورة الذكاء الاصطناعي احترف برمجة الذكاء الاصطناعي AI وتحليل البيانات وتعلم كافة المعلومات التي تحتاجها لبناء نماذج ذكاء اصطناعي متخصصة. اشترك الآن هل تتطلب دراسة معالجة اللغة الطبيعية معرفة بمجال اللغويات Linguistics ونظرية المعلومات تشكل نظرية المعلومات Information Theory الأساس الذي يعتمد عليه الكثيرون في فهم طريقة معالجة البيانات والمعلومات بطريقة منظمة وفعّالة، وهي تستخدم في مجالات متعددة، بما في ذلك معالجة اللغة الطبيعية NLP. فعلم البيانات ونظرية المعلومات يرتبطان ارتباطًا وثيقًا ببعضهما، وبالتالي فإن الفهم الجيد لمفاهيم مثل انتروبية المعلومات Information Entropy سيسهم في تعزيز قدرتنا على تطوير تطبيقات ذكاء اصطناعي احترافية، وسيساعدنا توظيف هذه المبادئ على التعمق في معالجة اللغات الطبيعية. أما بالنسبة للغويات Linguistics وفهم بنية وقواعد اللغة فلا يتطلب الأمر بالضرورة الحصول على شهادة أكاديمية في هذا المجال. ويمكننا الاستفادة من الدورات التدريبية عبر الإنترنت التي توفر محتوى تطبيقي يساعد في تعزيز مهاراتنا، فمن خلال هذه الدورات سنتمكن من اكتساب الخبرة اللازمة لتطبيق تقنيات معالجة اللغات الطبيعية باحترافية. ما هي نماذج BERT وGPT وما الأمثلة الواقعية عنها نماذج BERT وGPT هما نوعان من النماذج اللغوية Language Models المدربة على كميات ضخمة من النصوص بهدف أداء مهام معينة مثل ملء المعلومات الناقصة في النصوص Text Infilling. إن هذه النماذج مهيأة بشكل خاص للاستخدام في التفاعل الحواري، حيث يمكنها فهم السياق اللغوي، والرد على الاستفسارات بطريقة طبيعية مشابهة لطريقة البشر. كما تُظهر نماذج BERT وGPT أداء مذهلًا وتتفوق في العديد من التطبيقات الأخرى غير الحوارية، مثل حل المسائل الرياضية أو ترجمة النصوص. ويُظهِر كل من نموذج BERT الذي يعتمد على المعالجة ثنائية الاتجاه للنصوص Bidirectional Processing ونموذج GPT الذي يعتمد على النماذج اللغوية التوليدية Generative Language Models قدرة فائقة على فهم وتوليد اللغة في العديد من السياقات. وأحد الأمثلة الواقعية على استخدام GPT هو روبوت الدردشة ChatGPT، أما نموذج BERT فيستخدم بشكل رئيسي في تحسين محركات البحث SEO وأنظمة التوصية. ما أبرز الأدوات المفيدة في مجال معالجة اللغات الطبيعية من أبرز أدوات معالجة اللغة الطبيعية NLP نذكر: لغات البرمجة مثل بايثون Python و R الخدمات السحابية مثل Amazon Web Services و Microsoft Azure خدمات تسيير العمل مثل Apache Airflow و Amazon Neptune النماذج اللغوية مثل GPT و BERT أي لغة أفضل في تحليل النصوص لغة بايثون أم R يُفضِّل كثيرون استخدام لغة بايثون في كل شيء، وليس في علم البيانات فقط، فلهذه اللغة مميزات عديدة من أبرزها سهولتها ووجود مجتمع كبير داعم لها، وتوفر العديد من مكتبات تحليل النصوص واستخراج المعلومات مثل NLTK و spaCy و TextBlob. أما لغة R، فهي مختلفة عن لغات البرمجة الأخرى وقد يكون استخدامها صعبًا ومعقدًا في بيئة الإنتاج. لكن قدراتها في مجال الإحصاء الرياضي يعطيها ميزة كبيرة مقارنة بلغة بايثون. ما هي الخدمة السحابية الأفضل لبناء النماذج ونشرها هناك العديد من الخدمات السحابية المتاحة لبناء النماذج Models ونشرها مثل خدمات AWS و Azure و Google، يمكن اختيار الخدمة التي تناسبنا وينصح الكاتب باستخدام منصة AWS لأنها تجنبنا مشكلة احتكار البائع Vendor Lock-in التي قد نواجهها عندما نعتمد على مزود سحابي معين، والتي قد تعيق انتقالنا إلى مزود آخر بسهولة وتكبدنا تكاليف ضخمة وتحديات كبيرة في نقل بيئة العمل. هل يفيدنا استخدام أدوات تسيير العمل في خطوط عمل معالجة اللغة الطبيعية نعم، تفيد أدوات تسيير العمل مثل Prefect أو Airflow أو Luigi أو Neptune بشكل فعّال في خطوط عمل معالجة اللغة الطبيعية NLP pipelines، لاسيما عندما يتطلب الأمر تنسيق عدة عمليات مع الحاجة لإضافة أو تعديل خطوط العمل في المستقبل. فهذه الأدوات ضرورية في حالات معالجة البيانات الضخمة التي تتطلب عمليات استخراج البيانات Extract، وتحويلها Transform، وتحميلها Load، والمعروفة اختصارًا بعمليات ETL، وهي تساهم في إدارة العمليات بثقة ومرونة وتنظم تنفيذ العمليات المعقدة، وتُسهّل التعامل مع تدفقات البيانات وتحسن الكفاءة في مشاريع معالجة اللغة الطبيعية. ما الأدوات التي يُوصى بها في مجال تعلم الآلة ومعالجة اللغات الطبيعية ينصح الكاتب باستخدام التابع style من مكتبة Pandas لعرض البيانات وإجراء مقارنات سريعة بينها. كما ينصح باستخدام MLflow عند الحاجة لمشاركة نتائج تجربة معينة مع فريق من المبرمجين أو علماء البيانات، واستخدام مكتبة ploty بدلًا من matplotlib للحصول على تقارير تفاعلية، ويمكن استخدام منصة Weights & Biases في مجال التعلم العميق Deep Learning، لأن مراقبة الموترات أو التنسورات tensors -وهي البنية الأساسية للبيانات التي تعالجها الشبكة العصبية- أصعب بكثير من مراقبة المقاييس metrics بسبب طبيعة البيانات التي تعمل بها التنسورات، حيث تحتوي على معلومات متعددة الأبعاد قد تكون ضخمة ومعقدة، في حين أن المقاييس، مثل دقة النموذج accuracy و خسارة النموذج Loss فهي قيم واحدة مفردة يجري تحديثها باستمرار وعرضها خلال تدريب النموذج ومن السهل تتبعها وتحليلها. نصائح وأسئلة حول العمل في مجال معالجة اللغة الطبيعية فيما يلي مجموعة أسئلة وإجابات مرتبطة بالعمل في مجال معالجة اللغات الطبيعية. كيف يمكن تقسيم المهام اليومية في تنظيف البيانات وبناء نماذج التطبيقات يعد تنظيف البيانات Data Cleaning وهندسة الميزات Feature Engineering من المهام التي تتطلب وقتًا كبيرًا عند تطوير تطبيقات فعلية، نظرًا لأن جودة البيانات هي الأساس الذي يعتمد عليه تعلم الآلة في تقديم حلول فعّالة. لذا، يُنصح بتخصيص أكبر قدر ممكن من الوقت لبناء النماذج Models، خصوصًا عندما تكون متطلبات التطبيق بسيطة ومحدودة، ولا تحتاج إلى استخدام تقنيات معقدة أو حلول مبتكرة للوصول إلى النتائج المطلوبة. كيف يمكن تحليل جدوى لنموذج تعلم آلة لا يحقق الأداء المطلوب لو طُلب منا العمل على نموذج تعلم آلة لا يحقق الأداء المطلوب مهما درّبناه، وأردنا إجراء تحليل جدوى لتوفير الوقت وتقديم دليل على أن من الأفضل الانتقال إلى طرق أخر فيمكننا استخدام أسلوب التطوير المرن Lean الذي يهدف إلى تحقيق أفضل النتائج بأقل جهد ووقت، يجري ذلك من خلال معالجة بسيطة مسبقة للبيانات Data Preprocessing، واستخدام مجموعة نماذج بسيطة سهلة التنفيذ، واتباع ممارسات من شأنها ضمان عمل النموذ بشكل صحيح مثل فصل مجموعات التدريب، والتحقق من الصحة validation، واستخدام الاختبار والتقويم المتقاطع cross-validation عند الإمكان. فباستخدام هذه الخطوات البسيطة، يمكننا تقييم فيما إذا كان النموذج الحالي قابل للتحسين أو من الأفضل استخدام نماذج أخرى لتحقيق الأداء المطلوب. هل يمكن بناء نماذج تعلم آلة تستخدم موارد أقل وبجودة النماذج الأكبر حجمًا نعم، يمكن بناء نماذج أصغر باستخدام تقنيات مثل التقليم Pruning. والتقليم هو عملية تقليص حجم النموذج عن طريق إزالة العناصر غير المهمة التي لا تؤثر بشكل كبير على أداء النموذج. تساعدنا هذه التقنية في تقليل حجم النموذج وتحسين كفاءته الحسابية وتمكننا من تشغيله على أجهزة أقل قوة مع الحفاظ على نفس مستوى الأداء. من الأمثلة الحديثة على ذلك نموذج Chinchilla من DeepMind، فعلى الرغم من أن هذا النموذج أصغر بكثير من النماذج القوية مثل GPT-3 من حيث الحجم الحسابي، إلا أنه يقدم أداء أفضل. وهذا يثبت أن تقنيات مثل التقليم يمكن أن تساعدنا في تحسين الكفاءة الحسابية وتحقيق نتائج عالية الأداء بنماذج أصغر. أسئلة حول منتجات الذكاء الاصطناعي ورؤى الأعمال فيما يلي مجموعة أمثلة وإجابات حول منتجات الذكاء الاصطناعي ورؤى الأعمال ما هي الخطوات المتبعة في دورة تطوير منتجات تعلم الآلة تتكون دورة تطوير منتجات تعلم الآلة من عدة خطوات أساسية: تبدأ الدورة بتحليل البيانات الاستكشافي Exploratory Data Analysis أو اختصارًا EDA من خلال فحص البيانات بعناية لتحديد ما هو ضروري للعمل على منتج تعلم الآلة، بعدها تُناقش نتائج التحليل مع الفريق وتقيّم أهداف المشروع لضمان وضوح التوجهات بعد تحديد الأهداف، ثم تُستَخدم نماذج بسيطة لتوليد نتائج مرجعية تساعد في تحديد أفضل الحلول، وأخيرًا يجري تحسين النماذج وتعديلها لتحقيق النتائج المثلى وفقًا لمقاييس الأداء. وخلال جميع الخطوات يجب أن يكون هناك تواصل مستمر مع العميل لضمان تطابق الحلول مع احتياجاته. ما تحديات تطبيق الذكاء الاصطناعي وتعلم الآلة في تطوير المنتجات في الوقت الحالي، هناك تحديان رئيسيان في مجال الذكاء الاصطناعي وتعلم الآلة: الأول هو الذكاء الاصطناعي العام Artificial General Intelligence أو AGI اختصارًا، والذي أصبح محور اهتمام كبير فهو نوع من الذكاء الاصطناعي يُفترض أن يكون قادرًا على أداء أي مهمة يمكن أن يؤديها الإنسان. لكن رغم الاهتمام الكبير به، لا زال تحقيقه غير ممكن في الوقت الحالي، وما زال أمامنا وقت طويل للوصول إلى تحقيق مستوى عالي من الكفاءة في أداء مهام متنوعة، ولا زال الذكاء الاصطناعي يواجه صعوبة في التعامل مع مشكلات لم يتعلم كيفية حلها مسبقًا. الحد الثاني في الذكاء الاصطناعي هو التعلم المعزز Reinforcement Learning حيث يعتمد هذا النوع من التعلم على تحسين الأنظمة من خلال المحاولة والتجربة والتفاعل مع البيئة بدلاً من الاعتماد على البيانات الضخمة Big data. ورغم أنه يعد بديلاً للتعلم التقليدي القائم على البيانات الضخمة والتعلم الخاضع للإشراف Supervised learning، إلا أن جمع البيانات اللازمة لتعلم جميع المهام البشرية أمر يستغرق وقتًا طويلاً، وحتى إذا جمعنا البيانات المطلوبة، قد لا تكون كافية لإنشاء نموذج ذكي يعمل بنفس مستوى الكفاءة التي يعمل بها البشر، خاصة عندما تتغير الظروف والبيئات في المستقبل. فهذه التغيرات قد تؤثر على قدرة النموذج على التكيف مع التحديات الجديدة. لذا من غير المحتمل أن يتمكن مجتمع الذكاء الاصطناعي من حل هذه المشكلات قريبًا، وإذا تمكن من ذلك، ستتحول التحديات إلى أمور تتعلق بالكفاءة الحسابية. ما حالات استخدام عمليات تعلم الآلة تعد عمليات تعلم الآلة Machine Learning Operations أو MLOps اختصارًا، ممتازة لعديد من المنتجات والأهداف مثل الحلول المصممة بدون خادم Serverless والتي تُحَصَّل الرسوم فيها مقابل ما نستخدمه والتي لا نحتاج فيها إلى إدارة الخوادم أو القلق بشأن صيانتها، وكذلك تستخدم في واجهات برمجة تطبيقات تعلم الآلة التجارية مثل التنبؤ بالطلب على المنتجات أو تحسين تجربة العملاء، كما تُستخدم خدمات مجانية مثل MLflow لمتابعة ومراقبة التجارب أثناء تطوير النماذج في مراحلها الأولى، ومراقبة الأداء بعد نشر التطبيقات. كيف نقنع العميل أو المدير باستخدام تعلم الآلة في التطبيقات تتمتع عمليات تعلم الآلة بفوائد كبيرة في التطبيقات على مستوى المؤسسات، حيث تساهم في تحسين كفاءة عملية التطوير وتقليل التكاليف التقنية. ومع ذلك، من المهم تقييم مدى ملاءمة الحل المقترح للهدف المطلوب. على سبيل المثال، إذا كان لدينا خادم في مكتبنا ويمكن ضمان تلبية متطلبات اتفاقية مستوى الخدمة Service-level agreement أو اختصارًا SLA، ومعرفة عدد الطلبات المتوقعة، فلن نحتاج لاستخدام خدمات عمليات تعلم الآلة المُدارة managed MLOps service. تحدث المشكلات الشائعة عندما نفترض أن الخدمة المُدارة ستلبي جميع متطلبات المشروع، مثل أداء النموذج، ومتطلبات اتفاقية مستوى الخدمة SLA، وقابلية التوسع، وغيرها. على سبيل المثال، يتطلب إنشاء واجهة برمجة تطبيقات للتعرف الضوئي على الحروف Optical Character Recognition أو OCR اختصارًا إجراء ختبارات دقيقة لتقييم نقاط الفشل وكيفية حدوثها. ويجب استخدام هذه الاختبارات لتحديد العوائق التي قد تعيق الوصول إلى الأداء المطلوب. كيف تحدد المؤسسات احتياجات العميل بدقة وتنشئ نماذج تساعد في اتخاذ القرارات تُضيف أدوات علم البيانات مزيدًا من الغموض للعميل مقارنة بحلول البرمجة التقليدية، لأنها تعتمد غالبًا على التعامل مع حالات عدم اليقين بدلاً من تجنبها. لهذا، من الضروري أن يظل العميل على اطلاع دائم بسير العمل فالعميل هو الأكثر دراية باحتياجات المشروع وهو من يوافق على النتيجة النهائية. أسئلة حول مستقبل معالجة اللغات الطبيعية فيما يلي مجموعة أمثلة وإجابات حول مستقبل معالجة اللغات الطبيعية وتحديات تطبيقها. ما مبرر ارتفاع استهلاك الطاقة الناتج عن الشبكات العصبية التلافيفية الكبيرة CNNs قد يعتقد البعض أن نماذج مثل LLaMA من شركة Meta غير مفيدة وتهدر الموارد. ومع ذلك، بما أن هذه النماذج ستكون متاحة مجانًا للجمهور في المستقبل، فإن الاستثمارات التي تُنفق على تدريب هذه النماذج ستعود بالفائدة على المدى البعيد وستساهم في تقدم الأبحاث والتقنيات، فبتقديم هذه النماذج، نفتح الفرصة للباحثين والمطورين للاستفادة منها في مجالات متنوعة، ونسرع من الابتكار ونعزز من تقدم الذكاء الاصطناعي بشكل عام. هل استطاعت نماذج الذكاء الاصطناعي اكتساب وعي يماثل الوعي البشري إن الوعي في الذكاء الاصطناعي هو مفهوم نظري للغاية، والحديث عن وعي الذكاء الاصطناعي قد يكون غير دقيق في الغالب، ويؤثر سلبًا على فهم معالجة اللغات الطبيعية. بالعموم، تظل مشاريع الذكاء الاصطناعي اصطناعية ولا تمتلك وعيًا مشابهًا للوعي البشري. هل يجب أن نقلق بشأن القضايا الأخلاقية المتعلقة بالذكاء الاصطناعي وتعلم الآلة يجب أن نكون حذرين بشأن ذلك خاصة مع التقدم السريع في أنظمة الذكاء الاصطناعي مثل ChatGPT. ولكن، من المهم أن يكون لدينا تعليم وخبرة كافية لفهم هذه التقنية بشكل جيد. ومن المفترض أن تكون الحكومات هي المسؤولة عن تنظيم الأمور، ما زلنا بحاجة إلى وقت إضافي لتحقيق ذلك، ولعل إحدى القضايا الأخلاقية المهمة هي كيفية تقليل تحيز الذكاء الاصطناعي وتجنبه ومسؤولية ذلك تقع على عاتق المهندسين والشركات، وكذلك على العملاء. لذا يجب بذل جهد كبير لضمان عدم التمييز أو المعاملة غير العادلة لأي شخص، بغض النظر عن تكاليف تحقيق ذلك. الخاتمة ختامًا، لنتذكر أن تعلم الآلة هو المحرك الرئيسي الذي يمكن أن يقود البشرية إلى ثورتها الصناعية القادمة. فقد اختفت وظائف عدة أثناء الثورة الصناعية، ولكن ظهرت وظائف جديدةً أكثر إبداعًا ويمكنها تأدية عمل ينجزه عدد كبير من العمال. وبإمكاننا فعل الشيء نفسه الآن والتكيف مع تعلم الآلة والذكاء الاصطناعي بشكل إيجابي وفعال. ترجمة، وبتصرّف، للمقال Ask an NLP Engineer: From GPT Models to the Ethics of AI، لكاتبه Daniel Pérez Rubio. اقرأ أيضًا المفاهيم الأساسية لتعلم الآلة مجالات الذكاء الاصطناعي الذكاء الاصطناعي: أهم الإنجازات والاختراعات وكيف أثرت في حياتنا اليومية نظرة سريعة على مجال تعلم الآلة كل ما تود معرفته عن دراسة الذكاء الاصطناعي
-
تعرفنا في مقال سابق على طريقة بناء موقع ثابت كمعرض أعمال باستخدام تقنيات الويب الأساسية، وسنتعلم في هذا المقال أهم الخطوات التي علينا اتباعها لترقية موقعنا من موقع بسيط إلى تطبيق تفاعلي باستخدام لغة جافا سكريبت وإطار عملها Vue.js. متطلبات العمل لإنشاء التطبيق نحتاج إلى تثبيت بيئة نود جي إس Node.js ومدير الحزم npm على حاسوبنا المحلي، للقيام بذلك ننتقل إلى موقع Node.js الرسمي ونحمّل أحدث نسخة، بعد تنزيل وتثبيت Node.js سيثبت npm تلقائيًا. بعد ذلك نفتح موجه الأوامر أو الطرفية ونتحقق من أن Node.js ومدير الحزم npm مثبتان بشكل صحيح باستخدام الأمرين التاليين: node -v npm -v بهذا نكون قد أعددنا متطلبات العمل، ونحن جاهزون للبدء بالخطوات العملية لإنشاء تطبيق معرض الأعمال. إنشاء بنية المشروع يتوجب علينا بداية إنشاء مجلد جديد للمشروع، ثم ننشئ مشروع Vue.js جديد باستخدام الأمر التالي: npm init vue@latest سينشئ هذا الأمر مشروع فيو جديد لكن سيُطلب منا بداية بعض الخيارات مثل اسم المشروع وتهيئة المشروع. بعد الانتهاء من إنشاء المشروع، سوف نتنقل له، ونثبت جميع الحزم أو التبعيات المطلوبة، ثم نشغل الخادم المحلي لعرض مشروعنا في المتصفح من خلال التعليمات التالية: cd <your-project-name> npm install npm run dev يظهر لنا رابط الخادم المحلي localhost في الطرفية، ويمكن فتحه في المتصفح لعرض تطبيق Vue.js الخاص بنا كما في الصورة التالية: بنية المشروع إليك البنية التي سنتبعها لهذا المشروع: يمثل App.vue المكوّن الجذر root component، الذي يحتوي بدوره على خمسة مكونات فرعية child components. من بين هذه المكونات كما تلاحظ المكوّن ProjectListComponent.vue الذي يمكن أن يحتوي بدوره على مكون فرعي آخر هو ProjectComponent.vue. لتشيكل هيكل متداخل بسيط ضمن التطبيق. يمكننا استخدام البنية التي نريدها لتنظيم مكونات المشروع، فمثلًا، يمكن استخدام مكوّن رئيسي MainComponent يحتوي على القسم التعريفي، وقسم المهارات، وقسم النشرة الإخبارية، وقائمة المشاريع كمكوّنات أبناء child components، لجعل البنية أكثر تعقيدًا، كما يمكننا الجمع بين قسم التعريف والمهارات وقسم النشرة الإخبارية بمكوّن واحد، فإطار العمل Vue.js يمنحنا حرية هيكلة مشروعنا بالطريقة التي تريدها. أولاً، علينا تعديل بعض المعلومات الوصفية meta information في ملفIndex.html، وهو نقطة الأساس في المشروع: <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="description" content="My Portfolio" /> <meta name="keywords" content="HTML, CSS, JavaScript" /> <meta name="author" content="Hsoub Academy" /> <title>My Portfolio</title> </head> <body> <div id="app"></div> <script type="module" src="/src/main.js"></script> </body> </html> علينا وضع المكوّن الجذر App.vue في العنصر <div id="app"></div> ضمن الملف index.html. إنشاء المكوّن الجذر ومكوّن الترويسة header component بإمكاننا الآن إنشاء المكوّن الأول HeaderComponent.vue ببساطة، كل ما علينا هو نسخ شيفرة HTML من الملف index.html الذي أنشأناه في مقالنا السابق ولصقه في العنصر <template> ضمن هذا المكون على النحو التالي: <script> export default { props: ["websiteName"], }; </script> <template> <!--Header and Navigation Bar--> <div class="col-12 col-s-12 header-and-nav"> <header class="col-4 col-s-4 header"> <h1>{{ websiteName }}</h1> </header> <nav class="col-8 col-s-8"> <ul class="nav-list"> <li><a href="/">Root</a></li> <li><a href="portfolio.html">Home1</a></li> <li><a href="/portfolio.html">Home2</a></li> <li><a href="https://academy.hsoub.com/programming/">Lessons</a></li> <li><a href="#project">Projects</a></li> </ul> </nav> </div> </template> ثم نستورد هذا المكوّن الذي أنشأناه للتو داخل المكوّن الجذر App.vue كما يلي: <script> import HeaderComponent from "@/components/HeaderComponent.vue"; export default { data() { return { websiteName: "My Portfolio", }; }, components: { HeaderComponent, }, }; </script> <template> <div class="container"> <HeaderComponent></HeaderComponent> </div> </template> <style> @import "./assets/style.css"; </style> استوردنا أيضًا في نهاية الكود أعلاه شيفرة CSS التي كتباناها في المقال السابق داخل المكوّن الجذر، كي تُطبَّق التنسيقات على جميع المكوّنات، حيث وضعنا ملف CSS في مثالنا في المجلد /src/assets/. الآن إذا فتحنا رابط التطبيق في المتصفح فيجب أن نرى شريط التنقل الذي أضفناه. لدينا مشكلة جديدة لأن كل شيء مكتوب مباشرة في الشيفرة المصدرية، فإن أردنا تغيير شيء ما، فعلينا تغييره في كل مكان ورد فيه ضمن الشيفرة. لكن هدفنا هو جعل صفحة الويب ديناميكية ونسهل تغيير البيانات ولتحقيق ذلك، سنربط بعض معلومات موقعنا مع المتغيرات variables. على سبيل المثال لاحظ كيف كتبنا اسم الموقع وروابط التنقل في شريط التنقل من خلال إضافة الكود التالي للملف HeaderComponent.vue: <script> export default { data() { return { websiteName: "My Portfolio" navLinks: [ { id: 1, name: "Home", link: "#" }, { id: 2, name: "Features", link: "#" }, { id: 3, name: "Pricing", link: "#" }, { id: 4, name: "FAQs", link: "#" }, { id: 5, name: "About", link: "#" }, ], }; }, }; </script> <template> <!--Header and Navigation Bar--> <div class="col-12 col-s-12 header-and-nav"> <header class="col-4 col-s-4 header"> <h1>{{ websiteName }}</h1> </header> <nav class="col-8 col-s-8"> <ul class="nav-list"> <li class="nav-item" v-for="navLink in navLinks" v-bind:key="navLink.id" > <a href="/portfolio.html" v-bind:href="navLink.link">{{ navLink.name }}</a> </li> </ul> </nav> </div> </template> ولكن هل هذا هو الحل الأمثل؟ سيظهر اسم الموقع مرة أخرى في المكون FooterComponent، وبما أن المكوّنات المختلفة تُعرض منفصلة، فهذا يعني أن اسم الموقع سيُسترد من قاعدة البيانات مرتين، وذلك مضيعة للموارد. الحل البديل هو وضع اسم الموقع websiteName داخل المكوّن الجذر App.vue على شكل خاصية وتمريره إلى المكوّنات الأبناء التي تحتاج إلى استخدامه كما يلي: <script> import HeaderComponent from "@/components/HeaderComponent.vue"; export default { data() { return { websiteName: "My Portfolio", }; }, components: { HeaderComponent, }, }; </script> <template> <div class="container"> <HeaderComponent v-bind:websiteName="websiteName"></HeaderComponent> </div> </template> <style> @import "./assets/style.css"; </style> الآن نحصل على اسم الموقع في شيفرة HeaderComponent.vue كما يلي: <script> export default { data() { return { navLinks: [ { id: 1, name: "Home", link: "#" }, { id: 2, name: "Features", link: "#" }, { id: 3, name: "Pricing", link: "#" }, { id: 4, name: "FAQs", link: "#" }, { id: 5, name: "About", link: "#" }, ], }; }, props: ["websiteName"], }; </script> <template> <div class="col-12 col-s-12 header-and-nav"> <header class="col-4 col-s-4 header"> <h1>{{ websiteName }}</h1> </header> <nav class="col-8 col-s-8"> <ul class="nav-list"> <li class="nav-item" v-for="navLink in navLinks" :key="navLink.id"> <a :href="navLink.link">{{ navLink.name }}</a> </li> </ul> </nav> </div> </template> مكونات التطبيق شرحنا في الفقرات السابقة طريقة تحقيق مكون الترويسة، ويمكن إنشاء باقي مكونات التطبيق وتخصيصها بنفس الطريقة التي أضفنا فيها الترويسة حيث سيتضمن تطبيقنا المكونات التالية: مكون الترويسة HeaderComponent.vue مكون التعريف IntroComponent.vue مكون النشرة البريدية NewsletterComponent.vue مكون المهارات SkillsComponent.vue مكون المشاريع ProjectsComponent.vue مكون التذييل FooterComponent.vue بعد إنشاء المكونات المطلوبة نعرضها في المكون الجذر App.vue كما يلي: <script> import HeaderComponent from './components/HeaderComponent.vue' import IntroComponent from './components/IntroComponent.vue' import NewsletterComponent from './components/NewsletterComponent.vue' import SkillsComponent from './components/SkillsComponent.vue' import ProjectsComponent from './components/ProjectsComponent.vue' import FooterComponent from './components/FooterComponent.vue' export default { data() { return { websiteName: 'My Portfolio' } }, components: { HeaderComponent, IntroComponent, NewsletterComponent, SkillsComponent, ProjectsComponent, FooterComponent } } </script> <template> <div class="container"> <HeaderComponent :websiteName="websiteName" /> <IntroComponent /> <NewsletterComponent /> <SkillsComponent /> <ProjectsComponent /> <FooterComponent /> </div> </template> <style> @import './assets/style.css'; </style> ملاحظة: هنالك عدة طرق لإضافة الصور للتطبيق، وفي حالتنا سنضيف مجلد الصور images في المجلد public ضمن المشروع لسهولة الوصول لها مباشرة. عند الانتهاء من إضافة كافة الأقسام والصور والتنسيقات سيظهر تطبيقنا كما في الصورة التالية: الخاتمة تعلمنا في هذا المقال أهم خطوات تحويل موقع مطور بواسطة HTML و CSS إلى تطبيق Vue.js. حيث أنشأنا مشروع Vue جديد، ونقلنا التنسيقات والصور إلى المجلدات المناسبة في تطبيقنا، كما قسمنا صفحة HTML إلى مكونات متنوعة تمثل أجزاء الصفحة المختلفة وربطنا المكونات مع بعضها البعض في المكون الجذر. وتعرفنا كذلك على طريقة تحويل البيانات الثابتة إلى ديناميكية، حان دوركم لتجربة تحويل مواقعكم البسيطة إلى تطبيقات جافا سكريبت لجعلها أسهل في الصيانة وأكثر تنظيمًا. ترجمة، وبتصرّف للمقال Create a portfolio Website لكاتبه Eric Hu. اقرأ أيضًا مقدمة إلى Vue.js إنشاء مشاريع Vue.js باستخدام Vue CLI عرض مكونات Vue.js مدخل إلى التعامل مع المكونات في Vue.js
-
سنشرح في هذا المقال كيفية توظيف معلوماتك عن تقنيات الويب الأساسية وهي HTML وCSS و JavaScript لإنشاء موقع ويب يكون معرضًا لأعمالك تستخدمه للتعريف بك وبمشاريعك، وسنعمل في مقال لاحق على تحسين هذا الموقع من خلال إطار عمل Vue.js. إنشاء ملف HTML أولاً، ننشئ مجلدًا ونسميه portfolio، حيث سنخزن فيه كل ما يتعلق بمشروع معرض الأعمال. ثم ننشئ داخله ملف HTML، ونطلق عليه اسم Portfolio.html ونفتحه باستخدام أي محرر نصي نفضله، يمكن استخدام أي محرر كالمفكرة، لكن ننصح باستخدام محرر أكواد برمجية مناسب مثل Visual Studio Code. إذا فتحنا الملف في المتصفح واستكشفناه في أدوات المطور سنلاحظ أن له البنية التالية: <!doctype html> <html> <head> . . . </head> <body> . . . </body> </html> لنبدأ بالحديث عن قسم الترويسة <head> والذي يتضمن التالي: <head> <meta charset="utf-8" /> <meta name="description" content="My Portfolio" /> <meta name="keywords" content="HTML, CSS, JavaScript" /> <meta name="author" content="Hsoub Academy" /> <title>My Portfolio</title> </head> الجزء السابق بسيط وواضح، فقد حددنا أولاً مجموعة المحارف التي سيستخدمها الملف، إذ يستخدم المتصفح هذه المعلومات للتأكد من عرض الأحرف والرموز بصورة صحيحة. وبعدها حددنا الوصف والكلمات الرئيسية ومنشئ صفحة الويب، وأخيرًا، صرّحنا عن عنوان صفحة الويب وهو في حالتنا My Portfolio. ملاحظة: لا تُعرض معلومات <head> في موقع الويب، لكنها مهمة لتحسين محركات البحث SEO. . الترويسة Header وشريط التنقل Navigation bar بعدها سنبدأ بإنشاء ترويسة موقعنا، وننشئ شريط التنقل الأساسي من خلال كتابة الكود التالي: <!--Header and Navigation Bar--> <header> <h1>Simple Portfolio</h1> </header> <nav class="col-8 col-s-8"> <ul class="nav-list"> <li class="nav-item"><a href="./portfolio.html">Home</a></li> <li class="nav-item"><a href="https://academy.hsoub.com/programming">Lessons</a></li> <li class="nav-item"><a href="#project">Projects</a></li> </ul> </nav> نلاحظ أننا استخدمنا أنواع روابط مختلفة، فالرابط الأول في قسم التنقل هو عنوان نسبي relative URL سينقلنا إلى جذر الخادم root directory ثم سيبحث عن ملف portfolio.html، والرابط الثاني هو عنوان مطلق absolute URL، أما الرابط الأخير فهو رابط مرساة anchor link وسنتحدث عنه لاحقًا. إضافة القسم التعريفي لمعرض الأعمال نحتاج في معرض الأعمال الاحترافي للتعريف عن نفسنا ونسرد خبراتنا بإيجاز، ولتحقيق ذلك سنضيف الشيفرة التالية، مع تعديل النص الموجود ضمن وسم الفقرة <p>. . .</p> لعرض رسالة قصيرة نعرّف فيها زوار معرض الأعمال عنا: <!--Self Introduction Section--> <section> <h2>Welcome to My Portfolio</h2> <p> Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book </p> </section> قسم الرسائل الإخبارية Newsletter سنضيف بعدها الشيفرة التالية لإتاحة خيار الاشتراك في الرسائل الإخبارية لمتابعي الموقع: <!--Newsletter Sign Up Section--> <section> <h2>Would you like to see more tips and tutorials on web development?</h2> <form> <label for="firstname">First Name:</label> <input type="text" id="firstname" /> <br /><br /> <label for="lastname">Last Name:</label> <input type="text" id="lastname" /> <br /><br /> <label for="email">Enter your email:</label> <input type="email" id="email" name="email" /> </form> </section> قسم الخبرات Skills ثم نضيف الشيفرة التالية لعرض المهارات والخبرات المختلفة: <!--Skills Section--> <section> <h2>My Skills</h2> <ul> <li>HTML (100%)</li> <li>CSS (90%)</li> <li>JavaScript (90%)</li> <li>Python (90%)</li> <li>PHP (100%)</li> <li>Java (90%)</li> <li>Vue.js (80%)</li> <li>Django (90%)</li> <li>Laravel (90%)</li> </ul> </section> نلاحظ استخدام ثلاث طرق لتمثيل إشارة النسبة المئوية % في الكود أعلاه وجميعها تعطي النتيجة نفسها. قسم المشاريع Projects نضيف الشيفرة التالية لعرض المشاريع البرمجية المنجزة: <!--Projects Section--> <section id="project"> <h2>My Projects</h2> <div> <h3>First Project</h3> <img src="./images/first project.jpg" width="500" height="300" /> <p>. . .</p> </div> <div> <h3>Second Project</h3> <img src="./images/second project.jpg" width="500" height="300" /> <p>. . .</p> </div> <div> <h3>Third Project</h3> <img src="./images/third project.jpg" width="500" height="300" /> <p>. . .</p> </div> </section> أضفنا في السطر الثاني معرّفًا id للوسم <section> باسم projects، كي يعمل مع رابط المرساة anchor link الذي ذكرناه سابقًا. <a href="#project">Projects</a> سينقلنا هذا الرابط إلى العنصر ذي المعرّف project. حيث يتوجب عليك دائمًا استخدام المعرف لتحديد العنصر الذي نرغب في الربط به أو الانتقال إليه بحيث يكون فريدًا في صفحة الويب. أما الصور الموجودة في هذا القسم فكلها مخزنة في مجلد يسمى images ضمن مجلد المشروع portfolio. تذييل الصفحة Footer أخيرًا، نضيف الشيفرة التالية لإضافة تذييل إلى الصفحة: <!--Footer--> <footer> <p>Created by Hsoub Academy</p> <p><a href="mailto:example@email.com">example@email.com</a></p> </footer> ستبدو النتيجة النهائية بالشكل التالي، لكنها كما هو ظاهر في الصورة ليست احترافية، ولن تخوّلنا للحصول على وظيفة مناسبة بهيئتها الحالية. لذا سنوضح في الفقرات التالية خطوات تنسيق هذه الصفحة وجعلها أكثر جاذبية. إضافة تنسيقات CSS إلى مستند HTML حان الآن وقت تحسين مظهر الموقع باستخدام لغة CSS، وسنشرح هنا بعض المفاهيم الأساسية لهذه اللغة: أولًا، ننشئ ملف style.css في مجلد المشروع: ثم نستورده import داخل مستند HTML بكتابة وسم <link> داخل الوسم <head> كما يلي: <head> <meta charset="utf-8" /> <meta name="description" content="My Portfolio" /> <meta name="keywords" content="HTML, CSS, JavaScript" /> <meta name="author" content="Hsoub Academy" /> <title>My Portfolio</title> <!-- ربط ملف CSS --> <link rel="stylesheet" href="style.css"> </head> إنشاء تصميم متجاوب علينا تحقيق تصميم متجاوب لمعرض الأعمال، ولتحقيق ذلك يجب أن يحتوي تخطيط الصفحة على مكونين رئيسيين، هما الحاوية container ونظام التخطيط الشبكي grid system. أولاً، يجب أن يكون لدينا حاوية مرنة يتغير عرضها عند تغيير حجم نافذة المتصفح. نعتمد عادة العرض الأعظم على الشاشات الكبيرة كي لا تمتد الحاوية إلى الحافة. أما على الشاشات الأصغر حجمًا، فنضبط عرض الحاوية على القيمة 100% كي نستفيد من أكبر مساحة ممكنة. فيما يلي الشيفرة اللازمة لتحقيق ذلك: <body> <div class="container">. . .</div> </body> /* الشاشات صغيرة الحجم */ .container { max-width: 100%; display: flex; flex-wrap: wrap; } /* الشاشات كبيرة الحجم */ @media only screen and (min-width: 1200px) { .container { max-width: 1140px; margin: auto; display: flex; flex-wrap: wrap; } } نلاحظ أن لدينا نقطة حدّية breakpoint واحدة لتبسيط الأمور، إذا كان عرض الشاشة أقل من 1200 بكسل، فإن الحاوية ستمتد إلى الحواف. أما إن كانت الشاشة أكبر من 1200 بكسل، فسيُضبَط الحد الأقصى لعرض الحاوية على القيمة 1140 بكسل. وفي الحالة الثانية ضبطنا قيمة الهامش على القيمة التلقائية margin: auto; للتأكد من أن الحاوية موجودة داخل حدود الشاشة دائمًا . فيما يلي النتيجة في حالة الشاشات صغيرة الحجم: وفي حالة الشاشات متوسطة الحجم: وفي حالة الشاشات كبيرة الحجم: ثانياً، نحتاج إلى أنظمة تخطيط شبكي مختلفة grid systems للشاشات الصغيرة كشاشات الهواتف المحمولة، والشاشات المتوسطة كشاشات الأجهزة اللوحية، والشاشات الكبيرة كحواسيب سطح المكتب. يحتوي كل نظام شبكي على 12 عمودًا، وقد تشغل العناصر المختلفة أعمدة مختلفة باختلاف أنواع الشاشات، يمكن تحقيق ذلك إما عن طريق نظام الشبكة العادي regular grid system أو الصندوق المرن flexbox. لكننا سنستخدم في مقالنا تخطيط الصندوق المرن: <body> <div class="container"> <div class="col-6 col-s-8">Div1</div> <div class="col-6 col-s-4">Div2</div> <div class="col-2 col-s-10">Div3</div> <div class="col-4 col-s-2">Div4</div> </div> </body> /* للهواتف المحمولة */ [class*="col-"] { width: 100%; } /* للأجهزة اللوحية */ @media only screen and (min-width: 600px) { .col-s-1 { width: 8.33%; } .col-s-2 { width: 16.66%; } .col-s-3 { width: 25%; } .col-s-4 { width: 33.33%; } .col-s-5 { width: 41.66%; } .col-s-6 { width: 50%; } .col-s-7 { width: 58.33%; } .col-s-8 { width: 66.66%; } .col-s-9 { width: 75%; } .col-s-10 { width: 83.33%; } .col-s-11 { width: 91.66%; } .col-s-12 { width: 100%; } } /* للحواسيب المكتبية */ @media only screen and (min-width: 768px) { .col-1 { width: 8.33%; } .col-2 { width: 16.66%; } .col-3 { width: 25%; } .col-4 { width: 33.33%; } .col-5 { width: 41.66%; } .col-6 { width: 50%; } .col-7 { width: 58.33%; } .col-8 { width: 66.66%; } .col-9 { width: 75%; } .col-10 { width: 83.33%; } .col-11 { width: 91.66%; } .col-12 { width: 100%; } } لنرى الآن كيف سيبدو التخطيط السابق: على الشاشات الصغيرة: على الشاشات المتوسطة: على الشاشات الكبيرة: بعد أن انتهينا من تصميم التخطيط العام المتجاوب لموقعنا، سنتطرق إلى التفاصيل. ولكن أولًا، ننصح بالنقر على الروابط أدناه لإلقاء نظرة أوضح على النتيجة التي يجب أن تبدو عليها الصفحة المطلوبة من أجل حجم كل شاشة: تصميم الشاشات الصغيرة تصميم الشاشات المتوسطة تصميم الشاشات الصغيرة اختيار الألوان والخطوط قبل استكمال العمل على تنسيق صفحة الويب، دعونا نفكر في اختيار نظام الألوان والخط الذي ستستخدمه. قد يكون ذلك صعبًا، لكن هناك عديد من الأدوات التي يمكن أن تساعدنا في تحقيق المطلوب،على سبيل المثال يمكن استخدام موقع Coolors الذي يقدم مئات لوحات الألوان المختلفة مع رموزها. أما بالنسبة للخطوط، فننصح باستخدام Google Fonts إذ يمكن تحديد أي خط واستخدامه في ملف CSS. اخترنا في حالتنا الخطوط التالية: Comfortaa بوزن 700 Courier Prime بأوزان 400 و 700 ونوع monospace Crimson Text بأوزان 400 و 600 و 700 Poppins بأوزان 200 و 300 و 400 و 500 و 600 و 700 وكي نتمكن من تطبيق هذه الخطوط على عناصر موقعنا علينا كتابة شيفرة الاستيراد الشيفرة التالية أعلى ملف CSS كما يلي: @import url("https://fonts.googleapis.com/css2?family=Comfortaa:wght@700&family=Courier+Prime:ital,wght@0,400;0,700;1,400;1,700&family=Crimson+Text:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700&family=Poppins:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"); بمجرد استيراد هذه الخطوط عبر @import يمكننا تطبيقها على العناصر في صفحة HTML باستخدام CSS كما يلي: h1 { font-family: "Comfortaa", cursive; } h2, h3, h4 { font-family: "Crimson Text", serif; } p, a { font-family: "Poppins", sans-serif; } تنسيق مظهر أقسام الصفحة لنطبق التنسيقات على كل قسم من الأقسام التي أضفناها لملف HTML تنسيق مظهر شريط التنقل عند تصميم صفحات الويب، يجب عليك دائمًا اتباع قاعدة الجوال أولاً mobile first. أي علينا أولًا البدء بتصميم تخطيط الشاشة الصغيرة. سنبدأ بشريط التنقل. أولاً، نضع العنصر <header> و <nav> داخل العنصر<div>. إذ يقبل العنصر <div> إثني عشر عمودًا في جميع الأجهزة. <div class="col-12 col-s-12 header-and-nav"> <header>. . .</header> <nav>. . .</nav> </div> يجب أن يبقى العنصر <header> في أعلى العنصر <nav> في الشاشات الصغيرة، وفي الشاشات الأكبر حجمًا، نريد وضع العنصر <header> في الجانب الأيسر والعنصر <nav> في الأيمن. ولتنفيذ ذلك، يجب أن نحرص على أن العنصر <div> هو حاوية مرنة flexbox container، وذلك باستخدام الشيفرة التالية: .header-and-nav { display: flex; flex-wrap: wrap; } <div class="col-12 col-s-12 header-and-nav"> <header class="col-4 col-s-4">. . .</header> <nav class="col-8 col-s-8">. . .</nav> </div> والآن علينا وضع الترويسة وقائمة التنقل في منتصف الصفحة، كما يلي: <!--Header and Navigation Bar--> <div class="col-12 col-s-12 header-and-nav"> <header class="col-4 col-s-4 header"> <h1>Simple Portfolio</h1> </header> <nav class="col-8 col-s-8"> <ul class="nav-list"> <li class="nav-item"> <a href="./portfolio.html">Home</a> </li> . . . </ul> </nav> </div> .header { text-align: center; } .nav-list { text-align: center; } .nav-item { display: inline-block; } .nav-item a { display: inline-block; } إليك شكل قائمة التنقل الحالية: والآن سنضيف بعض الألوان والحشو paddings والهوامش margins وزخارف نصية للترويسة وقائمة التنقل لجعلها أكثر احترافية: .header { color: white; text-align: center; } .nav-list { list-style-type: none; margin: 0px; padding: 0px; text-align: center; } .nav-item { display: inline-block; } .nav-item a { display: inline-block; color: white; text-decoration: none; padding: 27px 20px; } .nav-item a:hover { background-color: #457b9d; text-decoration: underline; } وستصبح ترويسة الصفحة على النحو التالي: بعدها سنُغيّر شكل قائمة التنقل في الحواسيب المكتبية، ونجري محاذاة للروابط إلى اليمين، باستخدام الشيفرة التالية: @media only screen and (min-width: 768px) { .nav-list { list-style-type: none; margin: 0px; padding: 0px; text-align: right; } } ستصبح الآن على النحو التالي: تنسيق مظهر قسم التعريف الشخصي نستخدم الشيفرة التالية لتنسيق قسم التعريف الشخصي ويمكن استبدال الصورة بأخرى مناسبة: <!--Self Introduction Section--> <section class="col-12 col-s-12 self-intro"> <img src="./images/profile-image.jpg" class="col-4 col-s-4 profile-image" /> <div class="col-8 col-s-8 self-intro-text"> <h2>Welcome to My Portfolio</h2> <p>. . .</p> </div> </section> /* Self Introduction Section */ .self-intro { display: flex; align-items: center; gap: 20px; padding: 20px; background-color: #f8f8f2; } .profile-image { flex: 0 0 40%; height: auto; object-fit: cover; } .self-intro-text { flex: 1; text-align: left; } .self-intro-text h2 { font-size: 1.8rem; font-weight: bold; margin-bottom: 10px; text-decoration: underline; } تنسيق مظهر قسم الرسائل الإخبارية فيما يلي شكل قسم التسجيل في الرسائل الإخبارية والشيفرة اللازمة: على الشاشات الكبيرة: على الشاشات الصغيرة: <!--Newsletter Sign Up Section--> <section class="col-12 col-s-12 newsletter-signup"> <h2 class="col-6 col-s-6">Would you like to see more tips and tutorials on web development?</h2> <form class="col-6 col-s-6 newsletter-signup-form"> <label for="firstname">First Name:</label><br /> <input type="text" id="firstname" /> <br /> <label for="lastname">Last Name:</label><br /> <input type="text" id="lastname" /> <br /> <label for="email">Enter your email:</label><br /> <input type="email" id="email" name="email" /> <button type="submit">Submit</button> </form> </section> /* قسم التسجيل في الرسائل الإخبارية */ .newsletter-signup { background-color: #a8dadc; padding: 10px; display: flex; flex-wrap: wrap; } .newsletter-signup h2 { text-align: center; } .newsletter-signup-form { margin: 0 auto; } .newsletter-signup-form label { font-family: "Poppins", sans-serif; } .newsletter-signup-form input { width: 100%; padding: 12px 20px; margin: 8px 0; box-sizing: border-box; } .newsletter-signup-form button { background-color: #a8dadc; border: solid 3px #e63946; color: #e63946; width: 100%; padding: 10px 0; margin: 10px 0; cursor: pointer; font-family: "Poppins", sans-serif; font-size: 1em; font-weight: 600; } .newsletter-signup-form button:hover { background-color: #e63946; border: solid 3px #e63946; color: white; } @media only screen and (min-width: 768px) { .newsletter-signup { background-color: #a8dadc; padding: 10px; display: flex; flex-wrap: wrap; align-items: center; } .newsletter-signup h2 { text-align: center; padding: 10px; } } تنسيق مظهر قسم المهارات <!--Skills Section--> <section class="col-12 col-s-12 skills-section"> <h2 class="col-12 col-s-12">My Skills</h2> <ul class="col-8 col-s-8 skills-list"> <li>HTML (100%)</li> . . . </ul> </section> /* قسم المهارات */ .skills-section { padding: 10px; display: flex; flex-wrap: wrap; } .skills-section h2 { text-decoration: underline; } .skills-list { column-count: 2; } @media only screen and (min-width: 768px) { .skills-list { column-count: 2; margin: 0 auto; } } لاحظ أننا جعلنا عدد الأعمدة اثنين column-count: 2;، كي نعرض قائمة المهارات في عمودين. تنسيق مظهر قسم المشاريع نريد عرض قسم المشاريع على الشاشة الكبيرة كما يلي: وعرضها على الشاشات الصغيرة كما يلي: وفيما يلي الشيفرة اللازمة لتنسيق عرض قسم المهارات ليبدو بالشكل المطلوب: <!--Projects Section--> <section class="col-12 col-s-12 porject-section" id="project"> <h2 class="col-12 col-s-12">My Projects</h2> <div class="col-4 col-s-4"> <div class="project-card"> <h3>First Project</h3> <img src="/frontend/images/p1.jpg" /> <p>. . .</p> </div> </div> . . . </section> /* قسم المشاريع */ .porject-section { padding: 10px; display: flex; flex-wrap: wrap; background-color: #a8dadc; } .porject-section h2 { text-decoration: underline; } .project-card { border: solid 2px gray; border-radius: 5px; padding: 5px; margin: 5px; } .project-card img { max-width: 100%; object-fit: cover; } تنسيق مظهر تذييل الصفحة نريد عرض تذييل الصفحة بالشكل التالي: <!--Footer--> <footer class="col-12 col-s-12 footer"> <p>Created by Hsoub Academy</p> <p><a href="mailto:example@email.com">example@email.com</a></p> </footer> /*تذييل الصفحة */ .footer { background-color: #1d3557; color: white; text-align: center; } .footer a { color: white; } بهذا نكون قد انتهينا من تصميم موقعنا بالكامل وستبدو الصفحة الرئيسية لموقعنا على النحو التالي: يمكن تحميل الكود البرمجي الكامل لموقع معرض الأعمال وتعديله وفق متطلباتكم من هذا الرابط portfolio-website.zip الخاتمة بهذا نكون أنهينا مقالنا، والذي شرحنا فيه خطوة بخطوة كيفية إنشاء معرض أعمال باستخدام تقنيات الويب الأساسية، وسنتعلم في المقال التالي كيفية ترقية معرض الأعمال الحالي وتحويله إلى تطبيق باستخدام إطار جافا سكريبت Vue.js. ترجمة، وبتصرّف للمقال Create a portfolio Website لكاتبه Eric Hu. اقرأ أيضًا التصميم المتجاوب لصفحات الويب Responsive Web Design عرض محتوى صفحات الويب بتجاوب على الأجهزة المتعددة دليلك إلى استعلامات الوسائط Media Queries في CSS كيف تبرمج موقع ويب بسيط باستخدام HTML و CSS و Bootstrap
-
تملك أداة بودمان أداة تسمى بودمان كومبوز Podman Compose وهي بديلة عن أداة دوكر كومبوز Docker Compose وتُتيح لك العمل مع ملفاتها. وكما ذكرنا في مقالاتنا السابقة فإن بودمان يُعدّ بديلًا ممتازًا عن دوكر، لكن إحدى مساوئه هي أنه لا يُتيح ميزة سحب الصور وتشغيل الحاويات بدءًا من ملفات كومبوز. سنتعرف في مقالنا على هذه الأداة والفوائد التي تقدمها عند العمل مع الحاويات وكيفية حل هذه المشكلة من خلالها. ما هي أداة بودمان كومبوز Podman Compose تُتيح أداة دوكر خاصيّة تحديد جميع التفاصيل المهمة كاسم الحاوية، والصورة المُستَخدمة، وسياسة إعادة التشغيل restart policy، ووحدات التخزين، والمنافذ، والتسميات، وما شابه، في ملف واحد يدعى عادةً ملف docker-compose.yml. لكن هذه الخاصيّة ليست موجودةً في بودمان. لذلك يجب أن نستخدم أداة بودمان كومبوز لنحصل عليها. تتبع أداة بودمان كومبوز المواصفات نفسها التي تتبعها أداة دوكر Docker، مما يجعلها تتوافق مع ملفات docker-compose.yml (لكن قد توجد بعض الاختلافات البسيطة كوضع القيم بين علامتي الاقتباس المزدوجة (")، ولكن هذه الاختلافات يمكن حلها بمجرد النظر إلى الأخطاء الناتجة عن استعمال الأداة podman-compose.) تثبيت أداة بودمان كومبوز podman-compose تُعد أداة بودمان كومبوز أداةً جديدةً نسبيًا لذلك قد لا تجدها في مستودعات توزيعات لينكس المستقرة وذات الدعم طويل الأمد LTS distributions. لكن إليك الخيارات المتاحة من أجل تثبيتها: يمكنك تثبيت أداة بودمان كومبوز في توزيعة أوبنتو ذات الإصدار 22.10 نسخة كينيتك كودو Kinetic Kudu والنسخ الأحدث، وفي توزيعة ديبيان النسخة الثانية عشر بوكوورم Bookworm والنسخ الأحدث منها، باستخدام مدير الحزم apt على النحو التالي: sudo apt install podman-compose أما بالنسبة لمستخدمي الإصدار السادس والثلاثين من توزيعة فيدورا Fedora والإصدارات الأحدث (إصدار حزمة النسخة الخامسة والثلاثون من فيدورا هو 0.1.7-6.git) فيمكنهم استخدام مدير الحزم dnf لتثبيت أداة بودمان كومبوز كما يلي: sudo dnf install podman-compose أما لتثبيتها على نسخة OpenSUSE Tumbleweed أو Leap الإصدار الخامس عشر أو الإصدارات الأحدث فاستخدم الأمر التالي: sudo zypper install podman-compose أما مستخدمو Arch Linux فعليهم استخدام الأمر التالي: sudo pacman -Syu podman-compose التأكد من نجاح التثبيت للتأكد من نجاح عملية تثبيت أداة بودمان كومبوز وأن مسارها الصحيح موجود ضمن متغير البيئة path استخدم الأمر التالي والذي سيعرض لك نسخة بودمان المُستخدمة: podman-compose --version إليك خرج الأمر السابق على توزيعة فيدورا النسخة السادسة والثلاثون: $ podman-compose --version ['podman', '--version', ''] using podman version: 4.3.1 podman-composer version 1.0.3 podman --version podman version 4.3.1 exit code: 0 أساسيات أداة بودمان كومبوز إليك المقال التالي عن كيفية استخدام دوكر كومبوز. إليك ملف كومبوز الذي سنستخدمه في مقالنا: version: 3.7 services: reverse-proxy: image: docker.io/library/caddy:alpine container_name: caddy-vishwambhar command: caddy run --config /etc/caddy/Caddyfile restart: always ports: - "8080:80" - "8443:443" volumes: - /docker-volumes/caddy/Caddyfile:/etc/caddy/Caddyfile:Z - /docker-volumes/caddy/site:/srv:Z - /docker-volumes/caddy/caddy_data:/data:Z - /docker-volumes/caddy/caddy_config:/config:Z - /docker-volumes/caddy/ssl:/etc/ssl:Z labels: - io.containers.autoupdate=registry - pratham.container.category=proxy environment: - TZ=Asia/Kolkata depends_on: - gitea-web gitea-web: image: docker.io/gitea/gitea:latest container_name: gitea-govinda restart: always ports: - "8010:3000" - "8011:22" volumes: - /docker-volumes/gitea/web:/data:Z - /docker-volumes/gitea/ssh:/data/git/.ssh:Z - /etc/localtime:/etc/localtime:ro labels: - io.containers.autoupdate=registry - pratham.container.category=gitea environment: - RUN_MODE=prod - DISABLE_SSH=false - START_SSH_SERVER=true - SSH_PORT=22 - SSH_LISTEN_PORT=22 - ROOT_URL=https://git.mydomain.com - DOMAIN=git.mydomain.com - SSH_DOMAIN=git.mydomain.com - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=gitea-db:5432 - GITEA__database__NAME=gitea - GITEA__database__USER=gitea - GITEA__database__PASSWD=/run/secrets/gitea_database_user_password - GITEA__service__DISABLE_REGISTRATION=true - TZ=Asia/Kolkata depends_on: - gitea-db secrets: - gitea_database_user_password gitea-db: image: docker.io/library/postgres:14-alpine container_name: gitea-chitragupta restart: always volumes: - /docker-volumes/gitea/database:/var/lib/postgresql/data:Z labels: - io.containers.autoupdate=registry - pratham.container.category=gitea environment: - POSTGRES_USER=gitea - POSTGRES_PASSWORD=/run/secrets/gitea_database_user_password - POSTGRES_DB=gitea - TZ=Asia/Kolkata secrets: - gitea_database_user_password secrets: gitea_database_user_password: external: true تشغيل كل الحاويات من ملف كومبوز يمكننا باستخدام الأمر up إنشاء الخدمات المذكورة في ملف كومبوز (docker-compose.yml) وتشغيلها: podman-compose up -d يؤدي تشغيل الأمر up إلى تنفيذ كل الإجراءات اللازمة لتشغيل الخدمات والحاويات المذكورة في ملف كومبوز، بما فيه الخطوات التالية: سحب الصور غير المتوفرة محليًا. إنشاء الحاويات مع الخيارات المحددة (المنافذ، ووحدات التخزين، والشبكات، والمعلومات الحساسة secrets). تشغيل الحاويات وفق ترتيب معين (باستخدام القيود constrains مثل depends_on). إذا تمعّنت في المثال السابق ستلاحظ وجود الخيار d- الذي يُشغّل الحاويات في الخلفية ويفصلها عن الصدفة الحالية. يمكنك التأكد من عمل الحاويات بتشغيل الأمر podman ps: $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d7b7f91c03aa docker.io/library/caddy:alpine caddy run --confi... 4 hours ago Up 4 hours ago 0.0.0.0:8080->80/tcp, 0.0.0.0:8443->443/tcp caddy-vishwambhar 1cfcc6efc0d0 docker.io/library/postgres:14-alpine postgres 4 hours ago Up 4 hours ago gitea-chitragupta 531be3df06d0 docker.io/gitea/gitea:latest /bin/s6-svscan /e... 4 hours ago Up 4 hours ago 0.0.0.0:8010->3000/tcp, 0.0.0.0:8011->22/tcp gitea-govinda إيقاف جميع الحاويات باستخدام ملف كومبوز لإيقاف جميع الحاويات المحددة في ملف كومبوز عليك استخدام الأمر down: podman-compose down يمكنك تحديد وقت إيقاف timeout لتتوقف فيه الحاويات عن العمل من تلقاء نفسها، باستخدام أحد الخيارين التاليين: podman-compose down -t TIMEOUT_IN_SECONDS podman-compose down --timeout TIMEOUT_IN_SECONDS يرجى الانتباه إلى أن الأمر down يوقف عمل الحاويات فقط، أما إن أردت حذف الحاويات فعليك حذفها يدويًا. تشغيل أو إيقاف خدمات معينة إن كررت استخدام المنافذ ووحدات التخزين ومتغيرات البيئة، فمن المحتمل أنك ستستخدم الأمر podman-compose up والأمر podman-compose down بشكل متكرر. لكن هذا سيؤدي إلى تشغيل كل الخدمات وإيقافها، على التوالي. أي إن أردت تشغيل خدمة معينة أو إيقافها، فعليك انتظار تشغيل جميع الخدمات المدرجة في ملف كومبوز وإيقافها، وهذا ليس أمرًا محبّذًا. ولحل هذه المشكلة، يمكنك استخدام الأمر start والأمر stop لتشغيل وإيقاف خدمة معينة. ويمكنك استخدام الأمر restart لإعادة التشغيل. إليك المثال التالي الذي يوضح تشغيل الخدمة gitea-db، وإيقافها ثم إعادة تشغيلها: $ podman-comopse start gitea-db $ podman-compose stop gitea-db $ podman-compose restart gitea-db سحب صور الحاويات الضرورية دفعةً واحدة لنفترض أن لديك عشر خدمات مختلفة في ملف كومبوز وأنك تريد تشغيل الحاويات معًا، إذًا بإمكانك استخدام أمر السحب pull كما يلي: podman-compose pull سيؤدي تشغيل الأمر pull إلى سحب كل الصور المحددة في ملف كومبوز. تغيير اسم ملف كومبوز قد ترغب بتغيير اسم ملف كومبوز (docker-compose.yml) إلى اسم آخر، لتنفيذ ذلك يمكنك استخدام أحد الخيارين التاليين: podman-compose -f COMPOSE_FILE_NAME podman-compose --file COMPOSE_FILE_NAME على النحو التالي: podman-compose --file my-compose-file.yml إن تشغيل الأمر السابق يجعل أداة بودمان كومبوز تغير اسم الملف من docker-compose.yml إلى my-compose-file.yml. الخلاصة تهانينا! لقد وصلت إلى نهاية سلسلتنا التعليمية عن أداة بودمان التي تُعدّ أداةً رائعةً لإدارة الحاويات، وعند استخدامها مع أداة بودمان كومبوز يصبح بإمكانك إنشاء حاويات متعددة وتخصيصها وفق الإعدادات التي تناسبك. بها! ننصحك بتجربتها وشاركنا استفساراتك في قسم الأسئلة والأجوبة في أكاديمية حسوب. ترجمة -وبتصرّف- للمقال Beginner's Guide to Using Podman Compose من موقع Linux Handbook. اقرأ أيضًا المقال السابق: إدارة الحاويات محدودة الصلاحية Rootless Containers باستخدام أداة بودمان Podman تشغيل الحاويات تلقائيًا باستخدام أداة بودمان Podman الفرق بين أداتي دوكر Docker وبودمان Podman نظام كوبيرنتس Kubernetes وكيفية عمله
-
ستتعلم في هذا المقال كيفية التعامل مع الحاويات محدودة الصلاحية Rootless Containers باستخدام أداة بودمان. إن كنت تستخدم الحاويات لنشر البرمجيات، أو تستخدم أداة بودمان، أو أنك ترغب في رفع مستوى الأمان عن طريق تشغيل الحاويات محدودة الصلاحية rootless containers، فهذا المقال مناسب لك. ما هي أداة بودمان Podman إن أداة بودمان Podman هي أحد منتجات شركة Red Hat طُرِحَت كبديل فعّال عن أداة دوكر Docker ويمكنها أداء 99% من المهام التي تؤديها أداة دوكر. بعض ميزات بودمان هي دعم الحاويات محدودة الصلاحية rootless containers، واستخدام نموذج fork/exec لتشغيل الحاويات، وأنه لا يعمل وفق مبدأ البرنامج الخفي أي إنه daemon-less، وثمة كثير من الميزات الأخرى. أما مزايا الحاويات محدودة الصلاحية فهي واضحة، فهي لا تحتاج لصلاحيات الجذر الذي يملك وصولًا كاملًا إلى جميع موارد وملفات النظام كي تعمل، لذلك فإن تشغيلها أكثر أمانًا. تشغيل حاويات بودمان محدودة الصلاحية Rootless Containers إذا كنت متمرسًا في مجال تقنية المعلومات، فمن المحتمل أنك وقعت في أحد الخطأين التاليين: تشغيل الأمر docker باستخدام Sudo، وبالتالي زيادة امتيازاته. إضافة مستخدم محدود الصلاحيات non-root إلى مجموعة دوكر docker group. تلك أخطاء تُضِر بأمان النظام بصورة كبيرة؛ لأنك تسمح لبرنامج دوكر الخفي Docker daemon بالوصول إلى جهازك. وهذا يعرضك للخطر بطريقتين: يعمل برنامج دوكر الخفي (dockerd) كجذر، فإذا كانت ثمة ثغرة أمنية فيه، سيكون نظامك بكامله عرضةً للخطر لأن dockerd هي عملية تابعة للمستخدم الجذر. قد تحتوي الصورة التي تستخدمها على ثغرات أمنية. تخيّل ماذا سيحدث عند استخدام هذه الصورة بواسطة حاوية تعمل كعملية للمستخدم الجذر root process. يمكن لأحد المخترقين استخدام هذه الصورة للوصول إلى كافة موراد النظام. الحل بسيط، عليك الامتناع عن تشغيل البرامج بصلاحيات الجذر، حتى لو كنت تثق بها. تذكر أنه لا يوجد شيء آمن بنسبة 100%. وهنا تأتي ميزة بودمان في إدارة الحاويات دون الحاجة إلى الوصول إلى الجذر. فعند تشغيل حاوية باستخدام بودمان كمستخدم غير جذر، لن تحصل تلك الحاوية على امتيازات إضافية، ولن يطلب منك بودمان كلمة مرور sudo. إليك المزايا التي توفرها أداة بودمان عند إدارة الحاويات محدودة الصلاحية root-less containers: يمكنك تخصيص مجموعة من الحاويات المشتركة لكل مستخدم محلي. (على سبيل المثال، بإمكانك تشغيل Nextcloud وMariaDB لدى المستخدم nextcloud_user وتشغيل الحاويات Gitea وPostgreSQL لدى المستخدم gitea_user). حتى لو اختُرِقَت الحاوية، فلا يمكن التحكم بالنظام المضيف بكامله، لأن المستخدم المسؤول عن الحاوية ليس جذرًا. لكنه لن يعود صالحًا للاستخدام. قيود استخدام حاويات بودمان محدودة الصلاحية عند استخدام أداتي بودمان ودوكر مع صلاحيات المستخدم الجذر أي بنمط عمل root-full، فأنت تمنحها امتيازات على مستوى المستخدم المسؤول أو المميز super-user. وهذا ليس أمرًا محمودًا، ولكنه يضمن أن جميع الوظائف تعمل على النحو المطلوب. ومن الناحية الأخرى، ثمة بعض القيود على تشغيل حاويات بودمان بدون امتيازات الجذر، إليك أهمها: لا يمكن تشارك صور الحاويات بين المستخدمين إذا سحب المستخدم user0 صورة الحاوية nginx:stable-alpine فيجب على المستخدم user1 سحبها بنفسه مرةً أخرى. لا توجد لحد الآن طريقة تسمح تشارك الصور بين المستخدمين، لكن يمكنك نسخ الصور من مستخدم لآخر باتباع هذا الدليل من شركة ريد هات Red Hat. لا يمكن ربط المنافذ ports binding ذوات الأرقام الأدنى من 1024، لكن ثمة طريقة لحل هذه المشكلة. لا يمكن للحاوية محدودة الصلاحية إرسال الطلب ping لأي من المضيفين hosts. لكن ثمة طريقة لحل هذه المشكلة. إذا عيّنت معرّفًا مميزًا UID لحاوية بودمان محدودة الصلاحية، فقد يفشل ذلك إن لم تسند المعرّف المميز UID إلى حاوية موجودة مسبقًا. إذًا، من الأفضل تشغيل بودمان من صدفة طرفية (shell) مستخدم موجود، والخيار الأفضل هو إنشاء خدمة systemd لتشغيلها تلقائيًا. تشغيل حاويات محدودة الصلاحية Rootless Containers باستخدام بودمان قبل أن تبدأ بتشغيل الحاويات محدودة الصلاحية، ثمة بعض المتطلبات التي عليك توفيرها. تثبيت حزمة slirp4netns تُستخدم الحزمة slirp4netns لتوفير خيارات الشبكة لوضع المستخدم user-mode networking لفضاءات أسماء الشبكة. يعد هذا الأمر ضروريًا كي تتفاعل الحاوية محدودة الصلاحية مع أي شبكة وبدونها لا يمكن للحاويات محدودة الصلاحية الاتصال بالإنترنت أو الشبكات الداخلية، مما يحد من فائدتها بشكل كبير. يمكنك تثبيت حزمة slirp4netns على التوزيعات المعتمدة على نظامي ديبيان Debian وأوبنتو Ubuntu باستخدام مدير الحزم apt: sudo apt install slirp4netns أما في التوزيعات المعتمدة على نظامي فيدورا Fedora وريد هات Red Hat فاستخدم مدير الحزم dnf لتثبيت الحزمة، على النحو التالي: sudo dnf install slirp4netns بالنسبة لمستخدمي Arch Linux فعليك استخدام الأمر pacman على النحو التالي: sudo pacman -Sy slirp4netns ضبط subuid و subgid على النحو الصحيح نظرًا لأن حاويات بودمان محدودة الصلاحية تُشَغّل بواسطة مستخدم موجود على النظام، فإن المستخدم يحتاج إلى إذن لتشغيل هذه الحاوية بمعرّف مميز UID مختلف عن معرف المستخدم. وهذا ينطبق أيضًا على معرّف المجموعة GID. يُمنح كل مستخدم نطاقًا من المعرفات التي يُسمح له باستخدامها، تذكر المعرفات الفريدة UID في الملف /etc/subuid، أما معرفات المجموعات GID فتذكر في الملف /etc/subgid. وصيغة الملف هي على النحو التالي: username:initial UID/GID allocated to user:range/size of allowed UIDs/GIDs فلنفرض أن اسم المستخدم pratham يريد مئة معرّف مميز، والمستخدم krishna يريد ألفًا، إذًا ستكون صيغة الملف /etc/subuid على النحو التالي: pratham:100000:100 Krishna:100100:1000 يعني هذا أن المستخدم pratham يمكنه استخدام المعرّفات UID من المعرّف 100000 إلى 100100، والمستخدم krishna يمكنه استخدامها بدءً من المعرّف 100100 إلى 101100. يكون هذا عادةً مُعَدًا مسبقًا لكل مستخدم تنشئه، ويُحَدد للنطاق 65536 معرفًا قابلًا للاستخدام سواء كان معرفًا مميزًا UID أم معرّف مجموعة GID. ولكن، يجب أن تضبطه يدويًا في بعض الحالات. ولكن ليس عليك ضبط ذلك يدويًا لكل مستخدم، إذ يمكنك استخدام الأمر usermod لهذا الغرض. إليك صيغة الأمر المطلوبة: sudo usermod --add-subuids START-RANGE --add-subgids START-RANGE USERNAME والآن استبدل كل من السلسلة START و RANGE و USERNAME بما يناسبك. ** تنبيه:** احرص على ضبط سماحيات الملفين /etc/subuid و/etc/subgid على القيمة 644 وأن يكونا تابعين للمستخدم الجذر root:root. ربط المنافذ ذات الأرقام الأدنى من 1024 إن استخدمت وكيلًا عكسيًا reverse proxy لبروتوكول SSL، فأنت تعلم أن المنفذين 80 و443 يجب أن يكونا متاحين لمزود الشهادات مثلLet's Encrypt. إذا حاولت ربط المنافذ الأقل من 1024 بحاوية بودمان محدودة الصلاحية، فستلاحظ أن ذلك غير متاح كميّزة جاهزة out of the box. إذ لا يُسمح للمستخدم غير الجذر بربط أي شيء على المنافذ الأدنى من المنفذ 1024. إذًا، كيف يمكن ربط المنافذ الأدنى بحاويات بودمان محدودة الصلاحية؟ عليك أولاً تحديد المنفذ الأدنى الذي تحتاجه. في حالتنا، تحتاج إلى المنفذين 80 و443 لنشر بروتوكول SSL، لذا فإن أقل منفذ تحتاجه هو المنفذ 80. والآن، أضف السطر التالي إلى الملف /etc/sysctl.conf: net.ipv4.ip_unprivileged_port_start=YOUR_PORT_NUMBER ما ستفعله هو تغيير قيمة net.ipv4.ip_unprivileged_port_start إلى قيمة أدنى منفذ تحتاجه، إذًا عليك استبدال YOUR_PORT_NUMBER بالقيمة 80 كي تربط المنفذ 80 بحاوية محدودة الصلاحية. أين توجد صور الحاويات كما ذكرنا سابقًا فأحد قيود عمل أداة بودمان هي أنها لا تتيح مشاركة الصور بين المستخدمين. فيجب أن يسحب كل مستخدم الصورة، أو يجب نسخ الصورة من مستخدم لآخر. كلا الخيارين سيحجز ضعف أو أضعاف المساحة، حسب عدد نسخ الصور.حيث تُخَزّن صور حاويات المستخدم في المجلد الرئيسي، وبالتحديد داخل المجلد ~/local/share/containers/storage/ والآن، بعد أن تحققتَ من توفر المتطلبات السابقة، يمكنك تشغيل الأمر podman run من صدفة خارجية non-root user's shell وإنشاء حاوية. سنستخدم خادم Caddy في مثالنا لنشر بروتوكول SSL. شغّل خادم Caddy في حاوية محدودة الصلاحية واربطه بمنفذ أدنى من المنفذ 1024 على النحو التالي: $ whoami pratham $ podman run -d --name=prathams-caddy -p 80:80 -p 443:443 caddy:alpine e6ed67eb90e6d0f3475d78b287af941bc873f6d62db60d5c13b1106af80dc5ff $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e6ed67eb90e6 docker.io/library/caddy:alpine caddy run --confi... 2 seconds ago Up 2 seconds ago 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp prathams-caddy $ ps aux | grep caddy pratham 3022 0.0 0.0 85672 2140 ? Ssl 06:53 0:00 /usr/bin/conmon --api-version 1 -c e6ed67eb90e6d0f3475d78b287af941bc873f6d62db60d5c13b1106af80dc5ff [...] pratham 3025 0.1 0.3 753060 32320 ? Ssl 06:53 0:00 caddy run --config /etc/caddy/Caddyfile --adapter caddyfile لاحظ أن المستخدم pratham ليس جذرًا وأنه لا حاجة لاستخدام الأمر sudo لزيادة صلاحيات المستخدم. إذ استطعت تشغيل حاوية خادم Caddy محدودة الصلاحية باستخدام أداة بودمان. يُظهِر خرج الأمر ps أن رمز العملية PID ذو الرقم 3022هو عملية تابعة للمستخدم pratham وهي حاوية خادم Caddy (لكننا لم نُظهِر الخرج كاملًا في مثالنا). أما العملية 3025 فهي تابعة child process للعملية 3022 وهما تابعتان للمستخدم نفسه. الخلاصة وضّحنا في هذا المقال كيفية إدارة الحاويات محدودة الصلاحية باستخدام أداة بودمان، وتحدثنا عن البرامج الضرورية لذلك، وتطرقنا إلى بعض المشكلات الشائعة التي قد تواجهها وكيفية حلها. إن واجهت مشكلةً لم نأتِ على ذكرها مع حاويات بودمان محدودة الصلاحية، فذلك لأن أداة بودمان لا تزال جديدةً بالنسبة للبرمجيات، لذا من المحتمل ظهور بعض المشكلات، في هذه الحالة، شاركنا استفسارك في قسم الأسئلة والأجوبة في أكاديمية حسوب. كما يمكنك الاطلاع على التوثيق الرسمي من موقع بودمان. ترجمة -وبتصرّف- للمقال Getting Started With Rootless Container Using Podman من Linux Handbook. اقرأ أيضًا المقال السابق: تحديث حاويات بودمان Podman تلقائيًا تعلم الحوسبة السحابيّة: المتطلبات الأساسيّة، وكيف تصبح مهندس حوسبة سحابيّة الفرق بين أداتي دوكر Docker وبودمان Podman الفرق بين دوكر Docker وكوبيرنيتيس Kubernetes؟ ما عليك معرفته عن الفرق بين دوكر والأجهزة الافتراضية أساسيات تنسيق الحاويات
-
سنقدم لك في هذا المقال دليلًا مفصلًا حول كيفية ضبط التحديثات التلقائية للحاويات المُدارة بواسطة أداة بودمان Podman وتفعيلها. فتحديث البرامج أمر محبّذ، لا سيما عندما تحتوي التحديثات على ميزات جديدة أو خيارات لزيادة الأمان. لتسهيل العمل سنستخدم في هذا المقال صورة الخادم Caddy من مستودع Docker Hub. تعيين مصدر جلب صور الحاويات كي تستطيع استخدام صورة حاوية (container image) يجب أولًا سحب هذه الصورة من أحد المصادر باستخدام أداة إدارة الحاويات بودمان، يدعى هذا المصدر بسياسة التحديث التلقائي auto-update policy وهي تتضمن قواعد أو إعدادات تحدد زمان وكيفية تحديث الصور أو الحاويات بشكل تلقائي دون تدخل يدوي، مثلاً عند إصدار تحديث جديد للصورة، يتم تحميل التحديث وتطبيقه بشكل تلقائي دون تدخل المستخدم وذلك على النحو التالي: سجل registry: عند إسناد سجل (موقع) ما إلى سياسة التحديث التلقائي auto-update policy فإن بودمان سيسحب الصورة من سجل خارجي remote registry مثل Docker Hub أو Quay.io. مصدر محلي local: عند إسناد الخيار local إلى سياسة التحديث التلقائي، فإن أداة بودمان ستجلب الصورة من الصور المحلية. يُعدّ هذا الخيار هذا الخيار مفيدًا للمطورين الذين يرغبون في اختبار التعديلات المحلية قبل دفعها إلى سجل بعيد. ملاحظة: نستخدم في أمثلة هذا المقال حاوية محدودة الصلاحية root-less container، وحاولنا قدر الإمكان ذكر الأوامر الخاصة بالحاويات كاملة الصلاحية root-full container. فإن استخدمت حاوية كاملة الصلاحية وواجهك خطأ يتعلق بصلاحيات المستخدم، فعليك استخدام الأمر sudo. تفعيل التحديثات التلقائية لحاويات Podman يمكنك الآن تفعيل التحديثات التلقائية لحاويات بودمان بعد أن أصبحت تعلم ما هو مفهوم سياسة التحديث التلقائي، وذلك باستخدام الأمر التالي: io.containers.autoupdate=AUTO_UPDATE_POLICY والآن استبدل السلسلة AUTO_UPDATE_POLICY بالخيار registry أو local. ولكن كيف ستتحدث الحاوية تلقائيًا وأداة بودمان لا تعمل كبرنامج خفي؟ ضبط خدمة systemd عليك إدارة الحاويات التي تحتاج إلى التحديث التلقائي بواسطة نظام التمهيد systemd، وذلك لأن أداة بودمان لا تعمل كبرنامج خفي. إن أردت تشغيل الحاويات تلقائيًا عند إقلاع النظام، فلا شك أنك تستخدم systemd. سنشرح في الخطوات التالية كيفية دمج حاويات بودمان سواء كانت حاويات كاملة أو محدودة الصلاحية، مع خدمة systemd وتشغيلها تلقائيًا عند الاقلاع. الخطوة التمهيدية، إنشاء الحاوية عليك التأكد أولًا أن لديك حاوية بودمان، سواء كانت قيد العمل أو متوقفة. استخدم الأمر التالي للتحقق من الحاويات الموجودة عندك: podman container list لتوضيح أمثلة هذا المقال، اسحب صورةً قديمةً من خادم Caddy (الإصدار 2.5.2-alpine) ثم أعد تسميتها بالاسم alpine، إذ ستساعد إعادة تسمية الصورة في توضيح عملية التحديث. ويمكنك التحقق من ذلك لأن معرف الصورتين هو نفسه. ثم أنشئ حاويةً من الصورة وسمّها prathams-caddy: $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/library/caddy 2.5.2-alpine d83af79bf9e2 2 weeks ago 45.5 MB docker.io/library/caddy alpine d83af79bf9e2 2 weeks ago 45.5 MB $ podman container list CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 99d1838dd999 localhost/caddy:alpine caddy run --confi... 5 seconds ago Up 6 seconds ago prathams-caddy كما تلاحظ فإن لدينا حاويةً تدعى prathams-caddy تعمل على صورة Caddy (الإصدار الأقدم). عندما تنشئ الحاوية Prathams-caddy أسند سياسة التحديث التلقائي io.containers.autoupdate على خيار السجل registry كما تعلمنا في الخطوة السابقة. إذا كان لديك حاوية بدون هذا التعديل، فلست بحاجة إلى إعادة إنشاء حاوية جديدة. سنتحدث عن ذلك في الخطوة التالية. الخطوة الأولى، إنشاء ملف خدمة systemd للحاوية كي تتمكن من إدارة حاويات بودمان باستخدام نظام systemd، يجب عليك تحويله إلى خدمة، لتشغيل الحاويات عند إقلاع النظام وإيقافها عند إيقاف تشغيل النظام. إذًا، يجب تشغيل الحاوية كخدمة systemd. ولكن كي لا تضطر إلى كتابة ملف خدمة systemd لكل حاوية، أوجد مطورو أداة بودمان حلًا لذلك، وهو تشغيل أمر معين لكل حاوية. عليك تشغيل الأمر التالي للحاويات كاملة الصلاحية root-full container: sudo podman generate systemd -f --new --name CONTAINER_NAME والأمر التالي للحاويات محدودة الصلاحية root-less container: podman generate systemd -f --new --name CONTAINER_NAME ثم استبدل CONTAINER_NAME باسم حاويتك، وسيتولد بعدها ملف باسم الحاوية كما يلي: $ podman generate systemd -f --new --name prathams-caddy /home/pratham/container-prathams-caddy.service لاحظ من الخرج السابق إنشاء حاوية باسم container-prathams-caddy.service في الملف الحالي. سبق أن ضبطتَ ميزة التحديث التلقائي لهذه الحاوية. أما بالنسبة للحاويات التي لم تضبط فيها هذه الميزة، فليس عليك إعادة إنشاء الحاوية بل يكفي تعديل ملف خدمة systemd وإضافة السطر التالي إلى حقل ExecStart على النحو التالي: [...] ExecStart=/usr/bin/podman run \ [...] --label io.containers.autoupdate=registry [...] وهكذا يستدعي ملف خدمة systemd أمر تشغيل حاويات بودمان podman run. وكل ما عليك فعله هو إضافة io.containers.autoupdate إلى الأمر podman run. الخطوة الثانية، نقل ملف خدمة systemd قبل تفعيل خدمة systemd، يجب عليك نقل ملف الخدمة إلى أحد المجلدين التاليين: /etc/systemd/system/ : إذا كانت الحاوية كاملة الصلاحية وتحتاج إلى امتيازات المستخدم المسؤول superuser. ~/.config/systemd/user/ : إذا كانت الحاوية محدودة الصلاحية، ضعها في مجلد المستخدم الذي سيشغلها. إن الحاوية Prathams-caddy في مثالنا هي حاوية محدودة الصلاحية، لذا عليك نقلها إلى مجلد المستخدم الخاص بك: $ mv -v container-prathams-caddy.service ~/.config/systemd/user/ renamed 'container-prathams-caddy.service' -> '/home/pratham/.config/systemd/user/container-prathams-caddy.service' الخطوة الثالثة، تفعيل خدمة systemd أصبح بإمكانك الآن تفعيل خدمة systemd بعد أن نقلت ملف الخدمة إلى المجلد المناسب. لكن، يجب أولاً إعلام نظام systemd بالخدمة التي أنشأتها قبل إعادة تشغيل حاسوبك. وذلك بإعادة تحميل systemd باستخدام الأمر التالي إذا كانت الخدمة خاصةً بحاوية كاملة الصلاحية: sudo systemctl daemon-reload والأمر التالي للحاويات محدودة الصلاحية: systemctl --user daemon-reload أصبح بإمكانك الآن استخدام الأمر systemctl enable لتفعيل الخدمة: # للحاويات كاملة الصلاحية sudo systemctl enable SERVICE_NAME.service # للحاويات محدودة الصلاحية systemctl --user enable SERVICE_NAME.service تحقق من حالة الخدمة، ستلاحظ أنها غير نشطة inactive (dead) وذلك لأن الخدمة تعمل عند إعادة إقلاع الحاسوب أو النظام، ولم ننفذ ذلك بعد. $ systemctl --user enable container-prathams-caddy.service Created symlink /home/pratham/.config/systemd/user/default.target.wants/container-prathams-caddy.service → /home/pratham/.config/systemd/user/container-prathams-caddy.service. $ systemctl --user status container-prathams-caddy.service ○ container-prathams-caddy.service - Podman container-prathams-caddy.service Loaded: loaded (/home/pratham/.config/systemd/user/container-prathams-caddy.service; enabled; vendor preset: enabled) Active: inactive (dead) Docs: man:podman-generate-systemd(1) والآن أوقف عمل الحاوية ثم استخدم الأمر التالي لحذفها podman container rm وأعد إقلاع جهازك بعدها. $ podman stop prathams-caddy prathams-caddy $ podman container rm prathams-caddy 99d1838dd9990b2f79b4f2c83bc9bc16dfbaf3fdeeb6c6418ddd6e641535ce21 الخطوة الرابعة، تفعيل بقاء المستخدم نشطًا (اختيارية) إذا كانت حاويتك محدودة الصلاحية فمن الأفضل أن يبقى المستخدم المسؤول عنها نشطًا، وذلك باستخدام الأمر التالي: sudo loginctl enable-linger الخطوة الخامسة، تفعيل خدمة التحديث التلقائي كل ما عليك فعله الآن هو تفعيل خدمة التحديث التلقائي في بودمان باستخدام الأمر التالي: sudo systemctl enable podman-auto-update.service بعد تفعيل خدمة التحديث التلقائي podman-auto-update في بودمان، سيتحقق systemd من وجود صورة بحاجة إلى تحديث. إذا كان هناك تحديثات، تُحدّث الصور التي جلبت أولاً، ثم يُعاد تشغيل الحاوية، مع الاحتفاظ بالصورة القديمة في حالة الحاجة إلى التراجع عن التحديث لعدة أسباب. ملاحظة: على الرغم من أن خدمة التحديث التلقائي في بودمان podman-auto-update.service تُفعّل على مستوى النظام، إلا أن أداة بودمان ليست أساسية في عديد من التوزيعات غير التابعة لتوزيعة فيدورا Fedora. لذلك، ربما تحتاج إلى تشغيل الأمر التالي لتفعيل الخدمة عند المستخدمين محدودي الصلاحية: systemctl --user Enable --now podman-auto-update.service التحديث اليدوي إن لم تكن من محبي التحديثات التلقائية، فيمكنك تحديث الحاويات يدويًا باستخدام أمر واحد فقط، بشرط أن تكون مدارةً بواسطة systemd. هذا الأمر هو podman auto-update. وإن أردت التحقق من وجود تحديثات جديدة فقط، فأضف خيار dry-run-- حتى لا تُحَدّث أي حاوية. والآن لنتحقق من إمكانية تحديث صورة الحاوية "2.5.2-alpine" إلى الإصدار "2.6.1-alpine" باستخدام الأمر podman auto-update: $ podman container list CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a712a3c8846b docker.io/library/caddy:alpine caddy run --confi... 2 seconds ago Up 2 seconds ago prathams-caddy $ podman auto-update --dry-run UNIT CONTAINER IMAGE POLICY UPDATED container-prathams-caddy.service a712a3c8846b (prathams-caddy) caddy:alpine registry pending لاحظ أن حالة العمود updated في خرج أمر التحديث التلقائي هي pending أو معلقة وهذا يعني أنه ثم تحديث متوفر. كي تحدّث الحاوية، أزل الخيار dry-run-- من الأمر السابق. الخلاصة قد تبدو عملية تفعيل التحديثات التلقائية لحاويات بودمان معقدةً بعض الشيء، ولكنها ستؤتي ثمارها على المدى الطويل. تُحدّث جميع الحاويات المُدارة عادة بصورة تلقائية عند منتصف الليل في حال وجود التحديثات. وإن حدثت اي مشكلة في الحاوية فإن systemd سيعيدها إلى صورة قديمة، بحيث تستمر الحاوية في العمل. ترجمة وبتصرّف للمقال Automatically Updating Podman Containers من Linux Handbook. اقرأ أيضًا المقال السابق: تشغيل الحاويات تلقائيًا باستخدام أداة بودمان Podman أساسيات تنسيق الحاويات ما الفرق بين دوكر Docker وكوبيرنيتيس Kubernetes؟ ما عليك معرفته عن الفرق بين دوكر والأجهزة الافتراضية
-
لا شك أن أداة بودمان ممتازة لإدارة الحاويات بما تقدمه من ميزات متعددة، لكنها لا توفر خاصية التشغيل التلقائي للحاويات عند إقلاع النظام، سنتعلم في هذا المقال كيف نجد حلًا لهذه المشكلة. على الرغم من أن أداة بودمان لا تعمل كبرنامج خفي daemon، وتسمح للمستخدم محدود الصلاحيات unprivileged user بتشغيل الحاويات دون الحاجة إلى الوصول إلى الجذر، مما يزيد من أمان النظام. لكنها ليست أداةً مثاليةً بالكامل فهي لا تُتيح إعادة تشغيل الحاويات تلقائيًا بعد إقلاع الخادم. سياسة إعادة تشغيل الحاويات عند الاطلاع على صفحة التعليمات man الخاصة بالأمر podman-run ستجد أن خيار إعادة التشغيل restart-- لا يعيد تشغيل الحاويات عندما يقلع النظام. وسبب هذا يرجع إلى أن بنية بودمان لا تعتمد مبدأ البرنامج الخفي، أي إن بودمان لا يعمل تلقائيًا عند إقلاع النظام، وبالتالي فإن الحاويات لا تعمل عند الإقلاع أيضًا. على عكس أداة دوكر التي تعتمد مبدأ البرنامج الخفي الذي يعمل عند إقلاع النظام ويُشَغّل الحاويات المحددة. حل مشكلة عدم التشغيل التلقائي للحاويات أيًّا كانت توزيعة نظام التشغيل التي تعمل عليها فلا بد أنها تستخدم systemd كنظام تمهيد init، وهذا ما سنحاول الاستفادة منه في إيجاد حل للمشكلة. الخطوة الأولى: إعداد الحاوية وتشغيلها ثمة عدة طرق ممكنة لتشغيل الحاوية. إن كان لديك حاوية بسيطة فبإمكانك استخدام الأمر podman run. أو يمكنك استخدام ملف دوكر إن أردت حاويةً بإعدادات معقدة واحتجت لمزيد من التحكم بهذه الإعدادات. لتوضيح ذلك، سننشئ حاويةً من صورة الحاوية mariadb وسنسميها chitragupta-db. $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 422eed872347 docker.io/library/mariadb:latest --transaction-iso... 58 seconds ago Up 58 seconds ago chitragupta-db يمكنك إيقاف الحاوية الجديدة لاحقًا. الخطوة الثانية: إنشاء خدمة systemd كما ذكرنا سابقًا، فإن بودمان ليس برنامجًا خفيًا أي إنه daemon-less لإدارة الحاويات. إذًا، فإن تشغيل حاويات بودمان يحتاج إلى تشغيل يدوي أو خارجي. سننفذ ذلك من خلال إنشاء خدمة systemd. حيث إن خدمة systemd هي نظام تمهيد init يدير الخدمات والبرامج الخفية في أنظمة تشغيل لينكس. إنشاء ملف وحدة systemd ليس عليك إنشاء ملف وحدة systemd يدويًا، إذ يمكن تنفيذ ذلك باستخدام الأمر podman generator systemd على النحو التالي: podman generate systemd --new --name CONTAINER_NAME لإنشاء ملف وحدة systemd للحاوية استخدم الأمر podman generate systemd متبوعًا باسم الحاوية، اسم الحاوية في مثالنا هو chitragupta-db: كما تلاحظ فإن الأمر السابق نفّذ العمل المطلوب، ولكننا لم ننته من العمل بعد. إن خرج الأمر podman generate systemd هو ما يجب أن يكون موجودًا في ملف وحدة systemd، لكن ثمة خيار مفيد يمكنك الاستعانة به بدلًا من نسخ الخرج ولصقه، وهو الخيار files -- أو اختصارًا f-. إذ سيؤدي استخدام هذا الخيار أولًا إلى ملء الملف بالمحتوى المطلوب بدلاً من طباعته على الطرفية، وثانيًا، إنشاء ملف باسم Container-CONTAINER_NAME.service في مجلد العمل الحالي. $ podman generate systemd --new --name chitragupta-db -f /home/pratham/container-chitragupta-db.service $ ls *.service Container-chitragupta-db.service لاحظ أن اسم الحاوية في مثالنا هو chitragupta-db، وأنه أصبح لدينا ملف باسم container-chitragupta-db.service في المجلد الحالي. بما أن الأمر podman generate systemd سوف ينشئ ملف وحدة systemd فإن بإمكانك استخدام الخيارات التالية =after=, --requires=, --wants-- لتحديد الاعتماديات للحاويات. نقل ملف خدمة systemd إلى موقع محدد كما لاحظت فإن الأمر السابق سينشئ ملف وحدة systemd جديد في مجلد العمل الحالي، لكن ذلك ليس الخيار الأنسب. إليك المسار المناسب للملف بالنسبة للمستخدم المسؤول superuser: /etc/systemd/system/ أما بالنسبة للمستخدم محدود الصلاحيات non-root user فهو: ~/.config/systemd/user/ والآن عليك نقل الملف إلى المجلد المناسب. بما أن الحاوية في مثالنا هي حاوية محدودة الصلاحية، فعليك نقلها إلى المجلد config/systemd/user/.~. $ mv -v container-chitragupta-db.service ~/.config/systemd/user/ renamed 'container-chitragupta-db.service' -> '/home/pratham/.config/systemd/user/container-chitragupta-db.service' وهكذا بعد أن أنشأت ملف وحدة systemd بالاستعانة بأوامر الطرفية ونقلته إلى المجلد الصحيح، ما تبقى عليك الآن هو تفعيله. الخطوة الثالثة: تفعيل حاوية خدمة systemd عليك الآن أن تعيد إقلاع systemd كي تتفعل الخدمة التي أنشأتها في الخطوة السابقة. استخدم الأمر التالي لإعادة تشغيل خدمة systemd للمستخدم الجذر: sudo systemctl daemon-reload أما بالنسبة للمستخدم محدود الصلاحيات فعليك إزالة الأمر sudo وإضافة الخيار user--، كي يصبح الأمر على الشكل التالي: systemctl --user daemon-reload وهكذا سيُعاد تشغيل خدمة systemd دون إعادة إقلاع النظام، وسيُحدّث وتظهر الخدمة الجديدة container-chitragupta-db.service. والآن أصبح بإمكانك تفعيل الخدمة الجديدة. استخدم الأمر التالي لتفعيل الخدمة للمستخدم الجذر: sudo systemctl enable SERVICE_NAME.service أما بالنسبة للمستخدم محدود الصلاحيات فعليك إزالة الأمر sudo وإضافة الخيار user--، كي يصبح الأمر على الشكل التالي: systemctl --user enable SERVICE_NAME.service ستحصل على الخرج التالي عند تفعيل الحاوية محدودة الصلاحية root-less container: $ systemctl --user enable container-chitragupta-db.service Created symlink /home/pratham/.config/systemd/user/default.target.wants/container-chitragupta-db.service → /home/pratham/.config/systemd/user/container-chitragupta-db.service. يمكنك التحقق من حالة الخدمة بعد تفعيلها بإضافة الأمر status على الأمر السابق للمستخدم الجذر والمستخدم محدود الصلاحية وفقًا لما يلي: # للمستخدم الجذر sudo systemctl status SERVICE_NAME.service # للمستخدم محدود الصلاحية systemctl --user status SERVICE_NAME.service إليك حالة الخدمة container-chitragupta-db: $ systemctl --user status container-chitragupta-db.service ○ container-chitragupta-db.service - Podman container-chitragupta-db.service Loaded: loaded (/home/pratham/.config/systemd/user/container-chitragupta-db.service; enabled; vendor preset: disabled) Active: inactive (dead) Docs: man:podman-generate-systemd(1) لا تقلق لأن حالة الخدمة تظهر غير نشطة inactive (dead)، إذ فعّلنا الخدمة الآن ويجب أن تعمل الخدمة عند إقلاع النظام، وليس الآن، وهذا هو المطلوب. إذا لم توقف الحاوية في الخطوة الأولى، فهذا هو الوقت المناسب لإيقافها عن طريق استخدام الأمر podman stop ثم استخدام الأمر podman container rm لحذفها، وإعادة إقلاع النظام بعدها لتشغيل خدمة الحاوية. الخطوة الرابعة: تفعيل خدمة إعادة التشغيل قد تحتاج في بعض التوزيعات إلى تفعيل خدمة إعادة التشغيل في بودمان أيضًا. ينطبق هذا على التوزيعات غير المعتمدة على نظام فيدورا، وخاصةً توزيعة NixOS. لتفعيل خدمة إعادة التشغيل عليك استخدام الأمر التالي: systemctl --user enable podman-restart.service يحرص الأمر podman-restart على إعادة تشغيل جميع الحاويات التي ضُبطت ليُعاد تشغيل دائمًا أي عند ضبط الأمر restart-policy على الخيار always. الخطوة الخامسة، تفعيل بقاء المستخدم محدود الصلاحية نشطًا (خطوة اختيارية) بما أنك فعّلت هذه الخدمة بواسطة مستخدم عادي محدود الصلاحية وليس المستخدم الجذر، هذا يعني أن المستخدم يحتاج إلى تسجيل الدخول عند التشغيل ويجب أن يظل نشطًا إن خرج من جلسة واجهة المستخدم الرسومية GUI أو من الطرفية. ويمكن تحقيق ذلك باستخدام الأمر loginctl من طرفية المستخدم نفسه، على النحو التالي: sudo loginctl enable-linger يضمن هذا الأمر تفعيل جلسة المستخدم عند الإقلاع وبقاءها نشطةً حتى بعد تسجيل الخروج من واجهة المستخدم الرسومية أو الطرفية. وبهذا تكون قد فعّلتَ إعادة تشغيل حاويات بودمان عند الإقلاع. حيث ستؤدي إعادة تشغيل النظام إلى التشغيل التلقائي للحاويات التي أنشأت لها ملف وحدة systemd. تعديل خدمة systemd نعلم جميعًا أن الإعدادات الافتراضية تفيد المبتدئين دائمًا، إذ تساعد على تخفيف شعور الارتباك لديهم. تُعد الإعدادات الإفتراضية لملف systemd الذي أنشأته مثاليةً لمعظم الأشخاص، لكن إن لم تكن مبتدئًا فبإمكانك إضافة مزيد من التعديلات من خلال تعديل ملف systemd أو إنشاء خدمة مخصصة جديدة من الصفر. الخلاصة تعلمنا في هذا المقال كيفية إنشاء ملفات وحدة systemd للتشغيل التلقائي لحاويات بودمان عند إقلاع النظام. حيث أن استخدام خدمة systemd سيساعدك في مراقبة الحاويات التي تستخدم واجهة systemd. ترجمة وبتصرّف للمقال Autostarting Podman Containers من موقع Linux Handbook. اقرأ أيضًا المقال السابق: إنشاء الحاويات وحذفها باستخدام أداة بودمان Podman نظام كوبيرنتس Kubernetes وكيفية عمله كيفية تأمين الحاويات عن طريق سي لينكس SELinux الفرق بين أداتي دوكر Docker وبودمان Podman
-
هل أنت حديث العهد باستخدام أداة بودمان؟ إن كان جوابك نعم، فلا تقلق، سنتعلم في هذا المقال كيفية إنشاء الحاويات وكيفية عرضها وإيقافها وحذفها باستخدام بودمان. هذا المقال جزء من سلسلة مقالات بودمان Podman وهي تهدف لتعريفك على هذه الأداة كي تستطيع عند نهاية هذه المقالات، التعرف على الفرق بين دوكر وبودمان، وبدء استخدام بودمان بكفاءة عند العمل مع الحاويات. ما ستتعلمه في سلسلة تعرف على أداة بودمان Podman سنتعلم في هذه سلسلة ما يلي: الفرق بين أداتي دوكر وبودمان إنشاء الحاويات وحذفها باستخدام أداة بودمان تفعيل حاويات بودمان تلقائيًا عند إقلاع النظام تحديث الحاويات مفهوم الحاويات محدودة الصلاحية Rootless containers مفهوم بودمان كومبوز Podman Compose متطلبات هذه السلسلة معرفة مسبقة بمفهوم الحاويات تجربة مسبقة في التعامل مع دوكر خبرة في التعامل مع سطر الأوامر أو الطرفية Terminal في لينكس كما تعلمنا في مقال سابق فإن أداة بودمان هي أداة بديلة عن دوكر تستخدم لإدارة الحاويات، ولها بنية أوامر مشابهة لأوامر دوكر. وسنتعلم في مقال اليوم كيفية إنشاء الحاويات وحذفها. سحب الصور من سجل الصور باستخدام بودمان عند إنشاء الحاويات، ستحتاج أولًا إلى صورة للحاوية image، إذ لا يمكنك تنفيذ شيء بدون الصورة. ولذلك عليك سحب pull الصورة من سجل الصور. إليك بعض سجلات الصور الشهيرة: Docker Hub Quay.io سجلات الصور المستضافة مثل linuxserver.io ولسحب صورة باستخدام بودمان فعليك استخدام الصيغة التالية: podman pull [OPTIONS] FULLY_QUALIFIED_IMAGE_NAME[:tag|@digest] لمعرفة معنى اسم الصورة المؤهل بالكامل FULLY_QUALIFIED_IMAGE_NAME واختصارًا FQIN، ألقِ نظرةً على الأمرين التاليين: # باستخدام اسم الصورة المؤهل تمامًا podman pull docker.io/library/debian # بدون اسم الصورة المؤهل تمامًا podman pull debian كما تلاحظ، في اسم الصورة المؤهل بالكامل، يكون التنسيق على النحو التالي: السجل/اسم المستخدم/اسم الصورة. في مثالنا فإن docker.io هو عنوان سجل دوكر hub.docker.com. لسحب وسم tag محدد، اكتب اسم الوسم بعد اسم الصورة، مسبوقًا بنقطتين (:). إليك مثالًا عن سحب الوسم stable-slim لصورة ديبيان: podman pull docker.io/library/debian:stable-slim عرض الصور المتاحة بعد سحب صورة أو أكثر، يمكنك معاينة الصور المتوفرة محليًا باستخدام الأمر podman Images. عند سحب صورة debian:stable-slim، ستحصل على الخرج التالي: $ podman images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/library/debian stable-slim 86f9b934c377 2 days ago 77.8 MB والآن بعد أن حصلت على الصورة يمكنك إنشاء حاوية جديدة إنشاء حاوية جديدة لإنشاء حاوية جديدة في بودمان، عليك استخدام الأمر podman run بالطريقة التالية: podman run [OPTIONS] image [COMMAND [ARGS]] والآن، سنضيف بعض الخيارات options على الأمر السابق، سنضيف أولًا الخيار d- لتشغيل الحاوية باستمرار في الخلفية، والخيار t- لتخصيص طرفية زائفة pseudo-TTY لصورة ديبيان كي تعمل باستمرار. يمكنك الاطلاع على قائمة الخيارات المتاحة من توثيقات بودمان. والآن، سننشئ حاوية بسيطة تعتمد على صورة توزيعة ديبيان stable-slim التي سحبناها مسبقًا. podman run -d -t debian:stable-slim عند نجاح إنشاء الحاوية، ستحصل في الخرج output على سلسلة عشوائية من الأحرف والأرقام. هذه السلسلة هي معرف الحاوية الفريد unique container ID. 61d1b10b5818f397c6fd8f1fc542a83810d21f81825bbfb9603b7d99f6322845 عرض الحاويات أولًا، لعرض الحاويات قيد التشغيل، عليك استخدم الأمر podman ps، وهو يشبه الأمر ps في لينكس، لكن بدلاً من إظهار عمليات النظام، فإنه يظهر الحاويات قيد التشغيل وتفاصيلها. بما أننا استخدمنا الخيار t- لتشغيل حاوية دبيان، فلنرَ كيف تبدو نتيجة الأمر podman ps: $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 61d1b10b5818 docker.io/library/debian:stable-slim bash 44 seconds ago Up 44 seconds ago gallant_mahavira يمكنك الحصول على معلومات عن الحاوية باستخدام الأمر ps كمعرّف الحاوية الفريد القصير، والصورة المستخدمة لإنشاء هذه الحاوية، ومتى أُنشِئت الحاوية، ومنافذ الجهاز المضيف المسندة إلى منافذ الحاوية واسمها. ونلاحظ من الخرج أن الصورة المستخدمة هي debian:stable-slim أُنشِئت قبل 44 ثانية، أما اسم الحاوية فهو gallant_mahavira. يمكنك تسمية الحاوية عند إنشائها باستخدام الخيار name CONTAINER_NAME--، فعندما لا تحدد اسم الحاوية، يُولَد اسم عشوائي لها. ثانيًا، لعرض الحاويات المتوقفة عن العمل Stopped containers عليك استخدام الأمر التالي: podman container list -a والآن، سنتعلم كيفية إيقاف الحاويات. إيقاف الحاويات لإيقاف الحاويات عليك استخدام الأمر podman stop مع معرّف الحاوية أو اسمها، وذلك وفق الصيغة التالية: podman stop [CONTAINER_NAME|CONTAINER_ID] والآن سنوقف الحاوية الجارية باستخدام اسمها: $ podman stop gallant_mahavira gallant_mahavira والآن بإمكانك استخدام الأمر السابق لعرض جميع الحاويات الجارية والمتوقفة: $ podman container list -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 61d1b10b5818 docker.io/library/debian:stable-slim bash 14 minutes ago Exited (137) 3 minutes ago gallant_mahavira ملاحظة: ترتبط كل من الأوامر podman container list and podman container ls، podman ps، podman container ps بنفس الملف الثنائي binary ولها نفس الاستخدام وتعطي نفس الخرج. إعادة تشغيل الحاوية لإعادة تشغيل حاوية ما بعد إيقاف عملها أو فشله، عليك استخدام الأمر podman start. فلنفترض أن الحاوية التي أنشأتها من صورة ديبيان فشلت لسبب ما، إذًا يمكنك إعادة تشغيلها عن طريق كتابة اسمها أو معرّفها بعد الأمر podman start كالتالي: $ podman start 61d1b10b5818f397c6fd8f1fc542a83810d21f81825bbfb9603b7d99f6322845 حذف الحاويات قبل حذف حاوية أو تدميرها عليك أولًا إيقافها، وبعدها يمكنك استخدام الأمر podman rm لحذفها. بمجرد حذف الحاوية، فإنها ستختفي ولن تظهر في خرج الأمر podman Container list -a. إليك المثال التالي على إيقاف وحذف حاوية باستخدام بودمان، والذي استخدمنا فيه اسم الحاوية ومعرفها. $ podman ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 61d1b10b5818 docker.io/library/debian:stable-slim bash 44 minutes ago Up 1 second ago gallant_mahavira $ podman stop gallant_mahavira gallant_mahavira $ podman rm 61d1b10b5818 61d1b10b5818f397c6fd8f1fc542a83810d21f81825bbfb9603b7d99f6322845 $ podman container list -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES كما ترى فإن الحاوية اختفت تمامًا. يمكنك الآن إن أردت، إنشاء حاوية جديدة باستخدام أي صورة وفق الأوامر الخطوات التي تعلمتها. الخاتمة تهانينا، لقد وصلت إلى نهاية المقال الثالث في سلسلتنا التعليمية حول أداة بودمان، وتعلمت كيفية إنشاء الحاويات وعرضها وإيقافها وحذفها، تابع قراءة باقي المقالات كي تتعلم المزيد حول بودمان. ترجمة -وبتصرف- للمقال Creating and Destroying Containers Using Podman من موقع Linux Handbook. اقرأ أيضًا المقال السابق: الفرق بين أداتي دوكر Docker وبودمان Podman مدخل إلى حاويات لينكس LXC ما هي صورة الحاوية container image؟ نظرة عامّة على إعداد الحاويات containerization على Docker
-
إن أداة بودمان Podman هي أداة مقدمة ومدعومة من قبل توزيعة ريد هات Red Hat كبديل عن أداة دوكر Docker. فأداة بودمان شبيهةً بدوكر ويمكنك بدء استخدامها إن كنت على معرفة بدوكر. عندما نأتي على ذكر الحاويات، ستخطر الأداة دوكر Docker في ذهنك، لكنها ليست الأداة الوحيدة للتعامل مع الحاويات. إذ ستجد أن أداة بودمان المقدمة من ريد هات أداة واعدة وتلبي احتياجاتك وليس عليك تعلم كيفية التعامل معها من الصفر، لأنها مشابهة لدوكر. تهدف هذه السلسلة إلى تعريفك على أداة بودمان، كي تستطيع عند نهاية هذه المقالات، التعرف على الفرق بين دوكر وبودمان، وبدء استخدام بودمان عند العمل مع الحاويات. ما ستتعلمه سلسلة التعرف على أداة بودمان Podman سنتعلم في هذه السلسلة ما يلي: الفرق بين أداتي دوكر وبودمان. إنشاء الحاويات وحذفها باستخدام أداة بودمان. تفعيل حاويات بودمان تلقائيًا عند إقلاع النظام. تحديث الحاويات. مفهوم الحاويات محدودة الصلاحية Rootless containers. مفهوم بودمان كومبوز Podman Compose. متطلبات هذه السلسلة معرفة مسبقة بمفهوم الحاويات Containers. تجربة مسبقة في التعامل مع دوكر. خبرة في التعامل مع سطر الأوامر أو الطرفية Terminal في لينكس Linux. سنناقش في مقال اليوم الفرق بين أداتي دوكر وبودمان بالتفصيل، حيث يترافق مصطلح الحاويات Containers في ذهننا مع أداة دوكر Docker، لكن دعونا نتعرف في مقالنا على الفرق بينها وبين أداة بودمان Podman التي ازداد استخدامها مع الحاويات. ومع انتشار استخدام الحاويات أصبحت أداة دوكر، التي ظهرت في عام 2014، أشهر أداة لإدارة الحاويات. ونشرت شركة ريد هات Red Hat في عام 2018، أداة بودمان كبديل عن دوكر. وبما أن الأداتين لهما الغرض نفسه، سنتعرف في هذا المقال على مزايا كل منهما. مفهوم الحاويات لنفترض أنك تعمل كمهندس برمجيات وطُلِب منك نشر مجموعة برامج ذات مهام حرجة. ماذا ستفعل لو كان البرنامج الأول والبرنامج الثاني لهما نفس الاعتمادية dependency ولكنهما يعملان على إصدارات مختلفة من نفس الاعتمادية؟ أو لو كانت تبعية البرنامج الأول تتعارض مع الاعتمادية البرنامج الثاني؟ في هذه الحال عليك نشرهما في جهازين افتراضيين Virtual Machine مختلفين، لكن هذا يلغي قابلية التوسع scalability، لأنه عند تشغيل جهازين افتراضيين على نفس الجهاز، سيرث البرنامج 50% فقط من إجمالي قدرة الجهاز الحاسوبية. وعند زيادة عدد البرامج من برنامجين إلى عشرة سيتضح لك أن هذا الحل غير فعّال. حيث إن إحدى مساوئ الآلات الافتراضية هي أنها تعمل بنظام تشغيل كامل، وهذا يُعد أمرًا سلبيًا في حالتنا. فلو كان عندنا عشرة أجهزة افتراضية تعمل بنظام تشغيل ريد هات RHEL، سيصبح عندنا عشر نسخ من نفس الثنائيات binaries، وسيؤدي ذلك إلى استهلاك غير فعّال لذاكرة الوصول العشوائي RAM. حتى إن أبسط عملية تثبيت installation ستحجز أكثر من 4 جيجابايت من مساحة القرص لكل جهاز افتراضي. لذلك بدلًا من استخدام جهاز افتراضي، حيث يكون لديك نظام تشغيل كامل على الجهاز بالإضافة إلى برنامجك واعتمادياته، يمكنك استخدام صورة الحاوية container image. إذ تحتوي صور الحاوية على البرنامج واعتمادياته فقط. ومن مزايا صور الحاويات أن حجمها يكون عادةً أقل من 300 ميجابايت. فالمشكلة تكمن في طبيعة عمل الآلات الافتراضية؛ فعندما تنشئ آلةً افتراضية، تُنشَأ نسخة افتراضية من العتاد hardware. أي نسخة افتراضية من وحدة المعالجة المركزية وذاكرة الوصول العشوائي، وذاكرة التخزين والموارد الأخرى، ولا بد أن لهذا حمل على الجهاز. أما عند استخدام الحاويات، تُنشَأ نسخ من البرنامج مع اعتماديّاته، وهذا له حمل منخفض مقارنةً بالآلات الافتراضية. الغرض من استخدام دوكر أو بودمان ربما استخدمت برنامج فيرتشوال بوكس VirtualBox المُقدَّم من أوراكل Oracle لإدارة الآلات الافتراضية، والذي يُتيح لك إنشاء آلات افتراضية وتشغيلها أو إيقافها، وتعديلها، وحذفها. تُتيح كل من أداتي دوكر وبودمان ذلك، ولكنها تتعامل مع البرامج الموجودة في حاويات، وليس الآلات الافتراضية. وعلى الرغم من أن كِلا الأداتين تعملان وفق فلسفتين مختلفين، إلا أن كلتاهما تساعدان على إدارة الحاويات. لذلك سنتعرف الفروق بينهما وأي منهما هو الأفضل وفقًا لغرض الاستخدام الذي تريده. دوكر أم بودمان يُعد كل من دوكر و بودمان من البرامج الممتازة لإدارة الحاويات. وعندما أعلنت شركة ريد هات عن طرحها لبودمان كبديل عن دوكر قالت إن بودمان متوافق مع واجهة سطر أوامر دوكر، أي إن الانتقال من دوكر إلى بودمان لا يتطلب تغييرات كبيرة على الشيفرة البرمجية. هذا يعني أنه يمكنك استبدال أمر docker بالأمر podman وسيعمل البرنامج. ولكن ثمة بعض الاختلافات الأساسية، التي سنتعرف عليها: أولًا، مفهوم البرنامج الخفي Daemon إن الفرق الرئيسي الذي يميز بين أداتي دوكر وبودمان هو طريقة عملهما على نظام التشغيل. حيث تعمل نواة دوكر Docker core كبرنامج خفي dockerd، أي إنه يعمل دائمًا في الخلفية ويدير الحاويات. أما أداة بودمان فتشبه البرنامج العادي؛ أي إنه يبدأ العمل عند تنفيذ إجراء ما فيه (بدء أو إيقاف حاوية). تتميز طريقة عمل دوكر المعتمدة على البرنامج الخفي Daemon-based approach بما يلي: يتيح تشغيل الحاويات تلقائيًا وبسهولة عند تشغيل النظام. لا حاجة إلى مدير خدمة خارجي مثل systemd نظرًا لأن دوكر هو برنامج خفي. لكن هذا لا يعني أن أداة بودمان سيئة، إليك المزايا التي تتميز بها أداة بودمان عن دوكر: عند تعطل برنامج دوكر الخفي، فستكون حالة الحاويات غير معروفة. لكن يمكن تجنب ذلك عند استخدام أداة بودمان. يمكنك استخدام systemd لإدارة الحاويات، إذ يمنحك ذلك قدرة غير محدودة على ضبط وإدارة الحاويات مقارنةً بدوكر. يتيح ربط بودمان مع systemd تحديث الحاويات قيد التشغيل بأقل وقت توقف عن العمل downtime. كما يمكنك تلافي التحديثات السيئة. ثانيًا، الأمان Security إن أهم سبب لاستخدام بودمان بدلًا من دوكر هو الأمان، إذ طُرح بودمان كبديل أكثر آمنًا من دوكر. فإذا كنتَ مهتمًا بالأمان، فستجذبك اثنتان من ميزات بودمان الأساسية. ذكرنا آنفًا أن ما يميز بودمان عن دوكر هو أن بودمان لا يعمل كبرنامج خفي. أما الميزة الأساسية الثانية لبودمان هي أنه يمكنه تشغيل الحاويات دون صلاحيات الوصول إلى الجذر root. هذا يعني أنك لست بحاجة إلى امتيازات المستخدم المميز superuser لإدارة الحاويات. والآن، إليك ثلاثة أسباب تجعلك تفضل استخدام بودمان بدلًا عن دوكر إن كنت مهتمًا بالحصول على مستوى أعلى من الأمن. السبب الأول، يعمل الأمر dockerd كمستخدم جذر كما تعلم فإن نواة دوكر تعمل كبرنامج نظام خفي system daemon، أي كبرنامج ينفذه المستخدم المسؤول أو الجذر root user. سبق وذكرنا فوائد البرنامج الخفي، لكن ثمة بعض المشاكل الأمنية عند تشغيل البرنامج الخفي كمستخدم جذري. أولًا، إذا اختُرق برنامج دوكر الخفي (dockerd)، فيمكن لأحدهم أن يخترق نظامك من خلال الوصول إلى الجذر. ولا شك أنك لا تود حدوث ذلك. وهنا تتضح ميّزة بودمان إذ إنه لا يستخدم برنامجًا خفيًا وليس له متطلبات صارمة للوصول إلى الجذر. وهذا يقودنا إلى السبب الثاني. السبب الثاني، يدعم بودمان الحاويات دون صلاحيات جذر ربما سمعت أن بودمان يدعم تشغيل الحاويات دون الوصول إلى الجذر أو ما يعرف Root-less containers، وهذا أمر صحيح وأكثر أمنًا. والآن، لنفترض أن برنامج دوكر الخفي آمن، وأن صورة الحاوية التي تستخدمها فيها ثغرة أمنية. ولكن المطور لا يعرف ذلك. إذا شَغّلتَ هذه الصورة في حاوية تابعة للمستخدم الجذر، فاعلم أن الحظ ليس حليفك. أما عند استخدام بودمان، فيمكنك تشغيل الحاوية دون الحاجة إلى امتيازات الجذر. هذا يعني أنه إن احتوت صورة الحاوية على ثغرة أمنية، فلن يتعرض للخطر سوى المستخدم الذي يملك تلك الحاوية. أما بقية مستخدمي النظام فهم بأمان، ولا سيما المستخدم الجذر. وعلى الرغم من أن دوكر حصل مؤخرًا على دعم لتشغيل الحاويات محدودة الصلاحية Rootless containers ، لكن لا يزال ينقصه بعض الميزات، وهي أن دعم AppArmor غير موجود. وهو نظام التحكم الإلزامي بالوصول (MAC) الافتراضي الخاص بتوزيعتي ديبيان وأوبنتو السبب الثالث، تحديث الصور تلقائيًا قد يخطر في ذهنك أن تحديث الصور تلقائيًا لا يمكن أن يكون ميزة، لكنها كذلك. تذكر السبب الثاني الذي ذكرناه وافترض أن المطورين يعلمون بوجود الثغرة الأمنية، ثم أصدروا إعلانًا بذلك ونشروا الصورة المصححة. لكن ميزة التحديث التلقائي ليست مدمجة built in في دوكر، فماذا عن بودمان؟ يعتمد الجواب على كيفية تعريفنا لكلمة "مدمجة". نظرًا لأنه ليس لبودمان برنامج خفي، فإنه لا يمكنه إجراء فحوصات منتظمة للحصول على التحديثات. لكن بما أن بودمان هو أحد منتجات ريد هات Red Hat، فيمكن تحديث الحاويات تلقائيًا عن طريق systemd لأنه يتوافق معه، وهذا ما سنتحدث عنه في مقالنا التالي من هذه السلسلة. ملاحظة: لا تعني الأسباب التي ذكرناها أن دوكر غير آمن وأنه يجب على الجميع استخدام بودمان، إذ لا يوجد شيء آمن بنسبة 100%. لكن وجب تسليط الضوء عليها من باب الاحتياط وأخذ الحذر. ثالثًا، النهج المتبع في بودمان ربما لاحظت أن دوكر يتّبِع نهج "الحل الواحد" وأن بودمان يتّبع نهجًا مختلفًا. وهذا يعني أنه ليس عليك سوى تثبيت الملف الثنائي binary لدوكر على نظامك. ويمكنك استخدام الأمر docker لإنشاء الصور ونشرها (إلى السجلات مثل سجل hub.docker.com) وإدارة الحاويات. ولكن بالنسبة لبودمان، نشرت شركة ريد هات Red Hat ثلاثة ثنائيات منفصلة. فعليك استخدام الأمر buildah لبناء الصور. ولنشرها على سجل مثل سجل hub.docker.com، فعليك استخدام الأمر skopeo. ولإدارة الحاويات، فاستخدم الأمر podman. كلا النهجين يؤدي الغرض المرجو منه، إذًا فالأمر يعتمد على ما تفضّله، هل تفضّل استخدام نهج الحل الشامل الذي يقدمه دوكر أم تفضل نهج الحل المتشعب لبودمان. رابعًا، أداة دوكر سوارم Docker Swarm تُعدّ أداة دوكر سوارم Docker Swarm مفيدةً لتوسيع نطاق الحاويات باستخدام عدة أجهزة حقيقية وافتراضية. إذ يمكنك وضع عدة حواسيب ضمن "سرب" أو swarm من أجل غرض محدد. فيمكن أن تخصص سربًا للتعامل مع طلبات قاعدة البيانات فقط، وسربًا آخر للتعامل مع خادم ويب. في حين أن هذه الميزة غير متوفرة في بودمان، إلا أنه يمكنك الاستفادة منها باستخدام Kubernetes. ويمكننا القول إن Kubernetes يستخدم على نطاق أوسع من Docker Swarm، وعند الحاجة إلى التوسع واستخدام عدة أجهزة، فإن Kubernetes يلبي احتياجاتك على أفضل وجه. الخاتمة تُعد أداة دوكر مرادفةً للحاويات. لكن أنشأت شركة ريد هات Red Hat أداة بودمان لإدارة الحاويات للتغلب على بعض أوجه القصور في عمل دوكر. وتوافق بودمان مع أوامر دوكر يُسهل التوجه نحو استخدامها دون الحاجة إلى ترك ما تعلمته عن دوكر. لا يعني ذلك أن المسؤولين عن أداة دوكر لا يعملون على تحسينها، إذ إن إضافة ميزة الحاويات محدودة الصلاحية rootless containers هي خير دليل على ذلك. والآن فإن الخيار متروك لك في استخدام الأداة التي تفضلها، وللتعرف على المزيد حول أداة بودمان، تابع مقالنا التالي. ترجمة وبتصرّف للمقال Understanding the Differences Between Podman and Docker من سلسلة Container Management With Podman. اقرأ أيضًا مدخل إلى دوكر Docker ما الفرق بين دوكر Docker وكوبيرنيتيس Kubernetes؟ كيفية تأمين الحاويات عن طريق سي لينكس SELinux نظام كوبيرنتس Kubernetes وكيفية عمله
-
تتطلع الشركات في وقتنا الحالي إلى العمل بأسلوب ذي وتيرة إنجاز سريع والتركيز على جعل التحديثات "مملة"، لأنها أصبحت بسيطةً ومتوقعة، وهذه هي الخصائص الأساسية لنشر البرامج بصورة مستمرة وبثقة والتعامل مع التحديثات على أنها نشاط اعتيادي. تحدث كل من (دايفيد فارلي) و(جيز هامبل) في عام 2010 في كتابهما التسليم المستمر (Continuous Delivery) عن التصدير المستمر للبرمجيات، إذ ستجد في كتابهما عدة ممارسات لا تزال صالحة في يومنا هذا. إذًا، فالتسليم المستمر Continuous Delivery ليس مفهومًا جديدًا، لكن العديد من المؤسسات لا تزال لا تجيد تطبيقه. ستجد في هذا المقال مفاهيمًا تساعدك على فهم مبدأ النشر المستمر ونصائح لكيفية تطبيق ممارسات عملية لتحسين تقييمات العملاء التي تحصل عليها بعد كل إصدار. ما هو النشر المستمر CD الغرض من النشر هو استخدامه كطريقة للحصول على آراء العملاء، إذ ستحصد أكبر قدر ممكن من تعليقات العملاء عند كل نشر. لكن، للحصول على تعليقات قيّمة، يجب أن تأخذها من مستخدمي برامجك. ولذلك، تحتاج إلى إصدار التحديثات في بيئة الإنتاج production environment. وهذا هو جوهرالنشر المستمر Continuous Deployment أي نشر التعليمات البرمجية في بيئة الإنتاج بصورة آمنة ومستمرة وآلية ومؤتمتة دون الحاجة لإجراء أي تحقق يدوي. ملاحظة: بيئة الانتاج هي مكان نشر التطبيق وجعله متاحًا للمستخدمين، كمثال عليها Play Store أو الموقع الخاص بشركة ما بحيث ترفع تطبيقها عليه على سبيل المثال. قد يخطر في ذهنك أن هذا المفهوم غير مُستَخدَم على أرض الواقع وأنه مفهوم نظري وحسب، لكن تطبق الشركات الكبرى كشركة نتفليكس Netflix وايتسي Etsy وتسلا Tesla مفهوم النشر المستمر لنشر التحديثات البرمجية لتطبيقاتها المختلفة، فعند نشر التحديثات البرمجية تحصل الشركات على آراء المستخدمين بعد الاستخدام الفعلي، وتترجمها إلى خدمات أو تستخدمها لتطوير منتجاتها. وهذا هو الفرق الأساسي بين التسليم المستمر Continuous Delivery والنشر المستمر Continuous Deployment. ما الفرق بين النشر المستمر والتسليم المستمر إن النشر المستمر والتسليم المستمر هما أساس DevOps لكن الاعتقاد أن النشر المستمر هو نفس التسليم المستمر هو خطأ شائع، إذ إنه ثمة فرق بينهما يتعلق بوقت نشر التحديث. فالتسليم المستمر هو القدرة على تجهيز التحديثات البرمجية بحيث تكون جاهزة للإصدار. أي أن التحديثات مرت في أنابيب تجزئة تنفيذ التعليمات ونجحت في جميع الاختبارات، وليس هناك حاجة للعمل عليها. إذًا، أصبحت التحديثات البرمجية مؤهلة للإصدار. أما النشر المستمر فهو استراتيجية إصدار أو نشر تُستخدم في النشر المستمر Continuous Delivery، إن كان التحديث جاهزًا للنشر فيُدفع إلى بيئة الإنتاج تلقائيًا، أي يُصدر. فلا يمكن تطبيق النشر المستمر دون تطبيق التسليم المستمر، وبالتالي فإن التسليم المستمر هو الخطوة الأولى لإصدار التحديثات آليًّا وبسرعة وأمان وبطريقة "مملة" تحتاج إلى تنفيذ بعض الآليات المهمة بدءًا من التكامل المستمر. وللتعرف على المزيد من المعلومات حول أبرز الفروقات بين النشر المستمر والتسليم المستمر ننصحك بمشاهدة الفيديو التالي: ما سبب أهمية التكامل المستمر يُعد التكامل المستمر إحدى الممارسات المهمة لبناء خط تجزئة يصَدّر البرمجيات آليًّا مع التركيز على الجودة. توجد ثلاث قواعد أساسية للتكامل المستمر: يبنى البرنامج من فرع واحد من مجلد الشيفرة البرمجية code repository. يستخدم خط التجزئة مجموعة اختبارات مؤتمتة وموثوقة. إذا فشل بناء البرنامج، تتوقف عملية التكامل وتُلغى التعديلات. وبهذه الطريقة، تحرص على أن جميع التعديلات مؤهلة للإصدار، حتى لو أجلت الإصدار إلى وقت آخر أو منصة آخرى. لكن القاعدة الأهم هي إجراء اختبارات مؤتمتة موثوق بها. كما ستحتاج إلى إجراء اختبارات سريعة وتعمل بالتوازي، واختبارات لجميع السيناريوهات المهمة في تطبيقك، مثل اختبار المسار السعيد happy path test، واختبار للبيانات التي عطلت الإنتاج سابقًا، واختبار إدخال بيانات غير صحيحة. لا تحتاج إلى الحصول على درجة تغطية الشيفرة code coverage بنسبة 100%، ولكن يجب عليك زيادة عدد الاختبارات التي تجريها تدريجيًا قبل الإعلان عن جاهزية التعديلات البرمجية. لن تجري الأمور بسلاسة دائمًا كما خططت، وهذا أمر متوقع. ولهذا يجب أن تكون لديك القدرة على حل المشكلات فورًا. لا تترك خط التجزئة معطوبًا أبدًا. فالهدف هو ترك مسار متوفر في حال احتجت إلى إجراء تغيير طارئ، والاستمرار في استخدام خط التجزئة المؤتمت الذي أنشأته. وبطبيعة الحال، لن تصل إلى هذه النقطة بين عشية وضحاها، لذلك يجب أن تتبنى عقلية التحسين المستمر كي تنجح. والآن سنتعمق أكثر في كيفية تطبيق النشر المستمر. كيفية تطبيق النشر المستمر الخطوة الأولى، هي التدرب على أجزاء صغيرة من العمل، لا تنتظر حتى تجمّع تعديلات كافيةً أو مهمةً كي تنشر تحديثًا في بيئة الإنتاج. فكلما كانت التعديلات صغيرة، كان اختبارها ونشرها أسهل وأسرع. وتستطيع بهذه الطريقة التدرب مرارًا حتى تصل إلى نقطة يكون فيها وضع التعديلات مستقرًا. كما أن استخدام الأدوات هو أمر مهم، لذلك يجب أن تستخدم أدوات تساعدك في بناء، واختبار، وتحزيم، ونشر، وإصدار البرامج بصورة آليّة. إن إدارة الميزات Feature Management تُعد مفيدة للغاية، إذ يمكنك أن تفعّل التحديثات البرمجية للعملاء بنقرة واحدة. وبهذه الطريقة، تجعل الشيفرة البرمجية جاهزة للإصدار حتى لو لم تكن مكتملة. إذ يمكنك تفعيل ميزة ما لكي تختبرها، أو تفعيلها في جزء معين من الشيفرة لإجراء اختبارات ألف/باء أو A/B tests وأي اختبار آخر. فكل ذلك متاح بالإضافة إلى الحصول على آراء العملاء القيمة فورًا، وإنتاج برامج أفضل مع كل إصدار. لكن يجب أن تطبق النشر المستمر لغرض واضح مثل الابتكار، أو تحسين جودة البرامج، أو إصدار الميزات في الوقت المناسب. حتى إن وُجِدت قيود لا تسمح لك بتطبيق النشر المستمر، فإن الاستعداد لذلك سيساعدك على تقليل الوقت والجهد اللازمين لكل إصدار. الخاتمة لنلخص ما ورد في مقالنا، النشر المستمر هو القدرة على إصدار التحديثات البرمجية آليًّا دون أي تدخل بشري. تحتاج لتطبيق ذلك إلى الاعتماد على مجموعة اختبارات مُحكمَة الإعداد لتلافي حدوث الأخطاء، كما أن تقسيم التغييرات الكبيرة إلى تغييرات أصغر يسمح لك بالتدرب أكثر وتقليل احتمالات ظهور الأخطاء (كما يسهل التراجع عن عن هذه التغييرات الصغيرة). لا يمكنك تطبيق النشر المستمر بين عشية وضحاها، إذ إنه ثمة سلسلة من الخطوات التي عليك اتباعها أولاً. وترتيب هذه الخطوات هو كالتالي: التكامل المستمر، ثم التسليم المستمر، ثم النشر المستمر. كما يمكنك التدرب في بيئة التطوير أو الاختبار، وليس ضروريًا أن تبدأ في بيئة الإنتاج، ولكن عليك أن تحدد ما تريد إنجازه، مثلًا هل تريد تحقيق وقت تسويق قصير Time To Market، أم تريد تحقيق مدة توريد Lead Time قصيرة، أم تريد إجراء المزيد من التجارب. يمكنك اعتماد فحص يدوي أخير إذا كنت تحتاج إلى ذلك (على سبيل المثال، للتحقق من التوافق، أو التحقق من متاجر تطبيقات الأجهزة المحمولة، أو الأجهزة الطبية)، ولكن هذا يُعد تسليمًا مستمرًا، ولا بأس في ذلك. إذ يمكن تطبيق الممارسات والأدوات المذكورة في مقالنا، بغض النظر عن مجال عملك أو كميته. وإذا كان لديك من الاستفسارات حول ما ورد في مقالنا، أو أردت الحصول على الدعم والمساعدة أضف سؤالك في قسم التعليقات أسفل المقال، أو اكتبه في قسم الأسئلة والأجوبة في أكاديمية حسوب. ترجمة -وبتصرف- للمقال What Is Continuous Deployment? A Complete Explanation من موقع Cloudbees. اقرأ أيضًا مدخل إلى التكامل المستمر والنشر المستمر CI/CD أفضل ممارسات منهج التكامل المستمر والتسليم المستمر CI/CD إعداد التكامل المستمر والنشر المستمر باستخدام الخدمتين CircleCI وCoveralls التكامل المستمر: تثبيت Concourse CI على أوبنتو محاكاة عقلية DevOps
-
تعد الصور ذات الصيغ التالية JPG و PNG و GIF إحدى أكثر صيغ الصور الشائعة منذ التسعينات. لكن، بخلاف صور JPG و PNG، فإن صور GIF تحتوى على إطارات متعددة من الرسوم المتحركة، وهي منتشرة انتشارًا واسعًا في شبكة الإنترنت. تعد صور GIF أو نسق الرسومات المتبادلة تقنيةً قديمةً وقد أصبحت أقل فاعلية من تضمين مقاطع الفيديو الويب، لأن معظم فيديوهات الويب تستخدم تقنيات ضغط حديثة وبرامج ترميز Codecs أحدث من المستخدمة في الصور المتحركة GIF. تُستخدم برامج الترميز Codecs (أو المرمازات) لترميز مقاطع الفيديو وفك ترميزها، وتحتوي معظم المنصات على عتاديات مخصصة لتشغيل برامج الترميز هذه. أما ملفات GIF، يُفَك ترميزها مباشرةً باستخدام وحدة المعالجة المركزية CPU، حيث إن حمل وحدة المعالجة المركزية اللازم لمعالجة ملف GIF منخفض الدقة ذو إطارات متحركة قليلة لا يكاد يذكر، ولكن يمكنك من الناحية الفنية إنشاء ملف GIF بدقة ومعدل إطارات مماثل لمقاطع فيديوهات YouTube، وسوف تتفاجأ بعدد موارد النظام التي يستهلكها ذلك. وعلى الرغم من ذلك، لا تزال ملفات GIF مفيدة لأنها تُعد صورًا وليست مقاطع فيديو، ونظرًا لطريقة عمل الويب والتطبيقات الأخرى، فهذا يعني أنها ستُعرض وتحرك تلقائيًا في عدة تطبيقات، ولن تحتاج إلى تضمينها أو ربطها على نحو منفصل. ويُعد استخدام صور GIF مفيدًا في صور التفاعل، أو لتطوير الخيال التفاعلي، أو في تنسيقات العروض الأخرى. سنتعرف في هذا المقال على عدة أدوات لإنشاء الصور المتحركة GIF من مقاطع الفيديو، وعلى كيفية تحسين حجمها ودقتها، وطريقة استخدامها في عدة مجالات. كما يمكنك دمج هذه الأدوات واستخدامها في حزمة تطبيقات أخرى. المتطلبات سنزودك في هذا المقال بإرشادات تثبيت خادم أوبنتو 22.4، يمكنك الاستعانة بالمقال التالي لتثبيته. كما ستحتاج إلى تثبيت مدير الحزم Homebrew لتثبيت إحدى الأدوات التي سنتحدث عنها في مقالنا. الخطوة الأولى: تثبيت الأدوات ffmpeg وGifski وGifsicle ستحتاج إلى ثلاثة أدوات كي تستطيع متابعة خطوات هذا المقال. أول أداة ستحتاجها هي ffmpeg التي سنستخدمها لقص الفيديو والتعديل عليه، ثم سنستخدم Gifski لإنشاء صور GIF، و Gifsicle لتحسين الصور والتعديل عليها. ستجد هذه الأدوات متاحة في أغلب المنصات. كلا الأداتان ffmpeg و gifsicle متاحتان في مستودعات أوبنتو، ويمكنك تنزيلها باستخدام مدير الحزم apt. أولًا، حَدّث الحزم باستخدام الأمر apt update: sudo apt update ثم ثبت حزمتي ffmpeg و gifsicle باستخدام الأمر apt install: sudo apt install ffmpeg gifsicle أما الأداة الثالثة gifski فهي متاحة بواسطة Homebrew ويمكنك تثبيتها بواسطة الأمر brew install: brew install gifski قد يستغرق ذلك بضع دقائق لأن Homebrew سيثبت بعض الاعتماديات dependencies. والآن، بعد أن ثبّت جميع الأدوات اللازمة على جهازك، عليك اختيار فيديو لإنشاء صورة GIF منه. الخطوة الثانية: تنزيل وفحص ملف الفيديو بإمكانك إنشاء صورة GIF من أي مقطع فيديو على جهازك، أو يمكنك استخدام الفيديو التعريفي بمنصة تطبيقات DigitalOcean. لتنزيل نسخة من الفيديو من باستخدم الأمر curl: curl -O https://deved-images.nyc3.digitaloceanspaces.com/gif-cli/app-platform.webm curl هي إحدى أدوات سطر الأوامر تخولك من إنشاء مختلف طلبات الويب web request، مثلًا عند استخدام الراية -o مع عنوان URL فهذا يوّجه curl إلى تنزيل ملف من الإنترنت وتخزينه على جهازك بنفس الاسم. والآن، بعد أن أصبح عندك نسخةً من الفيديو على جهازك، بإمكانك التحقق من بياناته الوصفية metadata لأن ذلك مفيد عند إنشاء صورة GIF ذات جودة عالية. بعد تثبيت الأداة ffmpeg يمكنك استخدام الأمر ffprobe الذي يسمح لك التحقق من الدقة resolution، ومعدل الإطارات framerate، والمعلومات الأخرى في ملفات الوسائط. استعرض هذه المعلومات باستخدام الأمر ffprobe على الفيديو app-platform.webm الذي نزلته: ffprobe app-platform.webm ستحصل على الخرج التالي: Output … Input #0, matroska,webm, from 'app-platform.webm': Metadata: ENCODER : Lavf59.27.100 Duration: 00:01:59.04, start: -0.007000, bitrate: 1362 kb/s Stream #0:0(eng): Video: vp9 (Profile 0), yuv420p(tv, bt709), 1920x1080, SAR 1:1 DAR 16:9, 25 fps, 25 tbr, 1k tbn (default) Metadata: DURATION : 00:01:59.000000000 Stream #0:1(eng): Audio: opus, 48000 Hz, stereo, fltp (default) Metadata: DURATION : 00:01:59.041000000 يعرض الخرج التدفقات Streams الموجودة في الملف (عادةً فيديو واحد ودفق صوتي واحد على الأقل)، بالإضافة إلى معدل العينات sample rate، وبرامج الترميز Codecs، والخصائص الأخرى للتدفقات. لاحظ أن المعلومات المظللة في الخرج تدلنا أن الفيديو مرمز بدقة 1080 بكسل، ويُشَغل بمعدل 25 إطارًا في الثانية، كما أن طوله دقيقتين تقريبًا، وهو طويل جدًا بالنسبة لصورة GIF واحدة! أصبح عندنا المعلومات الكافية للانتقال إلى الخطوة التالية حيث سنقص مقطعًا من هذا الفيديو لإنشاء صورة GIF منه. الخطوة الثالثة، قص مقطع من الفيديو الآن أصبح لديك مقطع فيديو مدته دقيقتان وأصبحت تعرف خصائصه. قبل تحويله إلى صورة GIF عليك تقصير الفيديو،. ولا يُستحسن تشغيل مقطع الفيديو في الطرفية، لذا شاهد الفيديو على YouTube لتختار المقطع الذي تريده. اخترنا في مقالنا المقطع من الثانية 00:00:09 إلى الثانية 00:00:12، مما ينتج لدينا مقطعًا متحركًا سلسًا على النحو التالي: يمكنك قص الفيديو app-platform.webm باستخدام الأداة ffmpeg كالتالي: ffmpeg -ss 00:00:09 -to 00:00:12 -i app-platform.webm -c copy clip.webm إليك الشرح التفصيلي للأمر السابق: يعبر الجزء الأول -ss 00:00:09 -to 00:00:12 عن كيفية فهم ffmpeg للشيفرة الزمنية، من نقطة البدء إلى نقطة النهاية. كما يمكنك القص اعتمادًا على المدة أو أجزاء من الثانية. الجزء -i app-platform.webm هو مسار الفيديو مسبوقًا بـ -i. نحدد بعد الجزء -c copy مرماز فيديو الخرج أو الصوت للأداة ffmpeg، واستخدمنا للأمر copy بدلًا عن برنامج ترميز كي نحصل على الفيديو الجديد بسرعة، وبدون ترميز، ولنتفادى انخفاض دقة الفيديو. وبما أننا سننشأ صورة GIF فلا بأس إن حافظنا على نفس الصيغة في ملف الخرج لتوفير الوقت، لأننا سنحول الفيديو الناتج إلى صورة متحركة. الجزء clip.webm هو مسار الفيديو الناتج. ستحصل بعدها على فيديو مدته ثلاث ثواني باسم clip.webm، ويمكنك التأكد من حجمة باستخدام الأمر ls -lh: ls -lh clip.webm ستحصل على النتيجة التالية: Output -rw-r--r-- 1 sammy sammy 600K Nov 16 14:27 clip.webm لاحظ أن حجم ثلاث ثوانٍ من مقطع الفيديو هو 600K، بامكانك استخدام هذا الحجم كمرجع للمقارنة عندما تنشأ صورة GIF في الخطوة التالية. ملاحظة: إن كنت تستعمل جهازك المحلي، فيمكنك استخدام الأداة Lossless Cut وهي أداة واجهة رسوميات مفتوحة المصدر تستخدم لقص مقاطع الفيديو. تُعد هذه الأداة مفيدةً لأنها تنفذ نفس أوامر ffmpeg لاستخراج وقص مقاطع فيديو بسرعة استنادًا إلى الشيفرة الزمنية، دون إعادة ترميز الفيديو. بخلاف تشغيل ffmpeg في الطرفية، فإن Lossless Cut تحتوي على مشغل فيديو مدمج وواجهة تنقل. الخطوة الرابعة، تحويل الفيديو إلى صورة GIF بعد أن أصبح لديك مقطع فيديو مدته ثلاث ثوان وأصبحت تعرف معدل الإطارات والدقة اللازمة، بإمكانك الآن إنشاء صورة GIF منه. كما يمكنك تطوير خط آلي لتحويل مقاطع الفيديو إلى صور GIF، وحينها تستخدم الأداة ffprobe لاستخراج دقة الفيديو ومعدل الإطارات تلقائيًا من الفيديو وتمريرها مباشرةً إلى الأوامر اللاحقة. في مقالنا، سندخل يدويًا قيم الدقة ومعدل الإطارات للخرج المطلوب. لدينا عدة خيارات لإنشاء صور GIF في سطر الأوامر، يمكننا استخدام ffmpeg لوحدها لكن صيغة أوامرها صعبة الفهم والتغيير: ffmpeg -filter_complex "[0:v] fps=12,scale=w=540:h=-1,split [a][b];[a] palettegen [p];[b][p] paletteuse" -i clip.webm ffmpeg-sample.gif لاحظ أننا في مثالنا قلصنا الدقة ومعدل الإطارات إلى النصف، لنحصل على معدل إطارات 12fps ودقة بمقدار 540p بكسل، وتعد هذه بدايةً جيدة بالنسبة لصور GIF لأنها تعامل معاملة الصور العادية، إذ تُنَزل بالكامل عند تحميل صفحة ويب، بخلاف مقاطع الفيديو التي لا تُحَمّل تدريجيًا بدقة أقل. يمكنك استخدام شبكات توزيع المحتوى CDN لتحسين تسليم الأصول الثابتة للموقع مثل الصور، ولكن يجب أن تتفادى عرض الصور الضخمة دون هدف محدد. ولذا يجب ألا تنشأ صور GIF ذات حجم أعلى من 3 ميغا بايت، والآن، لنتحقق من حجم الصورة التي أنشأتها بواسطة الأمر ls -lh: ls -lh ffmpeg-sample.gif وستحصل على الخرج التالي: -rw-r--r-- 1 sammy sammy 2.0M Nov 16 14:28 ffmpeg-sample.gif أنشأنا بهذه الطريقة صورة GIF حجمها 2 ميغا بايت. لكن يمكننا الحصول على نتيجة أفضل باستخدام صياغة برمجية أقل تعقيدًا بواسطة gifski: gifski --fps 12 --width 540 -o gifski-sample.gif clip.webm لاحظ أننا ذكرنا التفاصيل المهمة كمعدل الإطارات والدقة، بالإضافة إلى اسمي ملفي الدخل والخرج. تحقق من الملف الناتج باستخدام الأمر التالي: ls -lh gifski-sample.gif لتحصل على الخرج التالي: -rw-r--r-- 1 sammy sammy 1.3M Nov 16 14:33 gifski-sample.gif حصلت على صورة GIF متحركة حجمها 1.3 ميغابايت وذلك يعد تحسنًا ملحوظًا عن النتيجة السابقة خاصةً أننا حافظنا على نفس الجودة. قد ترغب في إنشاء صورة ذات معدل إطارات كامل وبالدقة الكاملة كي تستطيع المقارنة وملاحظة الفرق: gifski --fps 25 --width 1080 -o gifski-high.gif clip.webm تحقق من حجم الملف الناتج: ls -lh gifski-high.gif الخرج -rw-r--r-- 1 sammy sammy 6.9M Nov 16 14:37 gifski-high.gif لاحظ أن حجم 6.9 ميغا بايت هو حجم كبير جدًا خصيصًا أن حجم الفيديو الأصلي هو 0.6 ميغا بايت وحسب! وتذكر أن صور GIF ليست ذات فاعلية مقارنةً ببرامج ترميز الفيديو الحديثة، فعليك التضحية قليلًا عندما تخفّض حجمها إلى حجم مقبول. سنتعلم في الخطوة التالية كيفية تحسين صور GIF. ملاحظة: إذا كنت تستخدم خادمًا بعيدًا لتنفيذ خطوات مقالنا، فيمكنك تنزيل الملفات وفحصها محليًا على جهازك، أو يمكنك نقلها إلى مجلد يمكن الوصول إليه من الويب كي تستعرضها في متصفح الويب. بهذه الطريقة سيصبح لديك مرجع مرئي لجودة الرسوميات. الخطوة الخامسة: تحسين صورة GIF والتحقق منها وعرضها سنستخدم الأداة gifsicle في الخطوة الأخيرة من مقالنا لتحسين جودة صورة GIF إذ إن ميزات استخدام gifsicle مع ملفات GIF تشابه ميزات استخدام ffmpegمع ملفات الصوت والفيديو وتمكننا من فعل أي شيء نرغبه، ولكن استخدامها قد يكون معقدًا جدًا. ولذلك، سنستخدم gifski لإنشاء صور GIF، وسنركز على بعض أوامر gifsicle لتحسين الصور أو معالجتها. أولًا، شَغّل أمر تحسين gifsicle القياسي: gifsicle -O3 --lossy=80 --colors 256 gifski-sample.gif -o optimized.gif لاحظ أننا في الأمر السابق طبقنا الخيار الثالث -O3 للحصول على أفضل تحسين، وطبقنا الخيار lossy 80-- لتحديد نسبة 20% كالحد الأقصى المسموح به لانخفاض الجودة عن الملف الأصلي، واخترنا --colors 256 لتطبيق 256 لون كحد أقصى في الصورة الناتجة. سيُنتِج ذلك صورةً ذات جودة أعلى من المتوقع بدون خسارة ملحوظة في الجودة لأن صور GIF لا تستخدم خوارزميات ضغط الإطارات الداخلية الحديثة، ولا تستخدم تقنيات ضغط صور JPEG. كما يشير 256 لونًا هنا إلى أي لوحة ألوان مكونة من 256 لونًا وفقًا للألوان الموجودة في ملف GIF، ولا يعبر عن لوحة ألوان محددة مكونة من أشيع 256 لون. وبصورة عامة، لا يكون ضغط GIF ملحوظًا. والآن، تحقق من حجم الصورة المحسنة optimized.gif: ls -lh optimized.gif وستحصل على الخرج التالي: -rw-r--r-- 1 sammy sammy 935K Nov 16 14:44 optimized.gif لاحظ أن الخطوة الأخيرة خفضت حجم الملف بنجاح إلى 935 كيلو بايت أي أكثر من حجم الفيديو الأصلي بقليل، وهو حجم مقبول لصورة متحركة. وهي نفس الصورة التي عرضناها سابقًا في مقالنا. يمكنك الاطلاع على دليل Gifsicle للتعرف على الطرق الأخرى لمعالجة صور GIF. على سبيل المثال، يمكنك "تقسيم" ملف GIF إلى ملفات صور متعددة، واحد لكل إطار رسوم متحرك باستخدام الأمر التالي: gifsicle --explode optimized.gif الذي ينشأ عدة ملفات اسمائها على نسق optimized.gif.000، optimized.gif.001 وهكذا، لكل صورة. استخدم الأمر ls -lh لعرض ملفات الصور: ls -lh optimized* لتحصل على الخرج التالي: -rw-r--r-- 1 sammy sammy 935K Nov 16 14:46 optimized.gif -rw-r--r-- 1 sammy sammy 20K Nov 16 14:54 optimized.gif.000 -rw-r--r-- 1 sammy sammy 17K Nov 16 14:54 optimized.gif.001 -rw-r--r-- 1 sammy sammy 22K Nov 16 14:54 optimized.gif.002 -rw-r--r-- 1 sammy sammy 22K Nov 16 14:54 optimized.gif.003 … كما يمكنك تدوير الصورة باستخدام خيار التدوير بمقدار 90 درجة --rotate-90 أو 180 درجة --rotate-180: gifsicle --rotate-90 optimized.gif -o rotated.gif على الرغم من عدم كفاءتها، لا تزال صور GIF مفيدةً لأنه يمكن استخدامها في عدة مواضع، عند الحاجة إلى مقطع متحرك قصير مثلًا، أو عند الحاجة إلى استخدام صيغة الصورة وليس الفيديو، أحيانًا لن تجد بديلًا عن صورة GIF. الخاتمة استخدمنا في مقالنا عدة أدوات لإنشاء صورة GIF من مقطع فيديو وتحسينها. كما تعرفنا على أدوات معالجة الفيديو مفتوحة المصدر وأدوات معالجة ملفات GIF، بالإضافة إلى بعض الخيارات لتعديل ملفات GIF. تعد صور GIF تقنيةً قديمةً ومثيرةً للاهتمام، لكن على الرغم من أنها ليست حديثة، إلا أنه لا يوجد لها بديل في بعض السياقات، كما أن أدوات التعامل مع صور GIF ذات أداء ودعم جيد.. والآن، أنشأ صور GIF وطبق ما تعلمناه في مقالنا هذا. وفي حال كان لديك مزيد من الاستفسارات حول ما ورد في المقال، أو أردت الحصول على الدعم والمساعدة أضف سؤالك في قسم الأسئلة والأجوبة في أكاديمية حسوب. ترجمة -وبتصرف- للمقال How To Make and Optimize GIFs on the Command Line. اقرأ أيضًا نصائح لإنشاء صور GIF دائمة الحركة كيف تنشئ صورًا متحركة بصيغة GIF من مجموعة صور PNG باستخدام ImageMagick وسطر الأوامر 10 أدوات وتطبيقات مجانية تسهل عليك تحسين الصور البحث عن الملفات والمجلدات على لينكس باستخدام الأمر find
-
تتطلب الأنظمة الحاسوبية الإدارة والمراقبة المناسبة، إذ تساعد مراقبة عمل النظام على اكتشاف المشكلات وحلها بسرعة. وثمة عدة أدوات أُنشئت لهذا الغرض، سنُعَرّفك في هذا المقال على أهم هذه الأدوات والتطبيقات. المتطلبات الأساسية لمتابعة خطوات هذا المقال، ستحتاج إلى ما يلي: حاسوب يعمل بنظام تشغيل لينكس Linux. يمكنك استخدام خادم خاص افتراضي VPS والاتصال به باستخدام بروتوكول SSH أو استخدام جهازك المحلي. استخدمنا في مقالنا خادم أوبنتو 20.04، لكن يمكنك اتباع أمثلتنا باستخدام أي من توزيعات لينكس. إن كنت تستخدم خادمًا بعيدًا فننصحك بالإطلاع على دليل إعداد الخادم الأولي لإعداد بيئة عمل آمنة على الخادم، ومستخدم غير جذري ذي صلاحيات sudo وجدار حماية، كما أن ذلك سيحسن مهاراتك في التعامل مع أنظمة لينكس. الخطوة الأولى: عرض العمليات الجارية Running Processes في لينكس يمكنك استعراض العمليات قيد التنفيذ في خادمك باستخدام الأمر top: top وستحصل على الخرج التالي: Output top - 15:14:40 up 46 min, 1 user, load average: 0.00, 0.01, 0.05 Tasks: 56 total, 1 running, 55 sleeping, 0 stopped, 0 zombie Cpu(s): 0.0%us, 0.0%sy, 0.0%ni,100.0%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st Mem: 1019600k total, 316576k used, 703024k free, 7652k buffers Swap: 0k total, 0k used, 0k free, 258976k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 init 2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd 3 root 20 0 0 0 0 S 0.0 0.0 0:00.07 ksoftirqd/0 6 root RT 0 0 0 0 S 0.0 0.0 0:00.00 migration/0 7 root RT 0 0 0 0 S 0.0 0.0 0:00.03 watchdog/0 8 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 cpuset 9 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper 10 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs لاحظ أن الأسطر الأولى من الخرج تزودنا بمعلومات أو إحصائيات statistics عن النظام، مثل حمل استخدام وحدة المعالجة المركزية والذاكرة والعدد الإجمالي للمهام قيد التشغيل. لاحظ أن هناك عملية واحدة قيد التشغيل، و 55 عملية خاملة Sleeping لأنها لا تستخدم وحدة المعالجة المركزية ويُظهر باقي الخرج العمليات الجارية وإحصائيات استخدامها. يرتب الأمر top هذه العمليات تلقائيًا حسب استخدام وحدة المعالجة المركزية، كي ترى العمليات الأكثر استهلاكًا للموارد أولاً. يستمر top في العمل في سطر الأوامر shell إلى أن توقفه باستخدام المفتاحين Ctrl + C للخروج من العملية الجارية.إذ يُرسل هذا إشارة إيقاف kill، ويطلب من العملية التوقف بأمان إذا كان ذلك ممكنًا. كما تتوفر في معظم مستودعات الحزم نسخة محسنة من الأمر top، تدعى htop. يمكنك تثبيت هذا الأمر على خادم أوبنتو باستخدام الأمر apt: sudo apt install htop شغّل بعد ذلك الأمر htop إذ أصبح متاحًا على جهازك: htop وستحصل على الخرج التالي: Mem[||||||||||| 49/995MB] Load average: 0.00 0.03 0.05 CPU[ 0.0%] Tasks: 21, 3 thr; 1 running Swp[ 0/0MB] Uptime: 00:58:11 PID USER PRI NI VIRT RES SHR S CPU% MEM% TIME+ Command 1259 root 20 0 25660 1880 1368 R 0.0 0.2 0:00.06 htop 1 root 20 0 24188 2120 1300 S 0.0 0.2 0:00.56 /sbin/init 311 root 20 0 17224 636 440 S 0.0 0.1 0:00.07 upstart-udev-brid 314 root 20 0 21592 1280 760 S 0.0 0.1 0:00.06 /sbin/udevd --dae 389 messagebu 20 0 23808 688 444 S 0.0 0.1 0:00.01 dbus-daemon --sys 407 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.02 rsyslogd -c5 408 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.00 rsyslogd -c5 409 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.00 rsyslogd -c5 406 syslog 20 0 243M 1404 1080 S 0.0 0.1 0:00.04 rsyslogd -c5 553 root 20 0 15180 400 204 S 0.0 0.0 0:00.01 upstart-socket-br يزودنا htop بتصور أفضل لخيوط وحدة المعالجة المركزية CPU threads وبدعم أفضل للعمليات في الطرفيات الحديثة، وخيارات فرز أوسع، بالإضافة لعدة ميزات أخرى. وبخلاف الأمر top، لا تجد htop مُنَزَلًا تلقائيًا ولكن عليك تنزيله، ويمكن أن تَعُده بديلًا عن top. كما يمكنك الخروج من الأمر htop باستخدام المفتاحين Ctrl+C. إليك بعض الاختصارات التي ستساعدك في استخدام htop بفاعلية أكبر: M: فرز العمليات حسب استهلاك المساحة P: فرز العمليات حسب استهلاك المعالج ?: المساعدة K: إيقاف العملية الجارية F2: ضبط إعدادات htop وضبط خيارات العرض /:: البحث في العمليات كما توجد عدة خيارات أخرى يمكنك الوصول إليها من خلال خيار المساعدة أو الضبط، ارجع إليها لاستكشاف وظائف htop. أما عن خطوتنا التالية، فسنتعلم فيها كيفية مراقبة النطاق الترددي للشبكة. الخطوة الثانية: مراقبة النطاق الترددي للشبكة إذا شعرت بازدياد الحمل على اتصال الشبكة، ولم تدرِ ما هو التطبيق الذي يستهلك الاتصال فيمكنك الاستعانة ببرنامج nethogs لمعرفة ذلك. ثبّت nethogs على خادم أوبنتو باستخدام الأمر التالي: sudo apt install nethogs سيصبح بعدها الأمر nethogs متاحًا للاستخدام: nethogs وستحصل عند تشغيله على الخرج التالي: NetHogs version 0.8.0 PID USER PROGRAM DEV SENT RECEIVED 3379 root /usr/sbin/sshd eth0 0.485 0.182 KB/sec 820 root sshd: root@pts/0 eth0 0.427 0.052 KB/sec ? root unknown TCP 0.000 0.000 KB/sec TOTAL يعرض برنامج nethogs استخدام كل برنامج للشبكة. إليك بعض الاختصارات التي ستسهل عليك التعامل معه: M: تغيير واحدة عرض النطاق الترددي إلى “kb/s” أو “kb” أو “b” أو “mb” R: الفرز حسب حجم البيانات المستلمة S: الفرز حسب حجم البيانات المُرسَلة Q: خروج كما يمكنك استخدام iptraf-ng لمراقبة استهلاك الشبكة، إذ يوفر عدة واجهات مراقبة تفاعلية. ملاحظة: يتطلب IPTraf حجم شاشة لا يقل عن 80 عمودًا و 24 سطرًا. ثبّت iptraf-ng على خادم أوبنتو باستخدام الأمر التالي: sudo apt install iptraf-ng لتشغيل الأمر iptraf-ng يجب أن تعطيه صلاحيات المستخدم الجذري، لذا عليك أن تستخدمه مع sudo: sudo iptraf-ng ستظهر قائمة تستخدم إطار عمل واجهة الطرفية الشائع المسمى ncurses: يمكنك بواسطة هذه القائمة اختيار الواجهة التي تود الوصول إليها. مثلًا، لإلقاء نظرة عامة على حركة البيانات في الشبكة، يمكنك اختيار القائمة الأولى ثم النقر على خيار جميع الواجهات "All interfaces"، وبعدها ستظهر لك شاشة كالتالية: سترى في هذه الواجهة جميع عناوين IP المستخدمة في واجهات شبكتك. إذا أردت تحويل عناوين IP هذه إلى نطاقات، فيمكنك تفعيل البحث العكسي عن DNS عن طريق الخروج من شاشة حركة بيانات الشبكة، ثم النقر على خيار الضبط configure، ثم Reverse DNS lookups. كما يمكنك تفعيل TCP/UDP service names أي أسماء خدمات بروتوكولي TCP/UDP لعرض أسماء الخدمات الحالية بدلًا عن أرقام منافذها. ستبدو الشاشة كالتالي، عند تفعيل الخيارين السابقين: ولدينا أيضًا الأمر netstat الذي يُعد أداةً متعددة الاستخدامات للحصول على معلومات عن الشبكة. والذي يوجد عادةً تلقائيًا في الأنظمة الحديثة، كما يمكنك تثبيته يدويًا من مستودع حزم الخادم الافتراضي package repository. الحزمة التي تحتوي على الأمر netstat في معظم أنظمة لينكس ومن ضمنها أوبنتو، هي net-tools: sudo apt install net-tools يطبع الأمر netstat من تلقاء نفسه قائمة بالمآخذ sockets المفتوحة: netstat ويعرض لك الخرج التالي: Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 192.241.187.204:ssh ip223.hichina.com:50324 ESTABLISHED tcp 0 0 192.241.187.204:ssh rrcs-72-43-115-18:50615 ESTABLISHED Active UNIX domain sockets (w/o servers) Proto RefCnt Flags Type State I-Node Path unix 5 [ ] DGRAM 6559 /dev/log unix 3 [ ] STREAM CONNECTED 9386 unix 3 [ ] STREAM CONNECTED 9385 . . . إذا أضفت الخيار a-، فسوف يعرض جميع المنافذ المفتوحة listening والمغلقة not listening netstat -a وستحصل على النتيجة التالية: Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 *:ssh *:* LISTEN tcp 0 0 192.241.187.204:ssh rrcs-72-43-115-18:50615 ESTABLISHED tcp6 0 0 [::]:ssh [::]:* LISTEN Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node Path unix 2 [ ACC ] STREAM LISTENING 6195 @/com/ubuntu/upstart unix 2 [ ACC ] STREAM LISTENING 7762 /var/run/acpid.socket unix 2 [ ACC ] STREAM LISTENING 6503 /var/run/dbus/system_bus_socket . . . إذا أردت تصفية النتائج لعرض اتصال TCP فقط أو UDP فقط، فعليك استخدام الراية t- أو u- : netstat -at الخرج Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 *:ssh *:* LISTEN tcp 0 0 192.241.187.204:ssh rrcs-72-43-115-18:50615 ESTABLISHED tcp6 0 0 [::]:ssh [::]:* LISTEN ولاحظ النتائج عند استخدام الراية s- netstat -s الخرج Ip: 13500 total packets received 0 forwarded 0 incoming packets discarded 13500 incoming packets delivered 3078 requests sent out 16 dropped because of missing route Icmp: 41 ICMP messages received 0 input ICMP message failed. ICMP input histogram: echo requests: 1 echo replies: 40 . . . إذا أردت تحديث الخرج باستمرار، يمكنك استخدام الراية c-. ثمة عدة خيارات متاحة للأمر netstat يمكنك التعرف عليها من خلال مراجعة صفحة دليلها التعليمي. سنتعرف، في الخطوة التالية، على بعض الطرق المفيدة لمراقبة استخدام قرص التخزين الخطوة الثالثة: مراقبة استخدام القرص استخدم الأمر df لإلقاء نظرة سريعة على مساحة القرص المتبقية على محرك الأقراص المرفق: df وستحصل على الخرج التالي: Filesystem 1K-blocks Used Available Use% Mounted on /dev/vda 31383196 1228936 28581396 5% / udev 505152 4 505148 1% /dev tmpfs 203920 204 203716 1% /run none 5120 0 5120 0% /run/lock none 509800 0 509800 0% /run/shm يعرض هذا الأمر المساحة المستخدمة بالبايتات، مما قد يجعلها صعبة القراءة، لحل هذه المشكلة اعرض الخرج بطريقة يَسهُل قراءتها على البشر human-readable، وذلك بإضافة الخيار h-: df -h وستحصل على الخرج التالي: Filesystem Size Used Avail Use% Mounted on /dev/vda 30G 1.2G 28G 5% / udev 494M 4.0K 494M 1% /dev tmpfs 200M 204K 199M 1% /run none 5.0M 0 5.0M 0% /run/lock none 498M 0 498M 0% /run/shm استخدم الخيار total-- لعرض إجمالي مساحة القرص المتاحة في جميع أنظمة الملفات، حينها ستُعرض المعلومات في سطر جديد في الأسفل، كما يلي: df -h --total الخرج Filesystem Size Used Avail Use% Mounted on /dev/vda 30G 1.2G 28G 5% / udev 494M 4.0K 494M 1% /dev tmpfs 200M 204K 199M 1% /run none 5.0M 0 5.0M 0% /run/lock none 498M 0 498M 0% /run/shm total 32G 1.2G 29G 4% لاحظ أن الأمر df يزوّدنا بمعلومات مفيدة، أما الأمر du فيستخدم التصنيف حسب المجلد، إذ يحلل الاستخدام للمجلد الحالي والمجلدات الفرعية. يبدو خرج du عند تشغيله في مجلد رئيسي فارغ كما يلي: du الخرج 4 ./.cache 8 ./.ssh 28 . كما يمكنك عرض الخرج بطريقة سهلة القراءة، وذلك بإضافة الخيار h-: du -h وستحصل على الخرج التالي: 4.0K ./.cache 8.0K ./.ssh 28K . ولعرض حجم الملفات والمجلدات، استخدم الخيار a- du -a الخرج 0 ./.cache/motd.legal-displayed 4 ./.cache 4 ./.ssh/authorized_keys 8 ./.ssh 4 ./.profile 4 ./.bashrc 4 ./.bash_history 28 . استخدم الخيار c- لإضافة سطر لعرض المحصلة: du -c وسيصبح الخرج كالتالي: 4 ./.cache 8 ./.ssh 28 . 28 total إذا أردت الحصول على المحصلة فقط دون التفاصيل استخدم الخيار s- du -s وسيكون الخرج كالتالي: 28 . كما توجد واجهة ncurses للأمر du تدعى ncdu ويمكنك تثبيتها باستخدام الأمر التالي: sudo apt install ncdu والذي سيمثل استخدام القرص بيانيًا كالتالي: ncdu الخرج --- /root ---------------------------------------------------------------------- 8.0KiB [##########] /.ssh 4.0KiB [##### ] /.cache 4.0KiB [##### ] .bashrc 4.0KiB [##### ] .profile 4.0KiB [##### ] .bash_history يمكنك التنقل في نظام الملفات باستخدام مفتاح السهم العلوي والسهم السفلي في لوحة المفاتيح والنقر على مفتاح enter لاستعراض المجلد. ستتعلم في الفقرة الأخيرة كيفية مراقبة استخدام الذاكرة. الخطوة الرابعة: مراقبة استخدام الذاكرة يمكنك عرض استخدام الذاكرة الحالي على نظام التشغيل باستخدام الأمر free: free وسيبدو الخرج كما يلي: total used free shared buff/cache available Mem: 1004896 390988 123484 3124 490424 313744 Swap: 0 0 0 لتسهيل قراءة الخرج، استخدم الخيار m- لعرض الحجم بواحدة الميغا بايت: free -m الخرج total used free shared buff/cache available Mem: 981 382 120 3 478 306 Swap: 0 0 0 يحتوي سطر mem على تفاصيل الذاكرة المستخدمة للتخزين المؤقت buffering and caching التي تفرغ محتوياتها عند الحاجة لاستخدامها في عملية أخرى. أما ذاكرة سواب swap فهي مكتوبة على ملف swapfile على القرص للمحافظة على الذاكرة النشطة Active memory. يعرض الأمر vmstat معلومات متعددة عن النظام بما في ذلك معلومات الذاكرة، ومعلومات الذاكرة swap، ومعلومات وحدة المعالجة المركزية، ومداخل ومخارج الأقراص. يمكنك استخدام vmstat لعرض معلومات استخدام الذاكرة: Vmstat الخرج procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu---- r b swpd free buff cache si so bi bo in cs us sy id wa 1 0 0 99340 123712 248296 0 0 0 1 9 3 0 0 100 0 اعرض الخرج بواحدة الميغا بايت عن طريق كتابة الواحدة M بعد الراية S- vmstat -S M Output 495 M total memory 398 M used memory 252 M active memory 119 M inactive memory 96 M free memory 120 M buffer memory 242 M swap cache 0 M total swap 0 M used swap 0 M free swap . . . استخدم الأمر التالي للحصول على معلومات عامة عن استخدام الذاكرة: vmstat -s -S M Output Cache Num Total Size Pages ext4_groupinfo_4k 195 195 104 39 UDPLITEv6 0 0 768 10 UDPv6 10 10 768 10 tw_sock_TCPv6 0 0 256 16 TCPv6 11 11 1408 11 kcopyd_job 0 0 2344 13 dm_uevent 0 0 2464 13 bsg_cmd 0 0 288 14 . . . أما للحصول على معلومات عن استخدام عمليات النظام الفردية لذاكرة التخزين المؤقت cache فاستخدم الأمر التالي: vmstat -m -S M وستحصل على الخرج التالي: Cache Num Total Size Pages ext4_groupinfo_4k 195 195 104 39 UDPLITEv6 0 0 768 10 UDPv6 10 10 768 10 tw_sock_TCPv6 0 0 256 16 TCPv6 11 11 1408 11 kcopyd_job 0 0 2344 13 dm_uevent 0 0 2464 13 bsg_cmd 0 0 288 14 . . . الذي سيزودك بتفاصيل حول المعلومات المخزنة في ذاكرة التخزين المؤقت. الخاتمة أصبحت الآن قادرًا على مراقبة خادمك من سطر الأوامر باستخدام الأدوات التي تعلمتها في مقالنا. وعلى الرغم أنه ثمة عدة أدوات مراقبة أخرى تُستخدم لأغراض مختلفة، إلا أن هذه تُعد انطلاقةًجيدة. ننصحك بعد قراءة هذا المقال بالتعرف على إدارة عمليات لينكس باستخدام ps وkill وnice. لمزيد من الاستفسارات حول ما ورد في مقالنا، أو للحصول على الدعم والمساعدة أضف سؤالك في قسم الأسئلة والأجوبة في أكاديمية حسوب. ترجمة -وبتصرف- للمقال How To Use Top, Netstat, Du, & Other Tools to Monitor Server Resources لصاحبيه Justin Ellingwood و Alex Garnett. اقرأ أيضًا إعداد خادم اختبار محلي مراقبة شهادات SSL/TLS في الموقع باستخدام أداة Checkmk مدخل إلى خادم الويب عشرون أمرا في لينكس يفترض أن يعرفها كل مدير نظم تعرف على عناوين بروتوكول الإنترنت والشبكات الفرعية والتوجيه غير الصنفي بين النطاقات
-
يُعد إطار Express أحد الإطارات الشائعة لبناء تطبيقات الويب السريعة وواجهات برمجة التطبيقات API باستخدام بيئة التشغيل Node.js. منصة تطبيقات DigitalOcean عبارة عن منتج منصة على أساس خدمة PaaS لضبط إعدادات التطبيقات ونشرها من مستودع شيفرات برمجية، فهي توفر طريقة سريعة وفعالة لنشر تطبيقات Express. سنتعلم في دليلنا هذا، كيفية نشر تطبيق Express على منصة تطبيقات DigitalOcean ثم توسيع نطاقه عن طريق إضافة التخزين المؤقت باستخدام إضافة متجر DigitalOcean Marketplace المخصصة لـ MemCachier. إذ يتوافق MemCachier مع نظام memcached للتخزين المؤقت للكائنات ولديه عدة مزايا، مثل تحسين سيناريوهات الفشل باستخدام مجموعة حواسيب عالية التوفر. سننشئ أولاً تطبيق Express يحسب عددًا أوليًا، ويحتوي على زر "أعجبني"، ويستخدم محرك قوالب Template engine. ستمكنك هذه الميزات من تنفيذ عدة استراتيجيات تخزين مؤقت لاحقًا. ثم ستدفع شيفرة التطبيق على Git Hub لتنشره بعدها على منصة التطبيقات App Platform. وأخيرًا، ستطبق ثلاث تقنيات تخزين مؤقت للكائنات لتسريع التطبيق وجعله سهل التطوير والتوسع. بنهاية هذا المقال، ستكون قادرًا على نشر تطبيق Express على منصة App Platform، وتطبيق تقنيات التخزين المؤقت لتخزرين العمليات ذات الاستخدام الكثيف للموارد، وتخزين طرق العرض المصيّر rendered views، والجلسات sessions. المتطلبات الأساسية لمتابعة خطوات هذا المقال التعليمي، ستحتاج إلى ما يلي: تثبيت بيئة تشغيل Node.js على جهازك العامل بنظام أوبنتو 22.04، ننصحك باتباع خطوات المقال التالي. أما إن كنت تستخدم نظام تشغيل آخر، فعليك اتباع المقال التالي. خادم Express مُثبّت عليه Node.js، ووللقيام بذلك ننصحك بالإطلاع على الخطوتين الأولى والثانية في هذا المقال. حساب غيت هب GitHub و تثبيت غيت Git على جهازك، إذ سننشر التطبيق في حسابك على غيت هب GitHub ثم سننشره على منصة تطبيقات DigitalOcean، اتبع الخطوات الواردة في المقال التالي لتثبيت غيت على جهازك. حساب على DigitalOcean لنشر التطبيق على منصة App Platform، وننبهك إلى أن نشر التطبيقات على هذه المنصة مأجور، لذا اطّلع على أجور منصة App Platform قبل البدء. متصفح إنترنت مثل متصفح كروم Chrome أو فايرفوكس Fire Fox. فهم أساسيات عمل موّلد قوالب Express. فهم آلية عمل البرمجيات الوسيطة middle-ware . الخطوة الأولى: ضبط قالب عرض مصيّر سنثبّت في هذه الخطوة موّلد قوالب Express، وننشئ قالبًا للمسار الرئيسي للتطبيق GET/، ثم سنحدّث المسار كي يستخدم هذا القالب. تمَكّننا القوالب من استخدام التخزين المؤقت للعرض المصيّر rendered view، مما يزيد سرعة معالجة الطلب ويقلل استخدام الموارد. لبدء العمل، انتقل إلى مجلد مشروع خادم Express باستخدام المحرر، سنثبّت محرك قوالب Express لاستخدام القوالب الثابتة في التطبيق، حيث يستبدل محرك القوالب المتغيرات الموجودة في ملف القالب بالقيم ثم يحول القالب إلى ملف HTML، ثم يُرسَل كرد أو استجابة response على طلب request. إذ يؤدي استخدام القوالب إلى تسهيل العمل باستخدام HTML. والآن، ثبّت مكتبة قوالب جافا سكربت المضمنة ejs، كما يمكنك استخدام أحد محركات القوالب التي يدعمها Express مثل Mustache أو Pug أو Nunjucks. npm install ejs بعد تثبيت مكتبة ejs، عليك ضبط إعدادات تطبيق Express كي يستخدمها، وذلك عن طريق فتح الملف server.js في محرر النصوص البرمجية، وإضافة السطر الثالث كما يلي: server.js const express = require('express'); const app = express(); app.set('view engine', 'ejs'); app.get('/', (req, res) => { res.send('Successful response.'); }); ... يعدّل هذا السطر إعدادات التطبيق ويعين خاصيّة view engine على ejs. ثم احفظ الملف بعد ذلك. ملاحظة: سنستخدم في هذا المقال الإعداد view engine، كما يمكنك استخدام الإعداد views الذي يدّل تطبيق Express على مكان وجود ملفات القوالب، وقيمته الافتراضية هي views/. والآن، أنشئ مجلد views ثم أنشئ فيه الملف views/index.ejs وافتحه في محرر النصوص البرمجية. وأضف توصيف القالب إلى الملف: views/index.ejs <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Find the largest prime number</title> </head> <body> <h1>Find the largest prime number</h1> <p> For any number N, find the largest prime number less than or equal to N. </p> </body> </html> ثم احفظ الملف. بعد أن أنشأت القالب، عليك تعديل المسار كي تتمكن من استخدامه. افتح الملف server.js وأضف ما يلي إليه: ... app.get('/', (req, res) => { res.render('index'); }); ... لاحظ أن دالة رد النداء render تأخذ اسم القالب كوسيط أول، وفي مثالنا يتوافق index مع اسم الملف views/index.ejs. والآن، أعد تشغيل التطبيق لكي تطبق التغيرات التي أجريتها. أوقف عمل الخادم في الطرفية باستخدام المفتاحين Ctrl+C ثم أعد تشغيل الخادم باستخدام الأمر التالي: node server.js الآن انتقل إلى localhost:3000 في المتصفح لمشاهدة محتوى القالب، ستحصل على نتيجة مماثلة لما يلي: والآن، أصبح تطبيقك يتمتع بعرض مُصَيّر للقوالب، لكنه لا ينفذ شيئًا الآن. سنضيف في الخطوة التالية وظيفة للعثور على عدد أولي. الخطوة الثانية، إضافة الوظائف إلى تطبيق Express سنضيف في هذه الخطوة ميّزة العثور على عدد أولي، وميّزة إبداء الإعجاب باستخدام زر "أعجبني Like". سنستخدم هذه الميزات للتفاعل مع التطبيق بعد نشره على منصة App Platform في الخطوة الرابعة من هذا المقال. العثور على العدد الأولي سنضيف الآن دالة إلى تطبيقنا وظيفتها العثور على أكبر عدد أولي أقل من أو يساوي N، حيث يشير N إلى عدد ما. سنرسل العدد N عبر استمارة باستخدام التابع GET إلى المسار الرئيسي (/) مع إضافة N كوسيط للاستعلام query، كما يلي: localhost:3000/?n=10 تمثل القيمة 10 هنا عينة الاستعلام، ويمكن أن يحتوي المسار الرئيسي على عناوين URL متعددة تنتج طرق عرض مصيّرة، كما يمكن تخزينها مؤقتًا بصورة فردية. أضف نموذجًا كالتالي يحتوي على عنصر إدخال لإدخال N في الملف views/index.ejs: ... <p> For any number N, find the largest prime number less than or equal to N. </p> <form action="/" method="get"> <label> N <input type="number" name="n" placeholder="e.g. 10" required> </label> <button>Find Prime</button> </form> ... لاحظ أن إجراء النموذج form يُرسَل إلى المسار الرئيسي /، الذي سيُعالَج بواسطة المسار الرئيسي (...'/')get.app في ملف server.js. وبما أن التابع هو get، فستضاف بيانات n إلى عنوان URL كوسيط للاستعلام. بعد ذلك، عند إجراء طلب باستخدام وسيط استعلام n، ستُمَرَر تلك البيانات إلى القالب. أضف الأسطر التالية بعد التابع get على الملف server.js، ثم احفظ الملف: ... app.get('/', (req, res) => { const n = req.query.n; if (!n) { res.render('index'); return; } const locals = { n }; res.render('index', locals); }); ... تتحقق الأسطر السابقة من وجود طلب له وسيط استعلام ذو القيمة n، فإذا تحقق ذلك يُصيَّر الملف index مع تمرير القيمة n إليه، وإلا فيُعرض الملف index بدون بيانات. ملاحظة: لا يمكن الوثوق دائمًا بالبيانات التي يدخلها المستخدم، لذا لإنشاء تطبيق جاهزًا للنشر يُنصح بالتحقق من المدخَلات باستخدام مكتبة joi. لاحظ أن للتابع render وسيط ثاني اختياري locals يُعَرّف المتغيرات المحلية التي تمرر إلى القالب لتصيير العرض. يحدد اسم الواصف المختصر الخاصية n للكائن المحلي locals، فعندما يكون للمتغير نفس اسم واف الكائن المُسند إليه، يمكن حذف اسم المتغير. لذلك يمكن كتابة { n: n } بالشكل { n }. والآن، أصبح بإمكاننا عرض القالب بعد أن أضفنا إليه البيانات. أضف الأسطر التالية على ملف views/index.ejs: <% if (locals.n) { %> <p>N: <%= n %></p> <% } %> ... وهكذا يعرض التطبيق المتغيرات المحلية n إن وجدت. احفظ الملف، ثم أعد تشغيل الخادم لتحديث التطبيق. سيُعرَض النموذج مع زر لإيجاد العدد الأولي Find Prime، حيث يأخذ التطبيق المدخلات من المستخدم ويعرضها تحت النموذج: أدخل عددًا ما ولاحظ أن العنوان URL سيتغير وسيضاف إليه العدد الذي أدخلته، على سبيل المثال، إن أدخلت العدد 40 سيصبح العنوان كالتالي: http://localhost:3000/?n=40 كما سيُعرض العدد الذي أدخلته أسفل النموذج على الشكل التالي N: 40. والآن بعد أن أصبح بإمكاننا إدخال قيمة للعدد N وعرضها، علينا إضافة دالة للعثور على أكبر عدد أولي أصغر أو مساوي للعدد N، وعرض النتيجة على الشاشة. أنشئ مجلد utils، ثم أنشئ الملف utils/findPrime.js. افتح الملف findPrime.js في المحرر ثم أضف الكود التالية لتعريف وظيفة أو دالة للعثور على العدد الأولي، ولا تنسَ حفظ الملف بعدها: utils/findPrime.js /** * Find the largest prime number less than or equal to `n` * @param {number} n A positive integer greater than the smallest prime number, 2 * @returns {number} */ module.exports = function (n) { let prime = 2; // initialize with the smallest prime number for (let i = n; i > 1; i--) { let isPrime = true; for (let j = 2; j < i; j++) { if (i % j == 0) { isPrime = false; break; } } if (isPrime) { prime = i; break; } } return prime; }; يوّثق تعليق JSDoc عمل الدالة، إذ تبدأ الخوارزمية بالعدد الأولي الأول 2، ثم ثم تكرر العمل بدءًا من العدد n وتنقص الرقم بمقدار 1 في كل حلقة. وتستمر الدالة في حلقة التكرار والبحث عن عدد أولي حتى يصبح الرقم 2، وهو أصغر رقم أولي. تفترض كل حلقة أن العدد الحالي هو عدد أولي، ثم تتحقق من صحة هذا الافتراض، عن طريق التحقق من وجود عامل آخر للعدد الحالي آخر غير 1 ونفسه. إذا أمكن قسمة العدد الحالي على أي رقم أكبر من 1 وأقل من العدد نفسه دون باقي، فهو ليس عددًا أوليًا. ثم ستتحق الدالة بعد ذلك من العدد التالي. بعدها، أضف السطر الثاني إلى ملف server.js لاستيراد دالة العدد الأولي: const express = require('express'); const findPrime = require('./utils/findPrime'); ... عدّل على المسار الرئيسي لإيجاد العدد الأولى وتمرير قيمته إلى القالب من خلال إضافة السطر التالي إلى ملف server.js، ثم احفظ الملف: const prime = findPrime(n); والآن، لعرض النتيجة في القالب وإظهار قيمة N أضف الشيفرة التالية في ملف views/index.ejs: <% if (locals.n && locals.prime) { %> <p> The largest prime number less than or equal to <%= n %> is <strong><%= prime %></strong>. </p> <% } %> ... بدلًا عن: <% if (locals.n) { %> <p>N: <%= n %></p> <% } %> ولا تنسَ حفظ الملف، ثم أعد تشغيل الخادم. اختبر عمل الدالة عن طريق إدخال عدد ما، كالعدد 10، ستظهر رسالة: The largest prime number less than or equal to 10 is 7 ومفادها أن العدد الأولي الأعظمي الأصغر أو يساوي العدد 10 هو العدد 7. أصبح بإمكان التطبيق إيجاد وعرض رقم أولي وفقًا لرقم يدخله المستخدم، والآن علينا إضافة زر أعجبني. إضافة زر أعجبني ينتج تطبيقنا حاليًا طرق عرض ونتائج مختلفة بناءً على كل عدد N ندخله، ومن المرجح أن يظل المحتوى كما هو. سيوفر لنا زر أعجبني Like طريقة لتحديث محتوى العرض. يوضح لنا هذا الزر الحاجة إلى إبطال طريقة العرض المخزنة مؤقتًا عند تغير محتوياتها، إذ سيفيدنا ذلك عند التخزين المؤقت لطرق العرض المصيّرة لاحقًا في مقالنا. عند استخدام زر "أعجبني"، يجب تخزين بيانات الإعجاب في مكان ما. على الرغم من أن التخزين الثابت persistent storage مثالي، إلا أننا ستخزن الإعجابات في الذاكرة نظرًا لأن إنشاء قاعدة بيانات يقع خارج نطاق مقالنا. هكذا، ستكون البيانات سريعة الزوال، مما يعني أننا سنفقد كل البيانات عندما يتوقف الخادم. افتح ملف server.js وأضف المتغير التالي: /** * Key is `n` * Value is the number of 'likes' for `n` */ const likesMap = {}; يُستخدم الغرض likesMap كخريطة لتخزين إعجابات الأعداد. المفتاح هو n وقيمه هي عدد إعجابات n. يجب تهيئة إعجابات العدد عند إرساله. أضف السطر الثاني والثالث على ملف server.js لتهيئة إعجابات N: ... const prime = findPrime(n); // Initialize likes for this number when necessary if (!likesMap[n]) likesMap[n] = 0; const locals = { n, prime }; res.render('index', locals); .. تتحقق عبارة if من وجود إعجابات للعدد الحالي. في حالة عدم وجود إعجابات، يُهيَّئ likesMaps على القيمة 0. ثم أضف الإعجابات كمتغير محلي للعرض، عن طريق تعديل سطر المتغيرات المحلية ليصبح كما يلي ولا تنسَ حفظ الملف: const locals = { n, prime, likes: likesMap[n] }; res.render('index', locals); بعد أن أصبح لدينا بيانات الإعجابات، أصبح بإمكاننا عرض قيمتها وإضافة زر أعجبني. عدّل على ملف views/index.ejs لإضافة توصيف Markup لزر أعجبني كما يلي: <% if (locals.n && locals.prime) { %> <p> The largest prime number less than or equal to <%= n %> is <strong><%= prime %></strong>. </p> <form action="/like" method="get"> <input type="hidden" name="n" value="<%= n %>"> <input type="submit" value="Like"> <%= likes %> </form> <% } %> يجب أن يبدو ملف views/index.ejs على النحو التالي: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Find the largest prime number</title> </head> <body> <h1>Find the largest prime number</h1> <p> For any number N, find the largest prime number less than or equal to N. </p> <form action="/" method="get"> <label> N <input type="number" name="n" placeholder="e.g. 10" required> </label> <button>Find Prime</button> </form> <% if (locals.n && locals.prime) { %> <p> The largest prime number less than or equal to <%= n %> is <strong><%= prime %></strong>. </p> <form action="/like" method="get"> <input type="hidden" name="n" value="<%= n %>"> <input type="submit" value="Like"> <%= likes %> </form> <% } %> </body> </html> لا تنسَ حفظ الملف. ثم أعد تشغيل الخادم. سيظهر على الشاشة زر أعجبني له القيمة 0 بعد ظهور نتيجة العدد الأولي. يؤدي النقر فوق زر "أعجبني" إلى إرسال طلب GET إلى المسار like/، بالقيمة الحالية لـ N كوسيط استعلام عبر إدخال غير مرئي. لكن ستحصل على رسالة خطأ 404 والعبارة Cannot GET /like، لأن التطبيق ليس لديه مسار مطابق بعد. سنضيف الآن المسار اللازم للتعامل مع الطلب، وذلك عبر إضافة الأسطر التالية: app.get('/like', (req, res) => { const n = req.query.n; if (!n) { res.redirect('/'); return; } likesMap[n]++; res.redirect(`/?n=${n}`); }); ... يتحق المسار الجديد من وجود n وفي حال عدم وجودها نعود إلى المسار الرئيسي. أما في حال وجودها، فيزيد التطبيق عدد الإعجابات لهذا العدد. ثم يوجهنا إلى شاشة العرض التي ضغطنا فيها على زر "أعجبني". يجب أن يبدو الملف على النحو التالي: const express = require('express'); const findPrime = require('./utils/findPrime'); const app = express(); app.set('view engine', 'ejs'); /** * Key is `n` * Value is the number of 'likes' for `n` */ const likesMap = {}; app.get('/', (req, res) => { const n = req.query.n; if (!n) { res.render('index'); return; } const prime = findPrime(n); // Initialize likes for this number when necessary if (!likesMap[n]) likesMap[n] = 0; const locals = { n, prime, likes: likesMap[n] }; res.render('index', locals); }); app.get('/like', (req, res) => { const n = req.query.n; if (!n) { res.redirect('/'); return; } likesMap[n]++; res.redirect(`/?n=${n}`); }); const port = process.env.PORT || 3000; app.listen(port, () => console.log(`Example app is listening on port ${port}.`) ); احفظ الملف، ثم أعد تشغيل التطبيق واختبر زر "أعجبني"، يجب أن يزداد عدد الإعجابات مع كل نقرة. ملاحظة: يمكنك استخدام تابع POST بدلاً من GET لهذا المسار، والذي يوافق نمط RESTful أكثر لأننا حدثنا أحد الموارد. نستخدم في مقالنا تابع GET بدلاً من التعامل مع طلب POST حتى تتمكن من العمل مع وسطاء استعلام الطلب المألوفة. أصبح التطبيق مكتملًا الآن ويعمل جيدًا، ويمكنك الاستعداد لنشره على منصة App Platform. في الخطوة التالية، سنُوْدِع الشيفرة في غيت Git، ثم ندفعها إلى مستودع غيت هب GitHub. الخطوة الثالثة، إنشاء مستودع الشيفرات البرمجية سننشئ في هذه الخطوة مستودع شيفرات برمجية Code Repository كي نخزّن فيه الملفات اللازمة للنشر. سنُوْدِع commit الشيفرة في غيت Git، ثم ندفعها push أو نضيفها إلى مستودع غيت هب GitHub، الذي سنستخدمه لنشر التطبيق على App platform. إيداع الشيفرة في جيت سنُودع الشيفرة في جيت كي تصبح جاهزةً لإضافتها أو دفعها إلى جيت هب. ملاحظة: إن لم تسجل الدخول إلى حسابك وتضبط الإعدادات، فاحرص على إعداد غيت و مصادقته حسابك على غيت هب باستخدام بروتوكول SSH. أولًا، عليك تهيئة مستودع غيت: git init ثم عليك استبعاد اعتماديات التطبيق dependencies، وذلك بإنشاء ملف اسمه gitignore. وإضافة الشيفرة التالية فيه: .gitignore node_modules # macOS file .DS_Store ملاحظة: السطر DS_Store. خاص بالأجهزة التي تعمل باستخدام نظام ماك أو إس mac OS ولا حاجة لإضافة إن كان نظام التشغيل مختلفًا. والآن احفظ الملف. ثم أضف كل الملفات إلى غيت: git add . وأَودِع التغييرات بواسطة الأمر التالي: git commit -m "Initial commit" يُستخدم الخيار m- لتحديد رسالة إيداع من اختيارك. والآن بعد إيداع الشيفرة، ستحصل على خرج مماثل لما يلي: Output [main (root-commit) deab84e] Initial commit 6 files changed, 1259 insertions(+) create mode 100644 .gitignore create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 server.js create mode 100644 utils/findPrime.js create mode 100644 views/index.ejs أي أنك أودعت الشيفرة في غيت، والآن عليك دفعها إلى غيت هب. دفع الشيفرة إلى مستودع غيت هب أصبح بإمكانك الآن دفع الشيفرة إلى غيت هب، ثم ربط الشيفرة بمنصة App Platform ونشره. أولاً، سجل الدخول إلى غيت هب من المتصفح وأنشئ مستودعًا جديدًا باسم Express-memcache. ثم أنشئ مستودعًا فارغًا بدون ملفات README أو gitignore. أو ملفات الشهادات. يمكنك جعل المستودع خاصًا أو عامًا. كما يمكنك مراجعة توثيق غيت هب حول كيفية إنشاء مستودع جديد. ثم عد إلى الطرفية، وأضف المستودع الذي أنشأته بمثابة remote origin، وحدّث اسم المستخدم الخاص بك: git remote add origin https://github.com/your_username/express-memcache.git يوجه الأمر السابق غيت إلى المكان الذي يجب عليه إضافة الشيفرة فيه. ثم سمّي الفرع الافتراضي فرعًا رئيسيًا main: git branch -M main ثم أضف الشيفرة إلى مستودعك: git push -u origin main ثم أدخل بياناتك إذا طُلب منك ذلك. وستحصل على خرج مشابه لما يلي: Enumerating objects: 10, done. Counting objects: 100% (10/10), done. Delta compression using up to 8 threads Compressing objects: 100% (7/7), done. Writing objects: 100% (10/10), 9.50 KiB | 9.50 MiB/s, done. Total 10 (delta 0), reused 0 (delta 0), pack-reused 0 To https://github.com/your_username/express-memcache.git * [new branch] main -> main Branch 'main' set up to track remote branch 'main' from 'origin'. وبهذا أصبحت شيفرة التطبيق موجودةً على غيت هب، وأصبح التطبيق جاهزًا للنشر على منصة App Platform. الخطوة الرابعة، نشر التطبيق على منصة App Platform سننشر في هذه الخطوة، تطبيقنا على منصة تطبيقات App Platform. سننشئ حسابًا على المنصة ونسمح له بالوصول إلى مستودع غيت هب لنشر التطبيق. سنحدّث أولًا إعدادات البيئة كي يُتاح لها قراءة الضبط بواسطة عنوان البيئة PORT. تحديث إعدادات بيئة التطبيق سنسمح في هذه الفقرة لمتغيرات البيئة بالوصول وقراءة إعدادات منفذ التطبيق، لأن هذه الإعدادات ربما تتغير عند النشر، لذا فإن هذه الخطوة ستُمكّن التطبيق من الوصول إلى المنفذ من بيئة منصة التطبيقات. افتح ملف server.js في محرر النصوص البرمجية وتأكد من إضافة الأسطر التالية: ... const port = process.env.PORT || 3000; app.listen(port, () => console.log(`Example app is listening on port ${port}.`) ); تنّص هذه الأسطر على استخدام متغير البيئة port في حال وجوده، أو استخدام المنفذ الافتراضي 3000. والآن، أصبح التطبيق قادرًا على القراءة من منفذ بيئة منصة التطبيقات التي سننشره عليها. إنشاء ونشر التطبيق على منصة App Platform سنُعدّ التطبيق للنشر على منصة App Platform، ولكن تذكر أن هذه الخطوة مأجورة، وعليك دفع رسوم تشغيل التطبيق على منصة App Platform بالثانية (بدءًا من دقيقة واحدة على الأقل). يمكنك الإطلاع على الأسعار في صفحة المعاينة Review، كما يمكنك الاطلاع على نظام تسعير منصة App Platform للحصول على تفاصيل أكثر. أولاً، سجل الدخول إلى حسابك على DigitalOcean، ثم انقر على إنشاء create من لوحة تحكم التطبيقات Apps Dashboard. كما يمكنك الاطلاع على توثيق كيفية إنشاء التطبيقات في منصة App Platform. ثم ادخل إلى صفحة Create Resource From Source Code screen، واختر غيت هب كمزود الخدمة Service Provider، وامنح الإذن لـDigitalOcean للوصول إلى مستودعك. ننصحك بتحديد المستودع الذي تريد نشره فقط. سُتطالب بتثبيت تطبيق DigitalOcean GitHub. حدد مستودعك من القائمة وانقر فوق التالي Next. في شاشة الموارد Resources، انقر على تعديل الشريحة Edit Plan لتحديد حجم الاشتراك. سنستخدم في مقالنا الاشتراك الأساسي ذو خدمات الويب الأصغر حجمًا (512 ميغابايت من ذاكرة الوصول العشوائي vCPU | RAM) مخصصة لمورد express-memcache. إذ يوفر الاشتراك الأساسي وأصغر خدمة ويب موارد كافيةً لتطبيقنا التدريبي. بعد اختيار الاشتراك، انقر على رجوع Back. ثم انقر على علامة تبويب المعلومات info في شريط التنقل الأيسر وانتبه على المنطقة التطبيق، إذ سنحتاج إلى ذلك في الخطوة التالية لإضافة MemCachier من متجر DigitalOcean. أخيرًا، انقر على نافذة المعانية Review، ثم زر إنشاء موارد Create Resources لإنشاء التطبيق ونشره. سيستغرق الأمر بعض الوقت لإنشاء التطبيق ونشره. ستصلك رسالة عند الانتهاء فيها رابط التطبيق بعد نشره. بهذا نكون قد أنشأنا تطبيق Express يمكنه العثور على رقم أولي ويحتوي على زر أعجبني. ثم أَودَعنا شيفرة التطبيق إلى غيت ودفعناه إلى غيت هب، ثم نشرنا التطبيق على App Platform. والآن، لجعل تطبيق Express أسرع وأكثر قابلية للتوسع، سوف ننفذ ثلاث استراتيجيات للتخزين المؤقت للكائنات. ستحتاج إلى ذاكرة تخزين مؤقت Cache، والتي سننشئها في الخطوة التالية. الخطوة الخامسة، إعداد ذاكرة تخزين مؤقت للكائنات باستخدام MemCachier في هذه الخطوة، سننشئ ونضبط إعدادات ذاكرة تخزين مؤقت للكائنات. يمكنك استخدام أي ذاكرة تخزين مؤقت متوافقة مع memcached. سنستخدم في مقالنا إضافة MemCachier من متجر DigitalOcean. وذاكرة التخزين المؤقت MemCachier هي عبارة عن ذاكرة تخزين مؤقت تخزن البيانات على هيئة قيمة-مفتاح. أولًا، علينا إضافة MemCachier من متجر Digital Ocean، وللقيام بذلك انتقل إلى صفحة إضافة MemCachier، ثم انقر على Add MemCachier، ثم اختر المنطقة المناسبة لتطبيقك، يجب أن تختار المنطقة نفسها للتطبيق والذاكرة كي تخفف من التأخير بقدر الإمكان. كما يمكنك مراجعة إعدادات التطبيق للتأكد من المنطقة واختيار اشتراك معين. ثم، انقر على Add MemCachier لإضافة الذاكرة المؤقتة. ملاحظة: لمعرفة اختصارات اسماء المناطق، ننصحك بزيارة مركز بيانات DigitalOcean، فمثلًا منطقة سان فرانسيسكو اختصارها هو sfo3. والآن، عليك ضبط إعدادات التطبيق لاستخدام الذاكرة. انتقل إلى لوحة تحكم الإضافات Add-Ons dashboard ثم انقر على إضافة MemCachier للانتقال إلى لوحة التحكم. بعدها، انقر على زر عرض Show متغيرات الإعدادات Configuration Variables لعرض القيم التالية MEMCACHIER_USERNAME، MEMCACHIER_PASSWORD، MEMCACHIER_SERVERS. انتبه على هذه القيم لأننا سنحتاجها لاحقًا. سنحفظ الآن متغيرات إعدادات MemCachier كمتغيرات بيئة للتطبيق. انتقل إلى لوحة تحكم التطبيق ثم انقر على الإعدادات Settings. ثم من Components انقر على express-memc وانتقل لقسم متغيرات البيئة Environment Variables وانقر على تعديل Edit ثم أضف متغيرات إعدادات MemCachier ذات المفاتيح: (MEMCACHIER_USERNAME، MEMCACHIER_PASSWORD، MEMCACHIER_SERVERS) وأضف القيم كل منها وفقًا للقيم الموجودة في لوحة تحكم MemCachier> انقر على خيار التشفير Encrypt بجانب المفتاح MEMCACHIER_PASSWORD لتشفير كلمة المرور، ثم انقر على حفظ Save. والآن، علينا ضبط عميل ذاكرة memcache client في التطبيق باستخدام المتغيرات التي أدخلنا كي يستطيع التطبيق التخاطب مع الذاكرة. ثبّت المكتبة memjs في الطرفية: npm install memjs ثم أنشأ مجلد خدمات services، وأنشأ فيه الملف services/memcache.js وافتحه في المحرر. ثم استورد مكتبة memjs في أعلى الملف واضبط إعدادات عميل الذاكرة cache client: const { Client } = require('memjs'); module.exports = Client.create(process.env.MEMCACHIER_SERVERS, { failover: true, timeout: 1, keepAlive: true, }); ولا تنسَ حفظ الملف. تنشأ الشيفرة السابقة عميل لذاكرة التخزين المؤقتة MemCachier. أما بالنسبة للخيار failover، ضبطناه على القيمة true لاستخدام مجموعة حواسيب MemCachier عالية التوفر في حال حدوث الفشل. إذ إنه في حالة فشل الخادم، ستُرسل أوامر المفاتيح المخزنة على هذا الخادم تلقائيًا إلى الخادم التالي المتاح. ينصح باستخدام مهلة timeout مدتها ثانية واحدة إذ إنها أفضل للتطبيقات المنشورة من المهلة الافتراضية البالغة 0.5 ثانية. أما السطر keepAlive: true فيبقي الاتصال مع ذاكرة التخزين المؤقت مفتوحًا حتى في وضع الخمول، وهو أمر محبّذ لأن عملية إجراء الاتصال بطيئة، ويجب أن تكون ذاكرة التخزين المؤقت سريعة لتكون فعالة. حصلنا في هذه الخطوة على ذاكرة تخزين مؤقت باستخدام إضافة MemCachier من متجر DigitalOcean. ثم أضفنا إعدادات ذاكرة التخزين المؤقت كمتغيرات بيئة في منصة التطبيقات، كي نستطيع إعداد عميل باستخدام مكتبة memjs ويتمكن التطبيق من الاتصال بذاكرة التخزين المؤقت. والآن، أصبحنا جاهزين لتطبيق للتخزين المؤقت في Express، وهو ما سنتعلمه في خطوتنا التالية. الخطوة السادسة، تطبيق تقنيات التخزين المؤقت في Express باستخدام إضافة MemCachier أصبح بإمكانك الآن استخدام ذاكرة التخزين المؤقت للكائنات بعد نشر التطبيق وإضافة ميزة التخزين المؤقت MemCachier. إذ سننفذ في هذه الخطوة ثلاث تقنيات للتخزين المؤقت للكائنات. سنبدأ بالتخزين المؤقت للعمليات ذات الاستخدام الكثيف للموارد لتحسين سرعة الاستخدام وكفاءته. بعد ذلك، سنطبق تقنيات لتخزين طرق العرض المصيّرة بعد الإدخال لتحسين معالجة الطلب وتخزين الجلسات القصيرة مؤقتًا لإتاحة المجال لتوسيع نطاق تطبيقك فيما بعد. التخزين المؤقت للعمليات ذات الاستخدام الكثيف للموارد سنخزن العمليات الحوسبية ذات الاستخدام الكثيف للموارد تخزينًا مؤقتًا لتسريع التطبيق، مما يؤدي إلى استخدام وحدة المعالجة المركزية بكفاءة أكبر. إذ تُعد الدالة findPrime عملية حسابية تستخدم الموارد بكثافة عند إدخال عدد كبير. سنخزن نتائج الدالة مؤقتًا عند توفرها بدلاً من تكرار العملية الحسابية. أولاً، افتح ملف server.js لإضافة عميل الذاكرة memcache: const express = require('express'); const findPrime = require('./utils/findPrime'); const memcache = require('./services/memcache'); ... ثم خزّن عددًا أوليًا محسوبًا من قبل في الذاكرة المؤقتة كما يلي: ... const prime = findPrime(n); const key = 'prime_' + n; memcache.set(key, prime.toString(), { expires: 0 }, (err) => { if (err) console.log(err); }); ... ولا تنسَ حفظ الملف. لاحظ أن التابع set يقبل مفتاحًا key كوسيط أول، وقيمة للسلسلة أي value كوسيطه الثاني. لذا حولنا العدد الأولي إلى سلسلة، أما الشرط الثالث فيحرص على عدم انتهاء مدة العنصر المُخزّن، والشرط الرابع والأخير هو تابع استدعاء اختياري عند حدوث خطأ ما. ملاحظة1: يجب التعامل مع أخطاء ذاكرة التخزين المؤقت بحذر. إذ تعد هذه ذاكرة بمثابة تحسين ويجب ألا تؤدي إلى تعطل التطبيق. في من الممكن أن يعمل التطبيق على نحو جيد، وإن كان أبطأ، بدون ذاكرة التخزين المؤقت. ملاحظة 2: بإمكان التطبيق الآن العمل محليًا ولكن بدون تخزين مؤقت، وسيظهر خطأ في الخرج عند استدعاء memcache.set لأن التطبيق لن يستمكن من إيجاد خادم تخزين مؤقت، وستحصل حينها على خرج مشابه للتالي: Output MemJS: Server <localhost:11211> failed after (2) retries with error - connect ECONNREFUSED 127.0.0.1:11211 Error: No servers available ... لن تحتاج إلى التخزين المحلي لإكمال باقي خطوات المقال. إذا يمكنك تشغيل localhost:11211 في العنوان الذي يُعد العنوان الافتراضي لـ memjs. والآن، عليك إيداع التغييرات: git add . && git commit -m "Add memjs client and cache prime number" ثم أضف هذه التغييرات إلى غيت هب، والتي ستُنشر إلى منصة التطبيقات تلقائيًا: git push ستظهر رسالة على لوحة تحكم منصة التطبيقات تشير إلى أن تطبيقك قيد الإنشاء، بعد أن كانت حالته Deployed أي منشور. وعند اكتمال إنشاء التطبيق، افتح التطبيق في متصفحك وأدخل عددًا للعثور على أكبر عدد أولي أصغر أو مساوٍ له. ملاحظة: قد تظهر رسالة "Waiting for service" على لوحة التحكم، وتعني حالة انتظار الخدمة، وهذه الرسالة ستختفى من تلقاء نفسها، ولكن إن طال ظهورها عليك تحديث التطبيق للتأكد أن التطبيق قد نُشر بعد اكتمال إنشائه. والآن، عليك الرجوع إلى صفحة إضافات لوحة التحكم ثم النقر على View MemCachier لعرض لوحة تحليلات ذاكرة التخزين المؤقت. في هذه اللوحة، زدنا الخيار Set Cmds في لوحة All Time Stats وحالة العناصر Items في لوحة التخزين Storage بمقدار 1. في كل مرة ترسل عددًا، سيزداد كل من Set Cmds وItems. ويجب عليك الضغط على زر التحديث لتحميل الإحصائيات الجديدة. ملاحظة: يُعد التحقق من سجلات التطبيق على منصة App Platform أمرًا مفيدًا لتصحيح الأخطاء. يمكنك النقر من لوحة تحكم التطبيق على Runtime Logs لعرض الأخطاء. يمكن الاستفادة من العناصر المخزنة في الذاكرة المؤقتة. ستتحقق الآن مما إذا كان العنصر قد خُزّن مسبقًا، وإذا كان الأمر كذلك، فسوف يُعرض من ذاكرة التخزين المؤقت، وإلا سيبحث التطبيق عن العدد الأولي كما في السابق. عّدل ملف server.js، إذ عليك تعديل بعض الأسطر وإضافة بعد الاسطر الجديدة كما يلي: ... app.get('/', (req, res) => { const n = req.query.n; if (!n) { res.render('index'); return; } let prime; const key = 'prime_' + n; memcache.get(key, (err, val) => { if (err) console.log(err); if (val !== null) { // Use the value from the cache // Convert Buffer string before converting to number prime = parseInt(val.toString()); } else { // No cached value available, find it prime = findPrime(n); memcache.set(key, prime.toString(), { expires: 0 }, (err) => { if (err) console.log(err); }); } // Initialize likes for this number when necessary if (!likesMap[n]) likesMap[n] = 0; const locals = { n, prime, likes: likesMap[n] }; res.render('index', locals); }); }); ... تهيئ الشبفرة السابقة العدد الأولي prime بدون قيمة، باستخدام الكلمة المفتاحية Let، حيث أُعيدَ تعيين قيمتها. ثم يحاول تابع memcache.get استرداد العدد الأولي المخزن. توجد معظم شيفرة المتحكم الآن في تابع الاستدعاء memcache.get لأن نتيجته لازمة لتحديد كيفية التعامل مع الطلب. فإن كان ثمة قيمة مخزنة متاحة، فعليه استخدامها، وإلا عليه إجراء الحسابات اللازمة للعثور على العدد الأولي وتخزين النتيجة في ذاكرة التخزين المؤقت. إن القيمة التي يستدعيها تابع الاستدعاء memcache.get هي قيمة تخزين مؤقتة Buffer، لذا عليك تحويلها إلى سلسلة قبل تحويل التابع prime إلى عدد. أودع التغييرات ثم ادفعها إلى غيت هب لتنشرها: git add . && git commit -m "Check cache for prime number" && git push عندما ترسل رقمًا لم يخزّن بعد في التطبيق، ستزداد إحصائيات Set Cmds وحالة العناصر Items وإحصائيات الأخطاء get misses في لوحة تحكم MemCachier بمقدار 1. تحدث حالة الخطأ miss عند محاولة الحصول على العنصر من ذاكرة التخزين المؤقت قبل تعيينه، فالعنصر غير موجود في ذاكرة التخزين المؤقت، مما يؤدي إلى حدوث خطأ، ثم يخزّن العنصر بعد ذلك. عند إدخال عدد مخزّن مسبقًا، سيزداد عدد مرات الحصول على النتائج get hits. وهكذا نكون قد خزّنا العمليات ذات الاستخدام الكثيف للموارد تخزينًا مؤقتًا. بعد ذلك، سنخزّن طرق عرض التطبيق المصيّرة مؤقتًا. تخزين طرق العرض المصيّرة سنخزّن الآن طرق عرض التطبيق مؤقتًا باستخدام برنامج وسيط. أعددنا في خطوة سابقة ejs كمولد قوالب وأنشأنا قالبًا لعرض كل رقم مُدخل n. قد يستهلك إنشاء العرض كثيرًا من الموارد، لذا فإن تخزينه مؤقتًا يمكن أن يسرع معالجة الطلب ويستخدم موارد أقل. أولًا، أنشئ مجلدًا للبرنامج الوسيط وسمّه middleware. ثم أنشئ الملف middleware/cacheView.js وافتحه في المحرر. ثم أضف هذه الأسطر في ملف CacheView.js لدالة البرنامج الوسيط: const memcache = require('../services/memcache'); /** * Express middleware to cache views and serve cached views */ module.exports = function (req, res, next) { const key = `view_${req.url}`; memcache.get(key, (err, val) => { if (err) console.log(err); if (val !== null) { // Convert Buffer string to send as the response body res.send(val.toString()); return; } }); }; استوردنا في الشيفرة السابقة عميل الذاكرة memcache. ثم عرفنا عن مفتاح، مثل view_/?n=100. وبعدها، تحققنا من وجود عرض لهذا المفتاح في ذاكرة التخزين المؤقت باستخدام التابع memcache.get. إذا لم يكن هناك خطأ ووُجدت قيمة لهذا المفتاح، ينتهي الطلب عن طريق إرسال العرض مرةً أخرى إلى العميل. بعد ذلك، إذا لم يكن العرض مخزنًا، فعليك تخزينه مؤقتًا، عن طريق تعديل override التابع res.send بإضافة الأسطر التالية على ملف middleware/cacheView.js: const originalSend = res.send; res.send = function (body) { memcache.set(key, body, { expires: 0 }, (err) => { if (err) console.log(err); }); originalSend.call(this, body); }; يجب أن يصبح محتوى الملف middleware/cacheView.js كالتالي: const memcache = require('../services/memcache'); /** * Express middleware to cache views and serve cached views */ module.exports = function (req, res, next) { const key = `view_${req.url}`; memcache.get(key, (err, val) => { if (err) console.log(err); if (val !== null) { // Convert Buffer string to send as the response body res.send(val.toString()); return; } const originalSend = res.send; res.send = function (body) { memcache.set(key, body, { expires: 0 }, (err) => { if (err) console.log(err); }); originalSend.call(this, body); }; }); }; يمكنك تعديل التابع res.send باستعمال دالة تخزن العرض في ذاكرة التخزين المؤقت قبل استدعاء دالة الإرسال الأساسية send كالمعتاد. إذ يمكنك استدعاء دالة الإرسال الأساسية send باستخدام تابع الاستدعاء call الذي يستخدم this والذي يعبر عن context الحالي بعد تعليمة الذاكرة memcache.set. احرص على استخدام دالة مجهولة (وليس دالة سهمية)، كي تحدد قيمة this الصحيحة. بعد ذلك، مرر التحكم إلى البرنامج الوسيط عن طريق إضافة الأمر next: ... /** * Express middleware to cache views and serve cached views */ module.exports = function (req, res, next) { const key = `view_${req.url}`; memcache.get(key, (err, val) => { if (err) console.log(err); if (val !== null) { // Convert Buffer to UTF-8 string to send as the response body res.send(val.toString()); return; } const originalSend = res.send; res.send = function (body) { memcache.set(key, body, { expires: 0 }, (err) => { if (err) console.log(err); }); originalSend.call(this, body); }; next(); }); }; ... إن إضافة التابع next يؤدي استدعاء دالة البرنامج الوسيط التالي في التطبيق. لكن لا يوجد في مثالنا برامج وسيط آخر، لذلك يُستدعى المتحكم controller. يوّلد التابع res.render الخاص بـ Express صفحة عرض view، ثم يستدعي التابع res.send داخليًا باستخدام طريقة العرض. والآن، في وحدة تحكم المسار الرئيسي، يُستدعى تابع التعديل override عند استدعاء res.render، ليخزّن العرض في ذاكرة التخزين المؤقت قبل استدعاء دالة send الأصلية لإكمال الرد. ملاحظة: يمكنك تمرير استدعاء للتابع render في المتحكم، ولكن عليك تكرار شيفرة التخزين المؤقت للعرض في وحدة التحكم لكل مسار يخزن مؤقتًا. والآن، استورد البرنامج الوسيط في الملف server.js: const express = require('express'); const findPrime = require('./utils/findPrime'); const memcache = require('./services/memcache'); const cacheView = require('./middleware/cacheView'); ... ثم أضف الوسيط cacheView لاستخدامه في المسار الرئيسي مع التابع / Get: ... app.get('/', cacheView, (req, res) => { ... }); ... ثم أودع التغييرات وادفعها إلى غيت هب لنشرها: git add . && git commit -m "Add view caching" && git push عند إدخال عدد جديد، ستزداد إحصائيات لوحة تحكم MemCachier لكل من Set Cmds وItems وget misses بمقدار اثنين: مرة لحساب العدد الأولي ومرة للعرض. عند تحديث التطبيق بنفس الرقم، فسترى زيادةً بمقدار 1 في get hit لوحة التحكم. لأن صفحة العرض استُرِدت من ذاكرة التخزين المؤقت، لذلك لا توجد حاجة لجلب نتيجة العدد الأولي من التطبيق ملاحظة: إن خيار view cache مفعّل تلقائيًا في الإنتاج، لكن هذا الخيار لا يخزن محتوى خرج القالب، بل يخزن القالب فقط.ويعاد عرض الصفحة مع كل طلب، حتى عندما تكون ذاكرة التخزين المؤقت قيد التشغيل. إذًا فخيار view cache، مختلف ولكنه مكمل للتخزين المؤقت للعرض الذي طبقناه. قد تلاحظ بعد أن خزّنا العرض أن زر الاعجاب لا يعمل. إذا سجلت عدد الإعجابات، فستلاحظ أنها تتغير وتزداد، لكن العرض المخزّن بحاجة إلى التحديث عندما يتغير عدد الإعجابات. إذًا يجب إيقاف العرض المخزن مؤقتًا عند تغيير العرض. ثم سنوقف العرض المخزّن عندما يتغير عدد الإعجابات likes وذلك عن طريق حذفه من ذاكرة التخزين المؤقت. عدّل دالة إعادة التوجيه redirect في ملف server.js عن طريق إضافة الأسطر التالية: likesMap[n]++; // The URL of the page being 'liked' const url = `/?n=${n}`; res.redirect(url); لتصبح الدالة كما يلي: ... app.get('/like', (req, res) => { const n = req.query.n; if (!n) { res.redirect('/'); return; } likesMap[n]++; // The URL of the page being 'liked' const url = `/?n=${n}`; res.redirect(url); }); ... بعد تغير عدد الاعجابات في صفحة العرض، ستصبح النسخة المخزنة غير صالحة، لذا أضف الأسطر التالية لحذف عدد الإعجابات من ذاكرة التخزين المؤقت عندما تتغير الإعجابات likes: ... const url = `/?n=${n}`; // The view for this URL has changed, so the cached version is no longer valid, delete it from the cache. const key = `view_${url}`; memcache.delete(key, (err) => { if (err) console.log(err); }); res.redirect(url); ... يجب أن يكون ملف server.js مماثلًا لما يلي: const express = require('express'); const findPrime = require('./utils/findPrime'); const memcache = require('./services/memcache'); const cacheView = require('./middleware/cacheView'); const app = express(); app.set('view engine', 'ejs'); /** * Key is `n` * Value is the number of 'likes' for `n` */ const likesMap = {}; app.get('/', cacheView, (req, res) => { const n = req.query.n; if (!n) { res.render('index'); return; } let prime; const key = 'prime_' + n; memcache.get(key, (err, val) => { if (err) console.log(err); if (val !== null) { // Use the value from the cache // Convert Buffer string before converting to number prime = parseInt(val.toString()); } else { // No cached value available, find it prime = findPrime(n); memcache.set(key, prime.toString(), { expires: 0 }, (err) => { if (err) console.log(err); }); } // Initialize likes for this number when necessary if (!likesMap[n]) likesMap[n] = 0; const locals = { n, prime, likes: likesMap[n] }; res.render('index', locals); }); }); app.get('/like', (req, res) => { const n = req.query.n; if (!n) { res.redirect('/'); return; } likesMap[n]++; // The URL of the page being 'liked' const url = `/?n=${n}`; // The view for this URL has changed, so the cached version is no longer valid, delete it from the cache. const key = `view_${url}`; memcache.delete(key, (err) => { if (err) console.log(err); }); res.redirect(url); }); const port = process.env.PORT || 3000; app.listen(port, () => console.log(`Example app is listening on port ${port}.`) ); لا تنسَ حفظ الملف، ثم أودع التغييرات وادفعها للنشر: git add . && git commit -m "Delete invalid cached view" && git push والآن سيعمل زر الاعجاب في التطبيق وستتغير الإحصائيات التالية في لوحة تحكم MemCachier عند النقر على الزر: delete hits تزداد عند حذف العرض. get misses تزداد عند حذف العرض وعدم وجوده في ذاكرة التخزين المؤقت. get hits تزداد عند العثور على العدد الأولي في ذاكرة التخزين المؤقت. Set Cmds تزداد عند إضافة العرض إلى ذاكرة التخزين المؤقت. Items تبقى على حالها عند حذف أو إضافة العرض. وهكذا نكون قد طبقنا التخزين المؤقت للعرض وأبطلنا استخدام صفحات العرض المخزنة عند تغييرها. أما التقنية الأخيرة التي سننفذها هي التخزين المؤقت للجلسة. التخزين المؤقت للجلسات سنتعلم في هذه الفقرة كيفية إضافة جلسات Sessions وتخزينها مؤقتًا في تطبيق Express، مما يجعل ذاكرة التخزين المؤقت مخزنًا للجلسات. وحيث إن إحدى الاستخدامات الشائعة للجلسات هي تسجيل دخول المستخدم user login، لذا يمكننا اعتبار هذه الفقرة خطوةً أوليةً لتنفيذ نظام تسجيل دخول المستخدم في المستقبل (على الرغم من أن نظام تسجيل دخول المستخدم خارج عن نطاق مقالنا). يمكن أن يكون تخزين الجلسات قصيرة الأمد في ذاكرة التخزين المؤقت أسرع وأكثر قابليةً للتوسع من تخزينها في قواعد البيانات. ملاحظة: تعتبر ذاكرة التخزين المؤقت مثالية لتخزين الجلسات القصيرة التي انتهت مدتها. ومع ذلك، فإن ذاكرة التخزين المؤقت ليست دائمة؛ لذا تعد حلول التخزين الدائمة كقواعد البيانات أكثر ملاءمةً لتخزين الجلسات طويلة الأمد. والآن، ثبّت أداة الجلسات express-session كي تضيف جلسات إلى التطبيق وإلى مكتبة connect-memjs لاستخدام MemCachier كمخزن للجلسات: npm install express-session connect-memjs استورد ملف express-session و connect-memjs إلى ملف server.js: const express = require('express'); const findPrime = require('./utils/findPrime'); const memcache = require('./services/memcache'); const cacheView = require('./middleware/cacheView'); const session = require('express-session'); const MemcacheStore = require('connect-memjs')(session); ... تُمرَر جلسة البرنامج الوسيط يتم تمرير البرنامج الوسيط للجلسة إلى وحدة الاتصال connect في memcached، مما يسمح لها بالوراثة من Express.session.Store. عدّل إعدادات البرنامج الوسيط للجلسة كي يستخدا ذاكرة التخزين المؤقت كمخزن له، وذلك بإضافة الأسطر التالية: ... app.set('view engine', 'ejs'); app.use( session({ secret: 'your-session-secret', resave: false, saveUninitialized: true, store: new MemcacheStore({ servers: [process.env.MEMCACHIER_SERVERS], prefix: 'session_', }), }) ); ... يستخدم secret لتسجيل ملفات تعريف الارتباط للجلسة أو ما يُعرف باسم cookie. لا تنسَ استبدال your-session-secret بسلسلة مميزة. ملاحظة: يجب استخدام متغيرات البيئة لضبط secret لمراحل الإنتاج، وذلك بإضافة السطر secret: process.env.SESSION_SECRET || 'your-session-secret' لكن عندها يجب ضبط متغير البيئة في لوحة تحكم App Platform. يجبر الأمر Resave الجلسة على إعادة الحفظ إذا تُعدَل أثناء الطلب. ولأننا لا نريد تخزين العنصر في الذاكرة التخزين المؤقت مرة أخرى، لذا علينا ضبط قيمته على false. saveUninitialized: false is useful when you only want to save modified sessions, as is often the case with login sessions where a user property might be added to the session after authentication. In this case, you will store all sessions indiscriminately, so you set it to true. يُعد الأمر saveUninitialized: false مفيدًا لحفظ الجلسات المعدلة فقط، كما هو الحال غالبًا مع جلسات تسجيل الدخول، حيث يمكن إضافة خاصية مستخدم إلى الجلسة بعد المصادقة، حينها سنخزّن جميع الجلسات بصورة عشوائية، لذلك سنضبطها على القيمة true. أخيرًا، اربط قيمة store مع ذاكرة التخزين المؤقتة، واضبط بادئة ذاكرة التخزين المؤقت للجلسة على ._session وهذا يعني أن مفتاح عنصر الجلسة في الذاكرة سيبدو كالتالي: session_<session ID>. بعدها، أضف برامجًا وسيطًا لتصحيح الأخطاء على مستوى التطبيق، والتي ستساعد في تحديد الجلسات المخزنة قيد التنفيذ: ... app.use( session({ ... }) ); /** * Session sanity check middleware */ app.use(function (req, res, next) { console.log('Session ID:', req.session.id); // Get the item from the cache memcache.get(`session_${req.session.id}`, (err, val) => { if (err) console.log(err); if (val !== null) { console.log('Session from cache:', val.toString()); } }); next(); }); ... وهكذا سيسجل البرنامج الوسيط معرف الجلسة لكل طلب. ثم سيحصل على جلسة هذا المعرف من ذاكرة التخزين المؤقت ويسجل محتوياتها. حيث توضح هذه الطريقة أن الجلسات تعمل وتخزّن. احفظ الملف، ثم أودع التغييرات وادفعها للنشر: git add . && git commit -m "Add session caching" && git push أدخل رقمًا في التطبيق ثم تحقق من سجلات وقت التشغيل **Runtime Logs ** في لوحة التحكم للوصول إلى رسائل تصحيح الأخطاء. ستجد معرف الجلسة والقيمة التي سجلتها، مما يوضح أن الجلسات تعمل وتخزّن بصورة صحيحة. في لوحة تحكم MemCachier، عند تخزين العرض والجلسة، سترى ثلاث نتائج لكل تحديث للصفحة: واحدة لصفحة العرض، وواحدة للجلسة، وواحدة لجلسة برنامج تصحيح الأخطاء الوسيط. والآن، يمكنك التوقف عند هذه الخطوة، أو يمكنك الاطلاع على الخطوة السابعةالإضافية. الخطوة السابعة، حذف الموارد (اختيارية) ثمة رسوم عليك دفعها عند نشر التطبيق على منصة App platform، لذا يمكنك حذف التطبيق وإضافة MemCachier عند الانتهاء. انقر على الإجراءات Actions من لوحة التحكم ثم انقر على حذف التطبيق Destroy App. لحذف إضافة MemCachier، انقر على الإضافات Add-Ons، ثم على MemCachier، وانقر بعدها على الإعدادات والحذف Settings and Destroy. تلغى ذاكرة MemCachier المجانية بعد 30 يومًا من عدم استخدامها، ولكن يُعد تنظيف الادوات أمرًا جيدًا. ختامًا تعلمنا في مقالنا كيفية إنشاء تطبيق Express للعثور على عدد أولي باستخدام وكيفية إضافة زر "أعجبني". ثم رفعنا هذا التطبيق على غيت هب ونشرناه على منصة تطبيقات DigitalOcean. ثم سرّعنا التطبيق وجعلناه قابلًا للتوسع من خلال تنفيذ ثلاث تقنيات للتخزين المؤقت للكائنات باستخدام إضافة MemCachier للتخزين المؤقت للعمليات ذات الاستخدام الكثيفة للموارد، ومن خلال العرض view، والجلسات sessions. يمكنك الاطلاع على ملفات هذا المقال في مستودع مجتمع DigitalOcean، تحتوي المفاتيح في كل استراتيجيات التخزين المؤقت التي نفذناها على بادئة: _prime و _view و _session prime_ و view_ وsession_. بالإضافة إلى ميزة فضاء الاسم، توفر البادئة فائدةً إضافيةً وهي السماح بتحديد أداء ذاكرة التخزين المؤقت. استخدمنا في مقالنا شريحة المطورين developer plan في MemCachier، ولكن يمكنك تجربة شريحة مُدارة بالكامل تأتي مع مجموعة ميزات االفحص الدقيق Introspection، مما يتيح لك تتبع أداء البادئات الفردية. على سبيل المثال، يمكنك مراقبة معدل النقر hit rate أو نسبة النقر hit ratio على أي بادئة، مما يوفر رؤية تفصيلية لأداء ذاكرة التخزين المؤقت. إن أردت متابعة استخدام MemCachier، يمكنك مراجعة التوثيقات التالية. إذا واجهت مشاكلًا عند تطبيق إحدى هذه الخطوات، يمكنك الحصول على الدعم والمساعدة عبر إضافة سؤالك في قسم الأسئلة والأجوبة في أكاديمية حسوب. ترجمة -وبتصرف- [للمقال ](How To Deploy an Express Application and Scale with MemCachier on DigitalOcean App Platform) من موقع DigitalOcean لكاتبيه Patrick O'Hanlon و Caitlin Postal. اقرأ أيضًا مدخل إلى إطار عمل الويب Express وبيئة Node دليل استخدام Node.js وإطار العمل Express للمبتدئين نشر تطبيق Express في بيئة الإنتاج مقدمة إلى القوالب Template في Express: إنشاء القالب الأساسي لموقع مكتبة محلية مثالًا