اذهب إلى المحتوى

kinan mawed

الأعضاء
  • المساهمات

    45
  • تاريخ الانضمام

  • تاريخ آخر زيارة

كل منشورات العضو kinan mawed

  1. سنتعلّم في هذا الدّرس كيفيّة استخدام HAProxy (والذي يرمز إلى الوسيط عالي التوفّر High Availability Proxy) كمُوازِن حمل عن طريق الطبقة السّابعة layer 7 load balancer من أجل تخديم تطبيقات متعدّدة من اسم مجال واحد Single Domain أو عنوان IP، بإمكان موازنة الحمل أن تزيد أداء، توفّر، ومرونة بيئتنا. تكون موازنة الحمل والوسيط العكسي للطبقة 7 ملائمة لموقعك إن أردت أن تملك اسم نطاق واحد يقوم بتخديم تطبيقات متعدّدة، حيث يمكن تحليل طلبات http لتقرّر أي تطبيق ينبغي عليه أن يستقبل حركة مرور البيانات. تمّت كتابة هذا الدّرس باستخدام ووردبريس وموقع ثابت Static website كأمثلة، ولكن يمكن استخدام مفاهيمه العامّة مع تطبيقات أخرى للحصول على تأثير مماثل. المتطلبات الأساسية قبل متابعة هذا الدّرس ينبغي عليك أن تملك تطبيقين على الأقل يعملان على خادومين منفصلين، سنستخدم موقعًا ثابتًا مستضافًا على Nginx و ووردبريس كتطبيقين لدينا، وبالإضافة للبيئة الحاليّة لديك سنقوم بإنشاء الخواديم التالية: haproxy-www: وهو خادوم HAProxy لأجل موازنة الحمل والوسيط العكسي wordpress-2: وهو خادوم الويب الثاني لووردبريس (تحتاجه فقط إن أردت موازنة حمل مكونات ووردبريس في بيئتك) web-2: خادوم ويب Nginx الثاني (تحتاجه فقط إن أردت موازنة حمل مكونات Nginx في بيئتك) إن لم يسبق لك التّعامل مع المفاهيم أو المصطلحات الأساسيّة لموازنة الحمل، مثل موازنة الحمل عن طريق الطبقة 7 أو الواجهات الخلفيّة backends أو قوائم تحكّم الوصول ACLs فهذا هو الدّرس الذي يشرح الأساسيّات: مقدّمة إلى HAProxy ومبادئ موازنة الحمل (Load Balancing). هدفنا بنهاية هذا الدّرس نريد أن نحصل على بيئة تبدو كما يلي: أي سيقوم المستخدمون لديك بالنفاذ لكلا تطبيقيك عبر http://example.com، وسيتم تمرير كل الطلبات التي تبدأ بـ http://example.com/wordpress إلى خواديم ووردبريس، ويتم تمرير جميع باقي الطلبات إلى خواديم Nginx الأساسيّة، لاحظ أنّه لا تحتاج بالضرورة لموازنة حمل تطبيقاتك حتى تظهر على مجال واحد، ولكن سنقوم بتغطية موازنة الحمل في هذا الدّرس. تثبيت HAProxy نقوم بإنشاء خادوم جديد مع الشّبكات الخاصّة، سنسمّيه في هذا الدّرس haproxy-www. نقوم بتثبيت HAProxy على الخادوم haproxy-www باستخدام apt-get: sudo apt-get update sudo apt-get install haproxy نحتاج لتمكين سكريبت التهيئة init script لـ HAProxy كي يبدأ ويتوقف HAProxy مع الخادوم لدينا: sudo vi /etc/default/haproxy نغيّر قيمة ENABLED إلى 1 لتمكين سكريبت التهيئة لـ HAProxy: ENABLED=1 نقوم بالحفظ والخروج، سيبدأ ويتوقف HAProxy الآن مع خادومنا، نستطيع أيضًا الآن استخدام الأمر service للتحكّم بـ HAProxy، فلنتحقّق من أنّه قيد التشغيل: user@haproxy-www:/etc/init.d$ sudo service haproxy status haproxy not running. نجد أنّه لا يعمل، لا مشكلة لأنّه يحتاج إلى إعداده قبل أن نتمكّن من استخدامه، فلنقم الآن بإعداد HAProxy لأجل بيئتنا. إعداد HAProxy يكون ملف إعدادات HAProxy مُقسّمًا إلى قسمين رئيسيين: العمومي Global: يقوم بتعيين المُعامِلات parameters على نطاق العمليّة الوسطاء Proxies: يتكون من المُعامِلات الافتراضيّة defaults، الاستماع listen، الواجهة الأماميّة frontend، والواجهة الخلفيّة backend. مرّة أخرى إن لم يسبق لك أن سمعت عن مفاهيم أو المصطلحات الأساسيّة لموازنة الحمل، فقم بالرجوع إلى هذا الدّرس: مقدّمة إلى HAProxy ومبادئ موازنة الحمل (Load Balancing). إعداد HAProxy: العمومي يجب أن يتم ضبط إعدادات HAProxy على الخادوم haproxy-www. في البداية لنقم بعمل نسخة من الملف haproxy.cfg الافتراضي: cd /etc/haproxy; sudo cp haproxy.cfg haproxy.cfg.orig نقوم الآن بفتح الملف haproxy.cfg باستخدام مُحرِّر نصوص: sudo vi /etc/haproxy/haproxy.cfg سنشاهد وجود قسمين معرّفين مسبقًا: global و defaults، سنلقي نظرة في البداية على بعض المعاملات القياسية default. تحت القسم defaults نبحث عن الأسطر التالية: mode http option httplog يقوم اختيار http كوضع بضبط HAProxy ليعمل كموازن حمل عن طريق الطبقة 7 (أو طبقة التطبيقات)، يعني هذا أنّ موازن الحمل سينظر إلى محتوى طلبات http ويقوم بتمريرها إلى الخادوم المناسب اعتمادًا على القواعد المعرّفة في الواجهة الأماميّة frontend، إن لم يكن هذا المفهوم مألوفًا لديك فمن فضلك اقرأ قسم أنواع موازنة الحمل في درس مقدّمة إلى HAProxy. لا تقم بإغلاق ملف الإعدادات الآن، لأنّنا سنضيف إعدادات الوسيط. إعداد HAProxy: الوسطاء إعداد الواجهة الأماميّة أول شيء نريد إضافته هو واجهة أماميّة frontend، ولأجل إعداد أساسي لوسيط عكسي وموازنة حمل عن طريق الطبقة 7 سنحتاج لتعريف قائمة تحكّم وصول ACL تُستخدَم لتوجيه حركة مرور بياناتنا إلى خواديم الواجهة الخلفيّة المناسبة، هنالك العديد من قوائم تحكّم الوصول التي يُمكن استخدامها في HAProxy، سنغطي فقط واحدة منها في هذا الدّرس (وهي path_beg)، ولأجل الحصول على قائمة كاملة من قوائم تحكّم الوصول في HAProxy قم بمراجعة التّوثيق الرسميّ: HAProxy ACLs. نضيف واجهتنا الأماميّة www في نهاية الملف، تأكّد من أن تضع عنوان IP الخاص بخادوم haproxy-www لديك بدلًا من haproxy_www_public_IP: frontend www bind haproxy_www_public_IP:80 option http-server-close acl url_wordpress path_beg /wordpress use_backend wordpress-backend if url_wordpress default_backend web-backend وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الأماميّة: frontend www: يُعيِّن واجهة أماميّة اسمها "www"، حيث سنستخدمها للتعامل مع حركة مرور بيانات www الواردة. bind haproxy_www_public_IP:80: ضع عنوان IP خادوم haproxy-www لديك بدلًا من haproxy_www_public_IP، يُخبر هذا السطر HAProxy أنّ هذه الواجهة الأماميّة ستتعامل مع حركة مرور بيانات الشبكة الواردة إلى عنوان IP هذا على هذا المنفذ. option http-server-close: يقوم بتمكين وضع إغلاق اتصال HTTP على الخادوم، ويحافظ على القدرة على دعم ترويسة HTTP keep-alive وتقنيّة HTTP pipelining على العميل (وهي تقنيّة لإرسال العديد من طلبات HTTP ضمن اتصال TCP وحيد بدون انتظار الموافقة لها)، يسمح هذا الخيار بأن يقوم HAProxy بمعالجة طلبات متعدّدة للعميل ضمن اتصال وحيد، والذي عادة ما يزيد من الأداء. acl url_wordpress path_beg /wordpress: يُعيِّن قائمة تحكّم وصول ACL تُدعى url_wordpress والتي تكون قيمتها صحيحة true إن كان مسار الطلب يبدأ بـ "wordpress/"، على سبيل المثال http://example.com/wordpress/hello-world. use_backend wordpress-backend if url_wordpress: يقوم بإعادة توجيه أي حركة مرور بيانات تتوافق مع قائمة تحكّم الوصول url_wordpress إلى wordpress-backend، والتي سنقوم بتعريفها قريبًا. default_backend web-backend: يُحدِّد أنّه أي حركة مرور بيانات لا تتوافق مع قاعدة use_backend سيتم تمريرها إلى web-backend، والتي سنقوم بتعريفها في الخطوة القادمة. إعداد الواجهة الخلفية Backend بعد أن تنتهي من إعداد الواجهة الأماميّة، قم الآن إضافة واجهتك الخلفيّة الأولى عن طريق إضافة الأسطر التالية، تأكّد من أن تضع عنوان IP المناسب بدلًا من web_1_private_IP: backend web-backend server web-1 web_1_private_IP:80 check وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الخلفيّة: backend web-backend: يُعيِّن واجهة خلفيّة تُدعى web-backend. server web-1 ... : يُعيِّن خادوم واجهة خلفيّة يُدعى web-1، مع عنوان IP الخاص (وهو الذي يجب أن تستبدله) والمنفذ الذي يستمع عليه، وهو 80 في هذه الحالة، يُخبِر الخيار check مُوازِن الحمل أن يُجري دوريًّا تحقّق من السّلامة على هذا الخادوم. بعدها أضف الواجهة الخلفيّة لتطبيق ووردبريس لديك: backend wordpress-backend reqrep ^([^\ :]*)\ /wordpress/(.*) \1\ /\2 server wordpress-1 wordpress_1_private_IP:80 check وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الخلفيّة: backend wordpress-backend: يُعيِّن واجهة خلفيّة تُدعى wordpress-backend. reqrep ... : يعيد كتابة الطلبات من wordpress/ إلى / عند تمرير حركة مرور البيانات إلى خواديم ووردبريس، وهو ليس ضروريًّا إن كان تطبيق ووردبريس مُثبّتًا على جذر root الخادوم ولكن نحتاج إليه لقابلية النفاذ عبر wordpress/ على خادوم HAProxy. server wordpress-1 ... : يُعيِّن خادوم واجهة خلفيّة يُدعى wordpress-1، مع عنوان IP الخاص (وهو الذي يجب أن تستبدله) والمنفذ الذي يستمع عليه، وهو 80 في هذه الحالة، يُخبِر الخيار check مُوازِن الحمل أن يُجري دوريًّا تحقّق من السّلامة على هذا الخادوم. إعدادات HAProxy: الإحصائيات Stats إن أردت تمكين إحصائيّات HAProxy، والتي قد تكون مفيدة في تحديد كيفيّة تعامل HAProxy مع حركة مرور البيانات الواردة، ستحتاج إلى إضافة الأسطر التالية إلى إعداداتك: listen stats :1936 stats enable stats scope www stats scope web-backend stats scope wordpress-backend stats uri / stats realm Haproxy\ Statistics stats auth user:password وهذا شرح لما تعنيه الأسطر غير البديهيّة من المقطع السابق المأخوذ من إعدادات listen stats: listen stats :1936: يقوم بإعداد صفحة إحصائيّات HAProxy لتكون قابلة للنفاذ على المنفذ 1936 (أي http://haproxy_www_public_IP:1936). stats scope ... : يجمع الإحصائيّات على الواجهة المُحدّدة سواء كانت أماميّة أو خلفيّة. / stats uri: يُعيِّن رابط صفحة الإحصائيّات إلى / . stats realm Haproxy\ Statistics: يقوم بتمكين الإحصائيّات وتعيين اسم الاستيثاق realm Authentication (وهو استيثاق ذو نافذة منبثقة)، يُستخدَم بالترابط مع الخيار stats auth. stats auth haproxy:password: يُعيِّن اعتمادات credentials الاستيثاق لصفحة الإحصائيّات، قم بوضع اسم المستخدم وكلمة السّر الخاصّة بك. الآن قم بالحفظ والإغلاق، عند تشغيل HAProxy تكون صفحة الإحصائيّات متوفّرة عبر الرابط http://haproxy_www_public_ip:1936/ حالما تبدأ خدمة HAProxy لديك، تكون HAProxy جاهزة الآن لتشغيلها ولكن فلنقم بتمكين التسجيل logging أولًا. تمكين تسجيل HAProxy إنّ تمكين التسجيل في HAProxy بسيط جدًّا، قم في البداية بتحرير الملف rsyslog.conf: sudo vi /etc/rsyslog.conf ثم ابحث عن السطرين التاليين وأزل التعليق عنهما لتمكين استقبال UDP syslog، يجب أن تبدو كما يلي عند الفراغ منها: $ModLoad imudp $UDPServerRun 514 $UDPServerAddress 127.0.0.1 الآن أعد تشغيل rsyslog لتمكين الإعدادات الجديدة: sudo service rsyslog restart تم تمكين تسجيل HAProxy الآن، سيتم إنشاء ملف السّجل في المسار var/log/haproxy.log/ بعد أن يتم تشغيل HAProxy. تحديث إعدادات ووردبريس الآن وقد تم تغيير رابط تطبيق ووردبريس فيجب علينا تحديث بعض الإعدادات في ووردبريس. قم بتعديل الملف wp-config.php على أي خادوم ووردبريس، هذا الملف موجود في مكان تثبيت ووردبريس (في هذا الدّرس تم تثبيته على المسار var/www/example.com/ ولكن قد يكون مختلفًا لديك): cd /var/www/example.com; sudo vi wp-config.php ابحث عن السطر الموجود في بداية الملف الذي يحتوي على ('define('DB_NAME', 'wordpress وقم بإضافة الأسطر التالية فوقه مع استبدال http://haproxy_www_public_IP: define('WP_SITEURL', 'http://haproxy_www_public_IP'); define('WP_HOME', 'http://haproxy_www_public_IP'); قم بحفظ وإغلاق الملف، تمّ الآن إعداد روابط ووردبريس لتشير إلى موازن الحمل بدلًا من خادوم ووردبريس الأصلي والتي تلعب دورها عند محاولتك النفاذ إلى لوحة تحكم ووردبريس. تشغيل HAProxy قم بتشغيل HAProxy على الخادوم haproxy-www ليتم تطبيق تغييرات الإعدادات: sudo service haproxy restart إتمام الوسيط العكسي Reverse Proxy أصبحت الآن تطبيقاتنا قابلة للوصول إليها عبر نفس المجال، example.com، عبر الوسيط العكسي للطبقة 7، ولكن لم يتم تطبيق موازنة الحمل عليها بعد، تبدو الآن البيئة لدينا كالمخطط التالي: وفقًا للواجهة الأماميّة التي عرفناها سابقًا، هذا وصف حول كيفيّة تمرير HAProxy لحركة مرور البيانات: http://example.com/wordpress: سيتم إرسال أي طلب يبدأ بـ wordpress/ إلى wordpress-backend (والذي يتكون من الخادوم wordpress-1). http://example.com/: سيتم إرسال أيّة طلبات أخرى إلى web-backend (والذي يتكون من الخادوم web-1). إن كان كل ما تريد فعله هو استضافة تطبيقات متعدّدة على مجال وحيد فقد أنجزت هذا بنجاح، أمّا إن أردت موازنة حمل تطبيقاتك أكمل قراءة الدّرس. كيفية إضافة موازنة الحمل موازنة حمل الخادوم web-1 لموازنة حمل خادوم ويب أساسي، كل ما تحتاج إليه هو إنشاء خادوم ويب جديد يمتلك إعدادات ومحتوى مطابق لخادوم الأصلي، سندعو هذا الخادوم الجديد: web-2. لديك خياران عند إنشاء الخادوم الجديد: إن كنت تملك خيار إنشاء خادوم جديد انطلاقًا من صورة web-1، فهذه هي الطريقة الأبسط لإنشاء web-2. إنشاؤه من الصفر، تثبيت نفس البرمجيّات، إعداده بشكل مماثل، ومن ثمّ نسخ محتوى جذر خادوم Nginx من web-1 إلى web-2 باستخدام rsync (اقرأ درس كيف تستخدِم Rsync لمزامنة مجلّدات بين الجهاز المحلّي والخادوم). ملاحظة: إن كل من الطريقتين السابقتين تقوم بإنشاء نسخة لمحتويات جذر الخادوم مرّة وحيدة، لذلك إن قمت بتحديث أي من الملفّات على أحد خواديمك، web-1 أو web-2، فتأكّد من مزامنة الملفّات مرّة أخرى. بعد أن يتم إعداد خادوم ويب المماثل لديك، قم بإضافته إلى web-backend ضمن إعدادات HAProxy. على الخادوم haproxy-www قم بتحرير الملف haproxy.cfg: sudo vi /etc/haproxy/haproxy.cfg ابحث عن القسم web-backend من الإعدادات: backend web-backend server web-1 web_1_private_IP:80 check وبعدها أضف الخادوم web-2 في السطر التالي: server web-2 web_2_private_IP:80 check قم بحفظ وإغلاق الملف، وأعد تحميل HAProxy لتطبيق التغييرات: sudo service haproxy reload يمتلك web-backend الآن خادومين يتعاملان مع حركة مرور البيانات غير المرتبطة بووردبريس، أي تمّ إعداد موازنة الحمل عليه بنجاح. موازنة حمل الخادوم wordpress-1 إنّ موازنة حمل تطبيق مثل ووردبريس أكثر تعقيدًا بقليل من موازنة حمل خادوم ثابت، لأنّه يجب عليك الاهتمام بأشياء مثل مزامنة الملفّات المُحمّلة ومستخدمي قواعد البيانات الإضافيّين. أكمل الخطوات الثلاث التالية لإنشاء خادوم ووردبريس الثاني wordpress-2: إنشاء خادوم تطبيق ويب الثاني. مزامنة ملفّات تطبيق الويب. إنشاء مستخدم قاعدة بيانات جديد. بعد أن تقوم بإنشاء الخادوم wordpress-2 مع إعداد قاعدة البيانات بشكل صحيح فكل ما تبقى عليك فعله هو إضافته إلى wordpress-backend ضمن إعدادات HAProxy. على الخادوم haproxy-www قم بتحرير الملف haproxy.cfg: sudo vi /etc/haproxy/haproxy.cfg ابحث عن القسم wordpress-backend من الإعدادات: backend wordpress-backend server wordpress-1 wordpress_1_private_IP:80 check وبعدها أضف الخادوم wordpress-2 في السطر التالي: server wordpress-2 wordpress_2_private_IP:80 check قم بحفظ وإغلاق الملف، وأعد تحميل HAProxy لتطبيق التغييرات: sudo service haproxy reload يمتلك web-backend الآن خادومين يتعاملان مع حركة مرور البيانات غير المرتبطة بووردبريس، أي تمّ إعداد موازنة الحمل عليه بنجاح. الخاتمة بعد أن أتممت الآن هذا الدّرس يجب أن تكون قادرًا على توسيع موازنة الحمل والوسيط العكسي لإضافة المزيد من التطبيقات والخواديم لبيئتك لجعلها تتوافق بشكل أفضل مع احتياجاتك، تذكّر أنّه لا توجد حدود لطرق إعداد بيئتك، وربّما تحتاج إلى البحث في توثيق HAProxy إن أردت متطلبات أكثر تعقيدًا. ترجمة -وبتصرّف- للمقال How To Use HAProxy As A Layer 7 Load Balancer For WordPress and Nginx On Ubuntu 14.04 لصاحبه Mitchell Anicas.
  2. مُقدّمة إنّ عنوان IP العائم في DigitalOcean هو عبارة عن عنوان IP ثابت وقابل للنفاذ من قبل العوام (أي قابل للوصول إليه) يُمكِن تعيينه لأي من الـ Droplets التي تملكها، يمكنك أيضًا إعادة تعيين هذا العنوان بشكل فوري إلى أي Droplet أخرى لديك في نفس مركز البيانات وذلك عبر لوحة تحكّم DigitalOcean أو برمجيًا عبر الواجهة البرمجية API. تمنحنا إمكانية إعادة تعيينه القدرة على تصميم وإنشاء بنى تحتيّة لخواديم عالية التوفّر High Availability (HA)، وهي بيئات لا تملك أي نقطة فشل، عن طريق إضافة التكرار redundancy إلى نقطة الدخول، أو البوابة gateway، إلى خواديمك، يتطلّب تحقيق بيئات عالية التوفّر بشكل كامل وجود تكرار على مستوى كل طبقة من بنيتك التحتيّة، كخواديم التطبيقات وقواعد البيانات، وهو أمر يصعب تطبيقه عادةً ولكن أثبت قيمته العالية لتقليل زمن الفشل downtime والحفاظ على قاعدة مستخدمين سعداء. لاحظ أنّ تعيين عنوان IP عائم لـ Droplet لا يستبدل عنوان IP العام الأصلي لها، والذي سيبقى بدون تغيير، ولكن بدلًا من ذلك يزوّدنا العنوان العائم بعنوان IP ثابت إضافي يُمكِن استخدامه للنفاذ إلى الـ Droplet المُخصّص لها حاليًّا. يُغطّي هذا الدّرس المواضيع التالية: إعداد أساسي لبيئة عالية التوفّر كيفيّة إدارة عناوين IP العائمة في DigitalOcean عناوين IP الرّابطة Droplet Anchor IPs البيانات الوصفيّة Metadata لعناوين IP العائمة كيفيّة تطبيق إعداد عالي التوفّر حالات أخرى لاستخدام عناوين IP عائمة فلننظر الآن إلى مثال لإعداد أساسي عالي التوفّر كبداية. إعداد أساسي عالي التوفّر إنّ أسهل طريقة لتعلّم آلية عمل خادوم عالي التوفّر هي مشاهدة مثال أساسي جدًّا، يتكوّن إعداد الخادوم عالي التوفّر الأكثر بساطة من عنوان IP عائم يشير، كحد أدنى، إلى مُوازِنَي حمل اثنين في حالة إعداد فعّال\غير فعّال active/passive، يُمثِّل هذا طبقة البوابة من إعداد خادومك، والتي سيقوم المستخدمون بالنفاذ إليها للوصول إلى خواديم الويب لديك. وهذا توصيف لكل مكوّن من المخطّط السّابق: الخادوم الفعّال Active Server: وهو الخادوم الذي يستقبل حركة مرور بيانات المستخدمين التي يتم تمريرها من عنوان IP العائم، وهو بشكل نموذجي مُوازِن حمل يقوم بتمرير حركة مرور البيانات إلى واجهة خلفيّة لخواديم تطبيقات ويب الخادوم غير الفعّال Passive Server: خادوم في وضع الاستعداد يكون عادة مضبوطًا بشكل مماثل للخادوم الفعّال، يستقبل حركة مرور البيانات فقط خلال حدوث الفشل، أي عندما يصبح الخادوم الفعّال غير متوفّر، ويتم إعادة تعيين عنوان IP العائم إلى الخادوم غير الفعّال عنوان IP العائم Floating IP: وهو عنوان IP الذي يشير إلى أحد خواديمك، ويُمكِن إعادة تعيينه في حال حدوث فشل في الخادوم الفعّال من الهام ملاحظة أنّ عنوان IP العائم لا يزودّنا من تلقاء نفسه بتوافر عالي، بل يجب تطبيق وإضافة آلية تجاوز للفشل إلى إعدادنا لكي يُعتبَر عالي التوفّر، والتي تقوم بأتمتة عمليّة اكتشاف فشل الخادوم الفعّال وإعادة تعيين عنوان IP العائم إلى الخادوم غير الفعّال، وبافتراض تطبيق استراتيجيّة فعّالة لتجاوز الفشل سيسمح الإعداد السابق للخدمة بأن تبقى متوفّرة حتى لو فشل أحد الخادومين. هناك العديد من الطرق المختلفة لتحقيق تجاوز للفشل، والتي سننظر إليها لاحقًا، ولكن فلنتحدّث أولًا عن كيفيّة استخدام عناوين IP العائمة في DigitalOcean. كيفيّة إدارة عناوين IP العائمة في DigitalOcean كما هو الحال مع معظم موارد DigitalOcean، يُمكِن إدارة عناوين IP العائمة عبر لوحة التحكّم أو الواجهة البرمجية API، وبينما تسمح لنا لوحة التحكّم بإنشاء، إعادة تعيين، وحذف عناوين IP عائمة، فإنّ استخدام الواجهة البرمجية ضروري لتطبيق آلية تلقائيّة وفعالّة لتجاوز الفشل، سنناقش كلا الطريقتين لإدارة عناوين IP العائمة، فلنبدأ بطريقة لوحة التحكّم. 1- لوحة التحكّم لإدارة عناوين IP العائمة عبر لوحة تحكّم DigitalOcean اضغط على رابط الشّبكة Networking (في قائمة التصفّح العلويّة)، وبعدها على عناوين IP العائمة Floating IPs في القائمة اليسرى، في أوّل مرة تزور فيها هذه الصفحة سترى صفحة تخبرك أنّك لا تمتلك عناوين IP عائمة ولكن بإمكانك أن تقوم بإنشائها: تستطيع هنا إنشاء عنوان IP عائم عن طريق اختيار واحدة من الـ Droplets لديك والنقر على زر تعيين عنوان IP عائم Assign Floating IP، إن أردت الحصول على عنوان IP عائم بدون تعيينه إلى Droplet فورًا فبإمكانك ببساطة اختيار مركز بيانات مُحدَّد من القائمة. ملاحظة: إن قمت بتعيين عنوان IP عائم لـ Droplet تمّ إنشاؤها قبل تاريخ 20 أكتوبر 2015 سيتم عرض رسالة تتضمّن تعليمات يجب أن تتبعها قبل تعيين عنوان IP عائم للـ Droplet، سيقوم هذا بإنشاء عنوان IP رابط للـ Droplet لديك، وهو موضوع سنناقشه لاحقًا في هذا الدّرس. بعد بضع لحظات ستملك عنوان IP عائم جديد يُشير إلى الـ Droplet التي اخترتها: إن كان لديك عنوان IP عائم واحد على الأقل فستعرض هذه الصفحة قائمة بعناوين IP العائمة لديك، والتي تتضمّن التفاصيل التالية حول كل مُدخَل: العنوان Address: عنوان IP العائم، كيف يُمكِن النفاذ إليه وكيف تمّ تعريفه داخليًّا أيضًا. مركز البيانات Datacenter: مركز البيانات الذي تمّ بداخله إنشاء عنوان IP العائم، يُمكن تعيين عنوان IP العائم فقط إلى Droplets موجودة ضمن نفس مركز البيانات Droplet: وهي الـ Droplet التي تمّ تعيين عنوان IP العائم إليها، يتم توجيه الطلبات المُرسَلة إلى عنوان IP العائم إلى هذه الـ Droplet، يُمكن أيضًا تعيين هذه القيمة إلى غير مُعيَّن "Unassigned"، والذي يعني أنّ عنوان IP العائم محجوز ولكن لن يُمرِّر أي حركة مرور بيانات من الشبكة لأي Droplet وبالإضافة لمعلومات عنوان IP العائم يسمح هذا القسم لك بإجراء ما يلي: إعادة التعيين (الزر الأزرق على شكل قلم): يقوم بتعيين عنوان IP العائم لـ Droplet أخرى ضمن نفس مركز البيانات، بإمكانك أيضًا إزالة تعيين عنوان IP العائم الحذف (الزر الأحمر على شكل X): يقوم بإزالة عنوان IP العائم من حسابك الآن بعد أن كوّنت فكرة أوضح عن إدارة عناوين IP العائمة عبر لوحة التحكّم فلننظر إلى استخدام الواجهة البرمجية API. 2- الواجهة البرمجية API تسمح لنا الواجهة البرمجية في DigitalOcean بتنفيذ جميع إجراءات إدارة عناوين IP العائمة التي يمكننا القيام بها من خلال لوحة التحكّم، غير أنّها تسمح لنا بالقيام بتلك التغييرات برمجيًّا، يكون هذا مفيدًا لنا بشكل خاص لأنّ الإعداد عالي التوفّر يتطلّب القدرة على أتمتة إعادة تعيين عنوان IP العائم إلى Droplet أخرى. تسمح لنا الواجهة البرمجية بالقيام بالإجراءات التاليّة الخاصّة بعنوان IP العائم: عرض عناوين IP العائمة حجز عنوان IP عائم جديد لمنطقة تعيين عنوان IP عائم جديد إلى Droplet إعادة تعيين عنوان IP عائم إلى Droplet إزالة تعيين عنوان IP عائم حذف عنوان IP عائم يُمكنك إيجاد التوثيق الكامل للواجهة البرمجية في DigitalOcean والتي تُغطّي موضوع عناوين IP العائمة هنا لن ندخل في كافّة تفاصيل إدارة عناوين IP العائمة عبر الواجهة البرمجية، ولكن سنشرح مثالًا سريعًا، وهو مثال حول استخدام الأمر curl لإعادة تعيين عنوان IP عائم موجود إلى Droplet: curl -X POST -H 'Content-Type: application/json' -H 'Authorization: Bearer your_api_token' -d '{ "type": "assign", "droplet_id": 5000 }' "https://api.digitalocean.com/v2/floating_ips/8.8.8.9/actions" بافتراض أنّك وضعت القيم الحقيقيّة لديك بدلًا من "your_api_token"، "5000"، و"8.8.8.9"، والتي تُشير على الترتيب إلى رمز الواجهة البرمجية API token، مُعرِّف (ID) الـ Droplet الهدف، وعنوان IP العائم الذي تريد إعادة تعيينه، فسيقوم هذا الأمر بتوجيه 8.8.8.9 إلى Droplet الخاصّة بك ذات المُعرِّف 5000. الآن وقد فهمت كيفية إدارة عناوين IP العائمة عبر لوحة التحكّم والواجهة البرمجية، فلنتحدّث عن كيفيّة تواصل عناوين IP العائمة مع الـ Droplets. عناوين IP الرّابطة للـ Droplet تتدفّق حركة مرور بيانات الشّبكة بين عنوان IP العائم والـ Droplet عبر IP رابط (anchor IP)، وهو عبارة عن عنوان IP يُمثِّل كناية Alias إلى واجهة الشبكة العامّة للـ Droplet (وهي eth0)، ولهذا السبب يجب أن تملك الـ Droplet عنوان IP رابط قبل أن نستطيع تعيين عنوان IP عائم لها، جميع الـ Droplets التي تمّ إنشاؤها بعد تاريخ 20 أكتوبر 2015 تمتلك تلقائيًّا عنوان IP رابط، إن كانت لديك Droplet قبل هذا التاريخ تستطيع إضافة عنوان IP رابط عن طريق متابعة التعليمات في درس كيفيّة تمكين عناوين IP العائمة على الـ Droplet القديمة. يكون عنوان IP الرّابط قابلًا للنفاذ فقط على الـ Droplet التي ينتمي لها ولعنوان IP العائم المُحدَّد لهذه الـ Droplet، السبب وراء هذا هو أنّ عنوان IP الرّابط هو المكان الذي ينبغي أن تربط إليه أي خدمات عامّة تريد جعلها عالية التوفّر عبر عنوان IP عائم، على سبيل المثال إن كنت تستخدم عنوان IP عائم ضمن إعداد موازن حمل فعّال/غير فعّال فيجب عليك ربط خدمات موازن الحمل إلى عنوان IP الرّابط للـ Droplet التي تنتمي لها حتّى تكون قابلة للنفاذ فقط من خلال عنوان IP العائم، يمنع هذا المستخدمين من استعمال عناوين IP العامّة للـ Droplets كي يتجاوزوا عنوان IP العائم. كيف تحصل على عنوان IP الرّابط أبسط طريقة لمعرفة عنوان IP الرابط للـ Droplet لديك هو استخدام خدمة البيانات الوصفيّة للـ Droplet، يُمكِن الحصول على معلومات عنوان IP الرّابط، مثل أي بيانات مُخزَّنة ضمن البيانات الوصفيّة، عن طريق تشغيل أمر curl أساسي من سطر الأوامر للـ Droplet. يسترجع هذا الأمر عنوان IP الرّابط للـ Droplet: curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/address يسترجع هذا الأمر قناع الشّبكة netmask لعنوان IP الرّابط للـ Droplet: curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/netmask يسترجع هذا الأمر بوابّة عنوان IP الرّابط للـ Droplet: curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/gateway الطريقة الأخرى للبحث عن معلومات حول عنوان IP الرّابط هو استخدام الأمر ip addr: ip addr show eth0 يكون عنوان IP الرّابط (وهو 10.17.0.47 في هذا المثال) موجودًا تحت معلومات عنوان IP العام الاعتياديّة كما يلي: [secondary_output Example output:] 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 04:01:7d:c2:a2:01 brd ff:ff:ff:ff:ff:ff inet 159.203.90.122/20 brd 159.203.95.255 scope global eth0 valid_lft forever preferred_lft forever inet 10.17.0.47/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::601:7dff:fec2:a201/64 scope link valid_lft forever preferred_lft forever البيانات الوصفيّة لعنوان IP العائم تستطيع الـ Droplet أن تعرف إذا ما تمّ تعيين عنوان IP عائم لها عن طريق خدمة البيانات الوصفيّة، فإن كان موجودًا يُمكِن استرجاع هذا العنوان، تكون هذه المعلومات مفيدة جدًّا عند تنفيذ إعداد خادوم عالي التوفّر. يُمكِن استرجاع هذه التفاصيل كأي معلومات مُخزّنة ضمن البيانات الوصفيّة عن طريق تنفيذ أمر curl أساسي من واجهة سطر الأوامر للـ Droplet. حتى ترى إن كانت الـ Droplet تملك عنوانًا IP عائمًا مُخصّصًا لها قم بتشغيل هذا الأمر: curl -s http://169.254.169.254/metadata/v1/floating_ip/ipv4/active إن كان هنالك عنوان IP عائم لها فبإمكانك استرجاعه عن طريق هذا الأمر: curl -s http://169.254.169.254/metadata/v1/floating_ip/ipv4/ip_address يُمكنك إيجاد الوثائق الكاملة للبيانات الوصفيّة للـ Droplet هنا. كيفيّة تنفيذ إعداد عالي التوفّر بعد أن فهمت آليّة عمل عناوين IP العائمة في DigitalOcean فقد أصبحت مستعدًّا للبدء ببناء إعداد خادوم عالي التوفّر. Corosync و Pacemaker: تزوّدنا Corosync و Pacemaker بحزمة برمجيّات عنقوديّة cluster يمكن استخدامها لإنشاء إعداد عالي التوفّر فعّال، توفّر Corosync طبقة رسائل تمكّن الخادوم من التواصل كعنقود واحد، بينما تعطينا Pacemaker القدرة على التحكّم بكيفيّة تصرف هذا العنقود. Keepalived: إنّ Keepalived هي عبارة عن خدمة تستطيع مراقبة الخواديم أو العمليّات من أجل تنفيذ بيئة عالية التوفّر على بنيتك التحتيّة. Heartbeat: تزوّدنا Heartbeat بوظيفة عنقوديّة يمكن استخدامها مع عناوين IP العائمة لتنفيذ إعداد خادوم عالي التوفّر فعّال\غير فعّال، لا يُنصَح باستخدام هذا الإعداد لأغراض عمليّة، ولكنّه يشرح بشكل فعّال كيفيّة تطبيق إعداد خادوم عالي التوفّر بسيط حالات أخرى لاستخدام عنوان IP عائم من الطرق الأخرى للاستفادة من عناوين IP العائمة هو نشر أزرق-أخضر Blue-green deployment، وهي استراتيجيّة لتوزيع ونشر البرمجيّات تعتمد على الحفاظ على بيئتين منفصلتين قادرتين على الإنتاج، وتُسمّى أزرق وأخضر لغرض سهولة النقاش، يتحدّث هذا الدّرس حول كيفيّة استخدام توزيع أزرق-أخضر على DigitalOcean لتبسيط عمليّة نقل المستخدمين إلى إصدار جديد من برمجيّتك. الخاتمة ينبغي أن تكون قد فهمت الآن كيفيّة عمل عناوين IP العائمة في DigitalOcean وكيف يُمكِن استخدامها لإنشاء بنية تحتيّة لخادوم عالي التوفّر. ترجمة -وبتصرّف- لـ How To Use Floating IPs on DigitalOcean لصاحبه Mitchell Anicas
  3. هناك العديد من الأسباب التي تجعل من جمع الإحصائيات حول خواديمنا، تطبيقاتنا، وحركة مرور البيانات فكرة جيدة. حيث يعطينا جمع وتنظيم البيانات الثقة في قراراتنا حول الامتداد والتّوسّع scaling، استكشاف الأخطاء troubleshooting، وتعقّب نقاط الضّعف في إعداداتنا. توجد العديد من الأدوات التي يمكن أن تستخدم لتتبُّع المقاييس على أجهزتنا، والتي غالبًا ما تُسنَد إلى جزء صغير مُحدَّد من العمليّة، بإمكاننا ضم هذه الأدوات إلى بعضها لإنشاء نظام لتجميع، تسجيل، وعرض النتائج. سنناقش في هذا الدّرس بعض التقنيات التي تسمح لنا بجمع، تخزين، وتمثيل البيانات المُولَّدة من قبل خواديمنا وتطبيقاتنا. سنتحدّث عن Graphite وهي مكتبة رسوم بيانيّة مصنوعة من عدّة مكوّنات يُمكِن استخدامها لتصيير render التمثيلات المرئيّة لبياناتنا عبر الزمن، سنقوم بإلقاء نظرة أيضًا على collectd، وهو عفريت (بالإنجليزية Daemon وهو برنامج يعمل في خلفيّة النظام) لإحصائيات النظام بإمكانه جمع معلومات في الزمن الفوري تقريبًا حول خادوم قيد التشغيل. وأخيرًا سنتحدّث عن StatsD وهو مُجمِّع إحصائيّات مرن يمكن استخدامه لجمع وتنظيم البيانات الكيفيّة arbitrary data. لماذا نتتبع البيانات؟ إنّ أول شيء نحتاج معرفته هو الأسباب التي تدفعنا لتتبّع البيانات في بيئة خادوم أو تطبيق. السبب الرئيسي بسيط للغاية فعليًّا: فكلّما ازداد عدد البيانات التي نمتلكها كلّما ازدادت قدرتنا على فهم ما يحصل في لحظة ما، يعطينا هذا قدرة ملحوظة على دعم قراراتنا في التعامل مع البيانات ونرى في وقت مبكر إذا ما كان التغيير يستهدف المُكوِّن الصحيح، يزوّدنا تتبع الإحصائيّات بمصدر إضافي للمعلومات والتي قد لا تكون موجودة في سجلّات التطبيق. معظم (ولكن ليس كل) أنظمة التسجيل غير قادرة على ربط البيانات من التطبيقات المتعددة أو على ربط الأحداث مع حالات أنظمة محدّدة لأنّها تمثل أساسًا خرْجًا لتطبيق مستقل، ممّا قد يجعل من المعقّد بناء نظرة شاملة للظروف المحيطة بحدث ما. بإمكاننا أن نتخيّل للحظة أنه لدينا حالة توقّف فيها خادوم قاعدة البيانات عن العمل، فأثناء قراءة السجلّات logs قد نلاحظ أنّه في تمام الساعة 15:35:28 UTC تمّ إنهاء خدمة MySQL لدينا بخطأ نفاذ الذاكرة (OOM (out of memory، نحن نعرف الآن أنّ استخدام الذاكرة هو المشكلة ولكن ليست لدينا أي فكرة عن السبب الذي أدى لارتفاع استهلاك الذاكرة في خادوم مستقر سابقًا. إن كنّا نتتبّع البيانات حول خادومنا وتطبيقاتنا نستطيع بوضوح البدء في جمع القطع المختلفة لبيانات النظام لتساعدنا على فهم كيف كانت تبدو البيئة تمامًا أثناء حدوث المشكلة، قد نجد أنّه كان لدينا صعود ثابت في استهلاك الذاكرة والذي قد يحدث من تسرّب ذاكرة memory leak، وإن كانت لدينا معلومات حول استخدام الذاكرة على مستوى التطبيقات فبإمكاننا بالضبط رؤية التطبيق المسؤول عن هذا، قد نرى أيضًا أنّه كان لدينا ارتفاع غير معتاد باستهلاك الذاكرة والذي قد يعني شيئًا مختلفًا تمامًا. وفي حالة مختلفة نستطيع أن نرى كيف يبدو النظام قبل وبعد نشر التّطبيق deploy، فلو قامت شيفرة جديدة بإنشاء بعض الحالات الغريبة نستطيع رؤية تأثيرها على المكونات الأخرى لدينا، ومقارنة أدائها بالشيفرة القديمة، ونتمكّن من تحديد النقاط التي تُظهِر فيها الشيفرة الجديدة تحسينًا، والأماكن التي قد ارتكبنا فيها خطأ ما. وبالجمع الذكي للبيانات نتمكّن من مشاهدة نظامنا كنظام بدلًا من مجموعة من المكوّنات غير المرتبطة. مكونات Graphite سنعود هنا قليلًا إلى الوراء ونتحدث في البداية عن Graphite، مكتبة الرسوم البيانيّة، وبعدها سنتكلّم عن بعض البرمجيات التي تستطيع Graphite استخدامها للحصول على البيانات. إنّ Graphite هي عبارة عن مكتبة رسوم بيانيّة مسؤولة عن تخزين وتصيير تمثيلات مرئيّة للبيانات، وهذا يعني أنّ Graphite تتطلب تطبيقات أخرى لجمع ونقل نقاط البيانات. مشروع Graphite بحد ذاته مكوّن من بعض المكوّنات المختلفة، وكل من هذه المكونات لديها غرض مُحدّد ومُركّز. تطبيق ويب Graphite المُكوّن الأكثر مرئية وديناميكية من تثبيت Graphite هو تطبيق ويب Graphite. وهو المكان الذي نستطيع فيه تصميم الرسوم البيانيّة التي تمثّل بياناتنا: تعطينا Graphite واجهة شديدة المرونة لتصميم الرسوم البيانيّة، نستطيع الجمع بين مختلف أنواع المقاييس، التحكم باللصيقات label، الخطوط، الألوان، وخصائص الأسطر، وبإمكاننا تغيير حجم البيانات والتعامل معها بحسب رغبتنا. الفكرة الأساسية التي يجب فهمها هنا هي أنّ Graphite تقوم بتصيير الرسوم البيانيّة بحسب نقاط البيانات التي تتلقاها والاتجاهات التي نعطيها إياها، فهي لا تقوم فقط بطباعة الرسم البياني ومن ثم تتخلص من البيانات، نستطيع تصيير البيانات بأي شكل نريده فورًا. يتيح لنا تطبيق الويب أيضًا حفظ تخطيطات layouts وخصائص الرسم البياني، بحيث نتمكن من استعادة واجهة المراقبة مع كافة الإعدادات التي نرغب بها، بإمكاننا الحصول على نوافذ عرض لوحة الرئيسية كما نريد، أي نستطيع أن نمتلك لوحة رئيسية منفصلة لكل جهاز أو تطبيق، وإن أردنا الربط بين البيانات عبر هذه اللوحات نقوم فقط بسحب وإفلات الرسوم البيانيّة لضم نافذة العرض. ولا تتوقف مرونة Graphite عند هذا الحد، فهي تسمح لنا بتصيير الرسوم البيانيّة إلى رابط مجرّد لتضمينه في واجهات أخرى، بإمكاننا أيضًا تصدير البيانات إلى تمثيلات غير رسوميّة مثل JSON أو CSV، أو خَرْج SVG مع تضمين معلومات البيانات. الآن وقد عرفنا ما الذي يمكننا فعله بالبيانات بعد أن نحصل عليها فلنتحدث حول مكونات Graphite الأخرى لمشاهدة العمليّات التي تسمح لنا بالقيام بها. Carbon إنّ Carbon هو مخزن المنتهى الخلفي Backend لإعدادات Graphite، حيث يمتلك إعداد Graphite المفرد عفريت Carbon أو أكثر مسؤول عن التعامل مع البيانات التي يتم إرسالها بواسطة العمليات الأخرى التي تجمع وتنقل الإحصائيّات (أدوات الجمع Collectors هي ليست جزءًا من Graphite). هنالك العديد من أنواع عفاريت Carbon المختلفة، كل منها يتعامل مع البيانات بطريقة مختلفة، الأساسي منها يُدعى carbon-cache.py، هذا العفريت بسيط حيث يستمع إلى البيانات على منفذ port ويكتبها إلى القرص كما وصلت بطريقة فعّالة. يخزّن البيانات كما أتت ويفرغها إلى القرص بعد فترة محدّدة مسبقًا، من الهام معرفة أنّ مكوّن Carbon يتعامل مع إجراءات إفراغ flushing واستقبال البيانات، فهو لا يتعامل مع آليات التخزين الفعليّة، والتي تُترَك للمكوّن whisper الذي سنتحدث عنه بعد قليل. يتم إخبار العفريت carbon-cache.py بالتنسيقات formats، الموافيق protocols، والمنافذ التي يعمل عليها، يتم أيضًا إخباره بسياسات الاحتفاظ بالبيانات لاستخدامها من أجل تخزين البيانات، والتي يتم إعطاؤها للمكوّن whisper، بالنسبة لمعظم الإعدادات الأساسيّة فإنّ نسخة واحدة من carbon-cache.py يكفي للتعامل مع استقبال البيانات. يمكن تشغيل عدّة نسخ منه في وقت واحد عندما يكبر حجم النظام لدينا، ويمكن موازنتها بواسطة عفريت carbon-relay.py أو carbon-aggregator.py في المقدمة. بإمكاننا استخدام العفريت carbon-relay.py لإرسال الطلبات لكافة عفاريت المنتهى الخلفي من أجل بعض التوفير، ويمكن أيضًا استخدامه لمشاركة البيانات عبر أمثال carbon-cache.py المختلفة لنشر أحمال القراءة عبر مواقع التخزين المتعددة. يمكن للعفريت carbon-aggregator.py أن يحتفظ بالبيانات مؤقتًا ومن ثمّ يلقيها إلى carbon-cache.py بعد فترة من الزمن، قد يساعد هذا في تخفيف تأثير معالجة الإحصائيات على النظام على حساب التفاصيل. Whisper إنّ Whisper هي عبارة عن مكتبة قواعد بيانات تستخدمها Graphite لتخزين المعلومات التي يتم إرسالها. هذه المكتبة مرنة جدًّا وتسمح بأن يتم تخزين البيانات المتسلسلة زمنيًّا بتفصيل رائع، تقوم بإنشاء أرشيفات مختلفة على مستويات مختلفة من التفصيل، لذا في الاستخدام العملي يتم تحويل المعلومات إلى دقة أقل عندما تتجاوز عتبات زمنيّة مُعيّنة. على سبيل المثال نستطيع تخزين نقطة بيانات واحدة كل ثانية لمقياس مُحدّد، بإمكاننا أن نطلب من whisper أن يحتفظ بهذه البيانات المفصّلة لمدّة خمس ساعات، بإمكاننا أن نمتلك أيضًا أرشيفًا لتخزين بيانات ذات دقة أقل، قد يقوم فقط بتخزين نقطة واحد كل دقيقة ويبقيها لمدّة ستة أشهر. يتم حساب كل نقطة من الأرشيف الأقل دقّة من خلال نفس البيانات المُخزّنة في الأرشيفات الأكثر دقّة، بإمكاننا أن نمتلك أرشيفات من دقات مختلفة مع معدلات احتفاظ بالبيانات كما نريد، نستطيع إعداد كيفيّة حساب whisper للبيانات للأرشيفات الأقل دقّة اعتمادًا على نوع المقياس الذي يتم تتبّعه. على سبيل المثال قد يكون المقياس هو سجل عدد المرات لحدوث بعض الأحداث خلال إطار زمني قصير، ولإنشاء نقطة لإطار زمني أطول بدقة أقل نضيف نقاط البيانات من الأرشيف ذي الدقة الأعلى لتلخيص قيم البيانات خلال الفترة الزمنية الأطول. تستطيع Whisper حساب البيانات ذات الدقة الأقل بطرق أخرى اعتمادًا على طبيعة المقاييس، على سبيل المثال يتم تعميم بعض البيانات عن طريق حساب المتوسط، بينما قد يتم تتبّع بيانات أخرى بحسب القيمة العظمى. بالنسبة للمتوسط يتم حساب القيمة الفعلية المتوسطة من نقاط ذات دقّة أعلى لإنشاء نقاط ذات دقّة أقل، وبالنسبة للقيمة العظمى يجب الإبقاء على أكبر قيمة ورمي باقي القيم للحفاظ على معنى الرقم. تقوم whisper بحساب وتسجيل البيانات ذات الدقّة الأقل في وقت استقبالها لتلك البيانات (بعد الفترة الزمنية اللازمة لجمع القيم الضروريّة)، فهي ببساطة تجمع نقاط البيانات التي تحتاجها لتنفيذ تقنية جمع البيانات (المتوسط، القيمة الكبرى، إلخ..) وبعدها تقوم بكتابتها. تستخدم Graphite أعلى دقّة للأرشيف والذي يحتوي على الفترة الزمنية المطلوبة عندما تقوم بالاستعلام عن البيانات لتصيير الرسوم البيانيّة. تجميع وتسليم الإحصائيات كما أشرنا سابقًا لا تهتم Graphite بجمع البيانات بنفسها، بل تعتمد بدلًا من ذلك على تزويدها بالمعلومات من قبل خدمات أخرى، يسمح هذا للمشروع بأن يحافظ على تركيزه وأن يتفاعل بشكل مُجزّأ مع خدمات الدخل input. سنناقش الآن الموافيق protocols التي تفهمها Graphite، وسنتحدّث بعدها عن برنامجين شائعين للجمع، وهما collectd و StatsD، والتي يمكن استخدامها لتمرير البيانات إلى Carbon من أجل المعالجة. الموافيق Protocols توجد ثلاث موافيق مختلفة نستطيع استخدامها لإرسال البيانات إلى Graphite. أولًا تقبل وتفهم Graphite النصوص المُجرّدة، وهو التنسيق الأكثر مرونة لأنّ أي تطبيق أو خدمة تقريبًا يستطيع إخراج نصوص والتي يمكن استخدامها كي نعطيها إلى Graphite أو أداة وسيطة ما. تتضمّن رسائل النصوص المُجرّدة معلومات حول اسم المقياس، القيمة المعطاة، وختم زمني لأجل تلك القيمة، يمكن إرسال تلك الرسائل مباشرة إلى Carbon على منفذ مصمّم لأجل النصوص المُجرّدة بدون أي تنسيق إضافي. ولأنّه تم إنشاء Graphite باستخدام لغة بايثون فهي تقبل أيضًا تنسيق البيانات التسلسلي "pickle"، يسمح لنا هذا التنسيق المعياري لبايثون بالاحتفاظ مؤقّتًا بقيم زمنية متعدّدة وإرسالها في تعامل واحد. تستطيع Graphite أيضًا أن تقبل البيانات باستخدام رسائل AMQP، تسمح لنا هذه بالتعامل مع أحمال كبيرة للبيانات بشكل أفضل، نستطيع مع هذا الإعداد إعطاء عدد كبير من الإحصائيات والتعامل مع انقطاعات اتصالات الشبكة بين المضيفين عن بُعد remote hosts بدون خسارة البيانات. Collectd من أبسط طرق جمع معلومات مفصّلة حول خادوم ما هي باستخدام عفريت يُدعى collectd. بإمكان collectd تجميع إحصائيّات حول العديد من المكونات المختلفة لبيئة الخادوم، فهي تسمح لنا بسهولة بتتبّع المقاييس الشائعة مثل استخدام الذاكرة، حمل المعالج CPU load، حركة مرور البيانات عبر الشبكة network traffic، إلخ..، يسمح لنا هذا بسهولة بربط الأحداث مع حالة أنظمتنا. وبغض النظر عن جمع معلومات النظام المعياريّة تمتلك collectd نظام إضافات يوسّع من وظيفتها، يعني هذا أنّه يمكننا بسهولة تتبّع البرمجيّات الشائعة مثل Apache ،Nginx ،iptables ،memcache ،MySQL ،PostgreSQL ،OpenVPN، وغيرها. تزوّدنا collectd بطريقة مبسّطة للحصول على البيانات من التطبيقات المبنيّة مسبقًا والخدمات الشائعة على خادومنا، ويجب استخدامها لتتبّع سلوك البنية التحتيّة والخدمات التي نعتمد عليها. StatsD إنّ StatsD هي عبارة عن عفريت بسيط يمكن استخدامه لإرسال البيانات الأخرى إلى Graphite، الفائدة من هذا النهج هو أنّه يصبح من البديهي بناء تتبّع إحصائيّات للتطبيقات والأنظمة التي نقوم بإنشائها. تعمل StatsD عن طريق الاستماع على الواجهة إلى رُزَم UDP البسيطة التي تمثّل نقطة بيانات مفردة، يعني هذا أنّها تقبل كميّة هائلة من المعلومات بطريقة لا تحتاج للاتصال، وبعدها تستطيع تجميع القيم التي تتلقّاها وتمررّها إلى Graphite. يسمح لنا هذا النظام بإرسال الإحصائيّات بكميّات كبيرة بدون القلق حول زيادة زمن الوصول إلى التطبيق، تجمع خدمة StatsD كافّة البيانات كما وصلتها، تجمّعها، ومن ثمّ ترسل نقاط بيانات ملخصة وجميلة إلى Graphite بالإطار الزمني المتوقّع. وبسبب هذه الميّزات فهي فعليًّا وسيط جيّد لأي نوع من البيانات المرسلة إلى Graphite، ولكن الطريقة الأساسيّة التي يمكننا الاستفادة منها بفعاليّة هي مراقبة تطبيقاتنا الخاصّة والأدوات التي نقوم بإنشائها. تكون StatsD مثاليّة لهذا لأنّها عفريت ذو غرض عام يقبل حركة مرور بيانات UDP، هناك العديد من المكتبات المختلفة التي تعمل من جهة العميل client-side في العديد من لغات البرمجة والتي بإمكانها إرسال البيانات إلى StatsD، يعني هذا أنّه يمكن للتطبيقات التي نبنيها إرسال البيانات بسهولة من أجل تتبّعها. الخاتمة يجب أن تملك الآن فهمًا جيّدًا كيف أنّه يمكن لمجموعة مختلفة من الإحصائيّات وأدوات الرسم البياني العمل معًا لإعطاء صورة كاملة عن نظامك. ترجمة -وبتصرف- للمقال An Introduction to Tracking Statistics with Graphite, StatsD, and CollectD لصاحبه Justin Ellingwood.
  4. سنتحدث في هذا القسم من هذه السلسلة حول زيادة سرعة WordPress عن طرق زيادة سرعة الموقع الخاصّة بالمطورين. زيادة السرعة المرتبطة بالتطوير يفضّل المطورون أن يقولوا أنّ انخفاض السرعة في أكثر الأحيان هو خطأ المستخدم، هناك بطبيعة الحال بعض الحقيقة في هذا الكلام، ولكن نعتقد أنّ العديد من المطورين يكتبون شيفرات تحتوي بعض الأخطاء سهوًا. لا تكون الشيفرة خاطئة من الناحية التقنية، فهي لا تحتوي على أخطاء، ولا تحاول عن قصد إبطاء الموقع، ومع ذلك فهي لا تفعل الكثير من أجل زيادة السرعة أو ضمان أن يبقى سريعًا لفترة من الزمن. ها هي بعض الأشياء التي يستطيع المطورون فعلها لضمان عمل مواقع ووردبريس بسلاسة وتساعد على الحفاظ على الأداء لأطول فترة ممكنة. 1. معرفة الأدوات التي بين يديك تبدو هذه مهمّة بسيطة للغاية، ومع ذلك هناك القليل من المطورين الذين يفهمون معنى ذلك، ليست هناك طريقة لمعرفة كل شيء حول نظام كبير مثل ووردبريس، ولكن ما يمكن فعله هو إتقان ما تعرفه وتكوين فكرة واضحة حول ما لا تعرفه (وبالتّالي يجب أن تبحث عنه)، أي بمعنى آخر: اعرف حرفتك جيّدًا وتعلّم باستمرار. على سبيل المثال هل احتجت يومًا ما إلى استرجاع عدد كبير من الحقول الوصفية meta fields لمنشور؟ ربّما باستخدام ()get_post_meta تقريبًا 20 مرة؟ قد تعتقد أنّ هذا مضيعة للوقت، حيث يبدو أنّنا نقوم بـ 20 طلب قاعدة بيانات. يستخدم بعض الأشخاص الصنف WPDB لسحب جميع البيانات الوصفية للمنشور واستخدام دالّة مصفوفة لإعادة الترتيب والحصول على البيانات الوصفية التي يحتاجونها، وبينما قد يبدو ذلك حلّا ذكيّا فهي طريقة ليست في محلّها تمامًا. ففي أول مرّة نستخدم فيها ()get_post_meta تقوم هذه الدالة بسحب كافّة البيانات الوصفية للمنشور بنفسها وتخزين النتيجة بشكل مؤقّت، وبالتالي تستخدم أي استدعاءات لاحقة لنفس المنشور البيانات المخزنة مؤقتًا بدلًا من قاعدة البيانات بشكل مباشر. تأكد قبل اتخاذ أي قرارات مثل القرار السابق أن تُلقي نظرة على توثيق WordPress Codex. 2. تقليل الطلبات نعود لموضوع تقليل الطلبات، فهذا هو واجبك كمطوّر، إن كان قالبك أو إضافتك تستخدم الكثير من ملفّات Javascript وCSS فمن فضلك قم بتجميعها. تقسيم التنسيقات والـسكربات إلى الكثير من الملفّات مُفيد أثناء التطوير، لكن غير مفيد بعد الفراغ منه. نستطيع بعدها استخدام أدوات مثل Gulp لتجميع الملفّات تلقائيًّا، يقود هذا عادةً إلى ملف تنسيقات واحد وملف Javascript واحد بدلًا من العشرات، وستزيد سرعة الموقع كثيرًا. ومن الأدوات القوية الأخرى التي يمكننا استخدامها هي sprites، وهي عبارة عن أداة لجمع الصور، فبدلًا من تحميل أيقونات الموقع بشكل منفصل نستطيع تجميعها في صورة واحدة واستخدام تلك الصورة كخلفية وضبط موقعها تمامًا بحيث يبدو الجزء الذي نريده منها فقط، يستخدم موقع تويتر sprites وكذلك الكثير من المواقع الضخمة نظرًا لخصائصها سهلة الاستخدام للطلب. وعندما نحتاج sprites نستخدم معها الأداة الرائعة Stitches الموجودة على الإنترنت، حيث تسمح هذه الأداة لنا بتحميل الصور وترتيبها على النحو الأمثل لنا، وتوليد التنسيقات التي نحتاجها تلقائيًّا. 3. تصغير حجم الملفات يعمل التجميع Concatenation وتصغير الحجم minification جنبًا إلى جنب، فبعد أن نقوم بعمل ملفاتنا النهائية يجب علينا تصغير حجمها قدر الإمكان، ففي النهاية لن يحتاج المتصفح إلى التعليقات الجميلة، المسافات، الفراغات بين الأسطر، والمسافات البادئة، فهو سعيد جدًّا مع كتلة الشيفرة غير المقروءة. نستخدم أيضًا Gulp من أجل هذا ولكن هناك أدوات أخرى مثل Grunt وأدوات معتمدة على الويب من أجل مهام محدّدة مثل تحسين الصور، التصغير، إلخ. 4. تحميل الـسكربتات في التذييل footer احرص على تحميل الـ scripts في التذييل footer ما لم يتوجب عليك استخدامها في الترويسة header، وعند استخدام الدالة ()wp_enqueue_script قم بتعيين المُعامِل الخامس إلى true ليتم تحميل السكربت في التذييل. سيؤدي هذا إلى زيادة واضحة في سرعة الموقع، بالرغم من أنّه لا يقلّل من عدد الطلبات أو حجم الملفّات ولكن يحرص على تحميل المحتوى الأساسي أولًا، وبالإضافة إلى ذلك إن حدثت مشكلة في script ما فلن يمنع تحميل المحتوى. 5. أعط الأولية للمحتوى الأساسي يمكن إعطاء المُحتويات التي يتم تحميلها أولويّات أيضًا، تمامًا مثل وضع الـسكربتات في التذييل، إن كان الشرط الجانبي يحتوي على معلومات مرتبطة ومحتوى غير أساسي فيجب أن نحرص على تحميله بعد تحميل المحتوى الرئيسي. لن يكون هذا الخيار متاحًا دومًا، ولكن إن حاولنا تحميل المحتوى الهام باكرًا قدر الإمكان سنحصل على موقع يبدو سريعًا وتقييمه مرتفع من وجهة نظر تهيئة المواقع لمحركات البحث SEO أيضًا. 6. استخدام أحجام الصور المناسبة عند عرض الصور في WordPress نستطيع تحديد حجم الصورة التي نريد استخدامها، غالبًا ما نعرف مدى كبر حجم هذه الصور: الصور البارزة featured images، الأيقونات الصغيرة للمنشورات، avatars، وما إلى ذلك. بإمكاننا باستخدام الدالّة ()add_image_size تحديد أحجام هذه الصور، يعني هذا أنّه عندما يتم تحميل صورة سيقوم WordPress بإنشاء نسخة من الصورة المحملة بذلك الحجم. الفكرة هنا هي أنّه إذا كنّا نحتاج صورة بقياس 600×320 يجب علينا الحصول على صورة بذلك الحجم تحديدًا وذلك لسببين: إن حصلنا على صورة أكبر فنحن نقوم بتضييع التّدفّق bandwidth وتقليل السرعة. تأخذ إعادة تحجيم الصورة-للقياس الأكبر أو الأصغر-قوّة معالجة على جهة العميل وتنقص من جودة الصورة. 7. تقليل وتحسين الاستعلامات يمكن أن تؤدي استعلامات قاعدة البيانات إلى انخفاض هام في السرعة بشكل رئيسي نظرًا إلى استخدام الذاكرة، عملت ذات مرّة على مشروع انهار فيه الخادوم عدّة مرات بسبب الاستعلامات الخاطئة حتى قام المضيف بتعطيل الموقع مؤقتًا. يمكن أن نستخدم استراتيجيتين هنا، تقليل وتحسين الاستعلامات، قد يعني تحسين الاستعلامات زيادة عددها لاستبدال تلك التي تستهلك الموارد خاصّة. يجب علينا في البداية تجنب استخدام استعلامات قاعدة البيانات الخام raw في WordPress، توجد الكثير من الدالات تحت تصرفنا للحصول على كل شيء من المنشورات إلى التعليقات، أنواع التصنيفات المخصّصة custom taxonomies، والبيانات الوصفية metadata. إن احتجنا لكتابة استعلام بنفسنا فيجب أن تستخدم الصنف WPDB من أجل أقصى درجات الأمان والكفاءة، كما ينبغي أن نتجنب ضم الجداول أو الأشياء الأكثر تعقيدًا مع بعضها، ففي أغلب الأحيان من الأفضل استخدام استعلامين منفصلين وسريعين. توجد الكثير من الأدوات لمعرفة إذا ما كانت استعلاماتنا مكتوبة بشكل جيّد، ولمشاهدة كافّة الاستعلامات التي تعمل خلال طلب ما. نستطيع استخدام الإضافة Query Monitor أو استخدام: define('SAVEQUERIES', true) في ملف الإعدادات لطباعة كل الاستعلامات عبر: $wpdb->queries نمتلك أيضًا الخيار لتسجيل استعلامات MySQL البطيئة، تعمل هذه الميزة تلقائيًّا للعديد من الاستضافات أو بإمكاننا تشغيلها بأنفسنا أو نطلب من الاستضافة تشغيلها. 8. استخدام تفعيل، تعطيل، وإزالة الخطافات Hooks لا تحتاج العديد من الأشياء التي تنفذها الإضافة أن تعمل في كل طلب، مثل إنشاء أدوار إضافية، إعادة توليد وكتابة القواعد، وإضافة جداول مخصّصة لقاعدة البيانات. فينبغي وضع هذه الأشياء في دالّة التفعيل، والتي تعمل فقط عند تفعيل الإضافة، يخفّف هذا من عبء المعالجة وبالتالي زيادة السرعة. من ناحية أخرى يجب أن نتأكد من إزالتها عند تعطيل الإضافة وإزالتها بشكل تام باستخدام خُطافات hooks التعطيل والإزالة. يساعد هذا على إبقاء قاعدة بيانات WordPress في حالتها الأصلية وتأخير الوقت الذي ستتباطأ فيه بسبب زيادة الأحمال، وعندما يحدث هذا سيكفي تحسين بسيط لإعادة الأمور إلى مسارها. 9. تثقيف العملاء من الصحيح أن العملاء والمستخدمين يتسبّبون في جعل مواقعهم الخاصة بطيئة في الكثير من الحالات ولكن يشكل هذا دافعًا كبيرًا لتثقيفهم، يُساعِد إنشاء توثيق للمستخدم النهائي على الحفاظ على سرعة الموقع، زيادة رضا العملاء، وحتى تخفيف الأعباء علينا على المدى الطويل. ركز تحديدًا على الجوانب التي يمكن أن تسبب مشاكل مثل الاستخدام الصحيح للإضافات، وليس تثبيت 24 أداة تحليل دفعة واحدة مثلًا. الخاتمة: السرعة هي ليست كل شيء نرغب في تأكيد أنّه بالرغم من أن السرعة هامّة جدًّا فهي ليست كل شيء، فبإمكاننا تعطيل جميع الصور وعدم استخدام تنسيقات تقريبًا أو Javascript، قد يقلل هذا زمن التحميل إلى 345 ميلي ثانية ولكن هل يخدمنا هذا في أي غرض عدا عن سباق سرعة لا طائل منه؟ أبق في ذهنك الهدف من موقعك. إن كان هدف موقعك هو التّربّح فينبغي أن تضع كل شيء في خدمة الهدف، يتم عادة تحقيق الهدف عبر الموازنة الذكية بين الأدوات المتعددة، سرعة الموقع هي فقط أداة من هذه الأدوات. ستحتاج إلى جعل الموقع جذابًا من الناحية البصرية وسهل الاستخدام وتوفير المعلومات الضرورية للمستخدمين، يعني هذا عادة الوصول إلى تسوية في نواحي أخرى. يجب عليك أيضًا موازنة التكلفة المالية والزمنية لتسريع الموقع الخاص بك، فدفع مبلغ كبير لشخص أو قضاء شهر في تخفيض زمن التحميل من 3.4 ثانية إلى 1.8 ثانية يستحق العناء، ولكن كلّما كان الرقم الذي منخفضًا أكثركلّما صعب الأمر أكثر. أمّا إنفاق نفس المبلغ الكبير أو شهر من أجل الوصول من 1.8 إلى 1.2 ليس خيارًا جيّدًا، فنستطيع صرف هذه الأموال أو هذا الوقت للحصول على صفقات مبيعات إضافية أو التسويق، أو حتى أخذ فريقك في عطلة. نأمل أن يساعد هذا الدرس على جعل موقعك أسرع وأفضل. ترجمة -وبتصرّف- لـ The Ultimate Mega Guide To Speeding Up Wordpress لصاحبه Daniel Pataki.
  5. سنتحدث في هذا القسم من هذه السلسلة حول زيادة سرعة WordPress عن طرق زيادة سرعة الموقع بالنسبة لغير المطورين. كيفية زيادة سرعة الموقع لقد وعدنا بالإشارة إلى جانبين في هذا الموضوع، طرق مُوجّهة للمطورين وطرق مُوجّهة لغير المطورين، ولكن هذا لا يعني أنّ الطرق المُوجّهة لغير المطورين سهلة الإعداد، سنقوم بالتفريق بينها بناءً على مدى اعتماد الطريقة على البرمجة والشيفرة، وبشكل أساسي أي شيء نحتاج إلى عمله في شيفرة القالب أو الإضافة سيكون ضمن قسم المطورين، وأي شيء آخر سيكون في القسم العام. زيادة السرعة بشكل عام نقصد بزيادة السرعة بشكل عام كافّة الطرق والنصائح التي يمكن القيام بها بدون الاقتراب من شيفرة الموقع (القوالب والإضافات)، قد نحتاج إلى تحرير بعض ملفّات الخادوم واستخدام أوامر الطرفيّة terminal، ولكن بشكل عام لن يقوم المطوّر بهذه الطرق لزيادة السرعة. سنتحدّث عن الأشياء التي يجب القيام بها، حاولنا اتباع القائمة التي تحدثنا عنها في القسم "لماذا يكون الموقع بطيئًا؟" لجعل الأمور أسهل. 1. تحديث التقنيات المستخدمة لن يتمكن 99.99999999% منّا من تحسين PHP، ولكن بإمكانهم التأكّد من أنّه تمّ تحديثها، ومن خلال تجربتنا فإنّه كلما كانت الاستضافة مكلفة كلّما قاموا بتحديث PHP من أجلنا بشكل تلقائي، تقوم بعض الخواديم قليلة التكلفة بتحديث إصدار PHP إن طلبنا منها، ولكنّها لا تقوم بهذا تلقائيًّا. إن ألقينا نظرة على بعض قياسات أداء PHP فسنعرف لماذا هذا مهم. كما نرى قد تشكّل التحديثات المختلفة لـ PHP تأثيرًا كبيرًا خاصّة مع الإصدار الجديد وهو PHP 7. تختلف طريقة تحديث إصدار PHP بحسب المضيف، إن قمنا بتسجيل الدخول إلى مضيفنا وبحثنا عن إعدادات PHP فقد نجد صندوقًا يسمح لنا بالاختيار بين الإصدارات المختلفة. ولكن قبل القيام بالتبديل إلى إصدار آخر يجب أن نعلم بوجود بعض المخاطر من تحديث PHP، لن تختفي شيفرة وملفات الموقع ولكن إن كانت لدينا شيفرة قديمة تعمل فقد تظهر أخطاء غير متوقعة، إن لم تكن متأكدًا من ذلك فقم بسؤال مضيفك إن كان بإمكانك العودة للإصدار القديم في حال حدوث أخطاء. 2. تحديث نظام إدارة المحتوى CMS لا زلنا نرى بعض المواقع تعمل على WordPress 3.5 والذي صدر منذ سنتين ونصف، لا تزوّدنا تحديثات نظام إدارة المحتوى عادةً بزيادة سرعة هائلة من إصدار إلى آخر، ولكنّها تقوم بإصلاح مشاكل أمنية. قد تؤدي الثغرات الأمنية في موقعنا إلى حقن شيفرة خبيثة بداخله والتي قد تبطئ سرعته بمقدار النصف. تقوم تحديثات نظام إدارة المحتوى أيضًا بتحسين النظام، ممّا يسمح بكتابة شيفرة أفضل من أجلها، وكنتيجة لذلك تصبح قاعدة البيانات أقل ازدحامًا والاستعلامات أسرع، ويترجم هذا إلى زيادة معدل السرعة مع الوقت. لا تتوقع قفزة في السرعة بالانتقال من إصدار WordPress 4.2 إلى 4.3، ولكن ما يمكن توقعه هو أنّك إذا كنت حريصًا على التحديثات هو وقت أطول بكثير بين انخفاضات السرعة بسبب ازدحام قاعدة البيانات البسيط على سبيل المثال. 3. تقليل الطلبات سنتحدث عن هذا الموضوع بالتفصيل في قسم المطورين لأنّه من الأسهل إصلاحه أثناء كتابة قالب أو إضافة، ولكن توجد بعض الأشياء التي يمكن أن يقوم بها المستخدم لتحسين هذا الأمر. ولكي نعرف في البداية عدد الطلبات التي يقوم بها موقعنا نستطيع استخدام العديد من الأدوات، بإمكاننا مشاهدة جميع الطلبات في أدوات المطورين الخاصّة بالمتصفح، أو باستخدام أدوات معتمدة على الويب مثل Pingdom للحصول على فكرة عامة جيدة. عند إضافة المحتوى إلى الموقع نقوم بزيادة الطلبات بإضافة الصور وعناصر الوسائط الأخرى، نقوم بشكل أساسي بزيادة طلب واحد لكل عنصر. إن أضفنا معارض إلى منشوراتنا وتمّ عرض أول 5 صور على صفحات الأرشيف أيضًا، فقد نكون الآن أمام 60-70 طلب في صفحة واحدة. إن كنت مصوّرًا، فنّانًا، أو شخصًا محبًّا للصور فربما لا ترغب بإضافة صور أقل، في هذه الحالة يفيد تقليل عدد المنشورات في الصفحة، أو إظهار صور أقل على صفحات الأرشيف. ولتقليل عدد المنشورات في الصفحة نذهب إلى إعدادات القراءة reading settings في WordPress وتقليلها إلى 8 أو 6. يجب أن نأخذ أيضًا في عين الاعتبار تقليل الإضافات التي تؤثّر على واجهة الموقع، تضيف العديد من الإضافات تنسيقات و scripts خاصّة بها، يوفّر تعطيلها 1-2 طلب إن كانت الإضافة مبرمجة بشكل جيّد أو 7-8 طلبات إن كانت سيئة البرمجة. يوفّر تبديل القوالب الكثير من الطلبات أيضًا، بالرغم من أنّ هذا خيار غير عملي في الكثير من الحالات، نلاحظ أنّ القوالب المدفوعة خاصّة -والتي توفّر جميع الميزات بشكل كامل- تميل إلى تحميل العديد من التنسيقات والـ scripts بشكل غير ضروري. تحميل الصور المتأخّر Lazy loading images هو أداة قويّة تزيد من سرعة الموقع، هي لا تقلل من الطلبات في الواقع ولكنّها تقلل من الحاجة إلى تحميلها، تكمن الفكرة وراء التحميل المتأخر في أنّ الصور التي تظهر لاحقًا في الصفحة لا تحتاج أن يتم إظهارها حتى ينزل المستخدم قريبًا منها، توجد مقالة رائعة حول مقارنة بين 6 إضافات للتحميل المتأخر، ألق نظرة عليها من أجل المزيد حول هذا الموضوع. إنّ أحد أفضل الطرق لتقليل الطلبات هي الجمع concatenation، والتي سنتحدث عنها بالتفصيل في قسم المبرمجين، فبدلًا من تحميل 10 ملفّات Javascript بإمكاننا نسخها ولصقها بالتتالي في ملف واحد، ويعني هذا أنّه بدلًا من تنزيل 10 ملفّات بحجم 20 كيلوبايت لكل ملف نستطيع تنزيل ملف واحد بحجم 200 كيلوبايت وهو أسرع بكثير، من السهل فعل هذا أثناء برمجة الموقع ولكن يصبح الموضوع أصعب بكثير بعد حدوث هذا. تقوم بعض الإضافات مثل: Merge + Minify + Refresh ،MinQueue، و Dependency + Minification بهذه العملية تلقائيًّا نوعًا ما، قم بتجربتها وإن عملت بشكل جيّد فسيتم تقليل الطلبات بشكل ملحوظ في موقعك. وبينما لا نفضّل المنشورات التي تحتوي على ترقيم للصفحات pagination ضمنها، ففي بعض الحالات قد يكون من المنطقي تقسيم منشور إلى صفحات متعدّدة، ولكن لا تفعل هذا لزيادة مشاهدات الصفحة، ولكن إن كنت تملك مقالًا كبيرًا جدًّا يعرض 500 فندق المفضلة لديك مثلا مع صورها فقد تكون فكرة جيّدة أن نفصلها إلى أقسام وكل قسم يحتوي على 25-50 فندق. 4. إزالة الإضافات غير الضرورية لا تزيد الإضافات من الطلبات فحسب، ولكن قد تؤدي إلى جميع أنواع المشاكل مثل مشاكل الذاكرة أو حتى مخاطر أمنيّة، توجد إضافة رائعة تُدعى P3 Plugin Performance Profiler تمكننا من التعرف على الإضافات الأكثر إشكاليّة. نستطيع أيضًا تعطيل أي إضافة نستخدمها نادرًا، فمثلًا إذا كنّا نستخدم عادة أدوات مثل Thumbnail Regenerator و Theme Check، أو P3، وهي أدوات لا تقدّر بثمن حين استخدامها ولكن ربّما نحتاجها مرّة في الشهر، لذلك عند عدم استخدامها يفضل تعطيلها للتأكد من عدم تأثيرها على الأداء. 5. إزالة الأشياء الجميلة غير الضرورية توجد العديد من عناصر التصميم والوحدات -الموجّهة بشكل أساسي بواسطة JavaScript- في الموقع والتي تبدو جميلة ولكن غير منطقيّة، فلننظر إلى مثالين عن هذا الموضوع. يتعامل المثال الأول مع العناصر المُحبِطة، فلنفترض أنّه لدينا قائمة مستخدم تنطوي باستخدام تحريك رائع عندما نحوم hover حولها، عندما يراها المستخدم لأول مرّة سيجد أنّها رائعة جدًّا، ولكن بعد الاستخدام الثالث لها سيجدها مزعجة، فلماذا يجب عليه الانتظار لمدة ثانية كي تظهر القائمة؟ يحدث هذا بسبب عدم استخدام المبرمجين وأصحاب الموقع لهذا الموقع بنفس الطريقة التي يستخدمها فيه المستخدمون، فعادة يقوم المبرمج بتسجيل الدخول للموقع عن طريق زيارة /wp-admin/، أما المستخدم فيقوم بتسجيل الدخول عن طريق الرابط الموجود في الترويسة، تأكد أن تمنح المستخدمين تجربة مرنة، وليس فقط أن تبدو رائعة ولكن تصبح محبطة مع مرور الوقت. وبغض النظر عن الجانب البصري فسيجني موقعنا بعض فوائد السرعة، سيكون هناك عناصر أقل لتحريكها، و Javascript أقل بالمجمل، والذي يُترجَم إلى موقع سريع فعليًّا. المثال الثاني هو حول الكفاءة والتحويل، المثال المفضّل هنا هو الـ sliders، فكل بحث عنها ينتهي بنفس النتيجة وهي أنّ الـ sliders سيّئة بكل ببساطة، ولا أحد يستخدمها، فهي تأخذ مساحة كبيرة جدًّا، وتقلّل تهيئة الموقع لمحركات البحث SEO، وتأخذ قدرًا كبيرًا من سرعة الموقع. نريد أن نشدّد على أنّ هدف موقعنا هو ليس أن يبدو جميلًا فحسب، فكونه جميلًا هو أداة تستخدم لتحقيق الهدف الحقيقي وهو جني الأموال، فإن أكّدت كل الأبحاث على حقيقة أنّك يجب أن تتخلص من الـ slider، إن كان هذا يزيد أرباحك فهل تهتم حقًّا؟ يجب أن تنظر إلى جميع عناصر موقعك وتتخذ بعض القرارات اللازمة بخصوصها، اقرأ حول الموضوع، اعمل أبحاثك، والأهم من ذلك كله هو أن تقيس النتائج. ضع في ذهنك أيضًا أنّه في بعض الحالات تكون الإزالة أمرًا جيّدًا، وفي بعض الحالات الأخرى قد ترغب في استبداله بعنصر آخر، فقد تؤدي إزالة الـ slider ببساطة إلى معدّل تحويل منخفض، أمّا استبداله بنص وروابط بسيطة سيرفع ذلك إلى فوق مستوى تأثير الـ slider. 6. استخدام شبكة تسليم محتوى CDN تجعل شبكات تسليم المحتوى CDN من كافّة الأمور الخاصّة بالموقع أبسط وأسرع، فهي تسمح باستضافة الصور خارج الخادوم وتقلّل زمن تحميل الصور. تقوم استضافة الصور خارج الخادوم بفصل المحتوى عن الوسائط، فبإمكاننا تغيير النطاق، والانتقال من استضافة إلى استضافة أخرى، وستبقى الوسائط دومًا في نفس المكان، قد تأخذ قاعدة بيانات الموقع والقالب تقريبًا 10-25 ميغابايت، ولكن قد يبقى لدينا حوالي 2 غيغابايت من الصور لنقلها أيضًا، إن كانت كل هذه الصور مستضافة خارج الخادوم فكل ما سنهتم بشأنه هو الـ 25 ميغابايت وهي ليست كثيرة. بالعودة لموضوع السرعة فإنّ الفكرة وراء شبكة تسليم المحتوى CDN (Content Deliver Network) هو وضع الموارد المطلوبة قريبًا منك جغرافيًّا، إن موقعي مستضاف في الولايات المتحدة ولكنني أستخدم Amazon Cloudfront كشبكة تسليم محتوى، ويعني هذا إن قمتَ بالوصول إلى موقعي من كاليفورنيا فقد تستقبل الصور من مركز بيانات بداخل الولاية. في هذه الأثناء قد أكون أنا في مركز أوروبا في بودابست، لذا قد أستقبل نفس الصور من مكان آخر قريب مثل برلين، يقلل هذا من زمن النقل، والـ hops (وهي عدد الموجهات، الجدران النارية، إلخ.. التي تحتاج البيانات المرور خلالها)، ومُعامِلات آخرى ممّا يؤدي إلى موقع أسرع. 7. تفعيل التخزين المؤقت Caching التخزين المؤقت Caching هو الطريقة الأولى التي يجب استخدامها لأنّها قد تؤدّي إلى معظم التحسينات الجذرية، يمكن فهم الفكرة وراء التخزين المؤقّت بمقارنة بسيطة، هل تذكر عندما تعلّمت الجمع لأول مرّة في المدرسة؟ كنت تحتاج أن تحسب 5+4 بشكل ملموس، فكنت تستخدم أصابعك أو أي شيء في المتناول (في حالتي تعلّمت باستخدام مكعبات السكر) لحسابها. أمّا الآن فقد أصبحت تتذكر الإجابة فقط وتلقائيًّا تعرف أنّها 9، فقد قام عقلك بتخزين النتيجة من أجلك، فلن تحتاج لعدّها بعد الآن. في حالة المواقع توجد بعض الاختلافات، فنتيجة المعادلة ليست دومًا نفسها ! وهذا هو السبب، تخيّل موقعًا لا يعرض شيئًا سوى اسمك والسنة الحاليّة، تتغير محتويات هذا الموقع فقط مرّة في السنة، ومع ذلك في كل مرّة تقوم فيها بتحميل الموقع يحسب الخادوم ما هي السنة الحاليّة. إنّ الشيء الذي يقوم به التخزين المؤقّت بشكل أساسي هو تخزين نسخة HTML من الموقع لفترة محدّدة، في مثالنا السابق كان بإمكاننا تعيين انتهاء مدة التخزين المؤقّت مرّة في اليوم، ويعني هذا أنّه يتم تحميل الموقع مرّة واحدة في اليوم بشكل طبيعي، وسيقوم باكتشاف طلب، يجعل الخادوم يعالج الشيفرة ويعيد النتيجة كـ HTML، وسيحفظ أيضًا نتيجة الـ HTML في الذاكرة. وفي المرّة التالية التي يقوم فيها أحدهم بتحميل الموقع يقوم التخزين المؤقّت بتحميل الـ HTML من الذاكرة، بدلًا من أن يجعل الخادوم يعالج هذا الطلب، لن يكون هذا كثيرًا بالنسبة لمثال بسيط كهذا ولكن من أجل موقع متوسّط قد يوفّر هذا عدّة ثوان من زمن التحميل. المثال الذي وصفناه هو عبارة عن تخزين مؤقّت كامل للصفحة، توجد العديد من الأنواع الأخرى، فالتخزين المؤقّت هو مهنة في حد ذاته، ومن حسن الحظ بإمكانك البدء بسهولة إن كنت تعمل ضمن WordPress. هنالك الكثير من الإعدادات لكل إضافة، نوصي بقراءة كل إعداد للحصول على أفضل أداء. بإمكاننا القول أنّك إذا استخدمت الإعدادات البسيطة فقط ستحقق على الأقل 80% من أقصى سرعة قد تصل إليها، لذا فهي تستحق البدء معها حتى لو كنت مبتدئًا. يجب أيضًا أن تنتبه أنّه يمكن تحقيق تخزين مؤقّت أفضل على مستوى الخادوم، توفّر بعض خدمات ووردبريس (شركات استضافة مُتخصّصة في ووردبريس) تخزينًا مؤقّتًا على مستوى الخادوم والذي يكون أسرع دائمًا، لا تسمح معظم هذه الاستضافات لنا بتثبيت إضافات تخزين مؤقّت لأنّها ببساطة ستؤدي إلى موقع أبطأ. 8. تحسين قاعدة البيانات مع مرور الوقت ستجد أن قاعدة البيانات تحتفظ بيانات كبيرة الحجم لكن لم تعد هناك حاجة لها، وهو شيء لا يمكن تجنبه تقريبًا، هنالك قسمان رئيسيان لهذه المعادلة: البيانات غير المستخدمة والأحمال الزائدة على مستوى قاعدة البيانات database-level overhead. قد تأتي البيانات غير المستخدمة من عدة أماكن، فإن كنّا نملك بعض الحلول المخصّصة لحذف المستخدمين فمن المحتمل ألّا تحذف الطرق المستخدمة البيانات الوصفية المرافقة، وقد يترك هذا مئات الأسطر في قاعدة البيانات غير المرتبطة بأي أحد. وربّما نكون قد استخدمنا عددّا من الحقول المخصّصة في قاعدة البيانات والتي لم نعد بحاجة إليها، وحيث أنّ هذه الحقول المخصّصة ربّما تمّت إضافتها إلى مئات المنشورات فنحن نتحدث عن مئات أو حتى آلاف الأسطر. وبخصوص الأحمال الزائدة على مستوى قاعدة البيانات فبإمكاننا استخدام أدوات مبنيّة في MySQL والتي تعتني بهذا تلقائيًّا، وهذا يُدعى تحسين الجدول، وهو مشابه جدًّا لعملية إلغاء تجزئة الأقراص. 9. تحسين الصور تحدّثنا عن استخدام صور أقل، فلنهتم الآن بموضوع الصور التي يجب علينا فعلًا استخدامها، إنّ ضغط الصور قد يجعل حجمها أصغر بمقدار 30%-80% بدون أي فرق واضح. إنّ أحد أفضل الأدوات التي يمكن استخدامها هي WP Smush Pro والتي تستخدم من قبل 200 ألف موقع ووردبريس، نستطيع أيضًا استخدام أدوات مثل Photoshop عند حفظ الصور. يمكن استخدام Imageoptim على نظام OS X لتحسين الصور أو استخدام RIOT على Windows. 10. تمكين ضغط Gzip يمكن لهذا أن يعطينا سرعة كبيرة، يقوم ضغط Gzip بضغط العديد من الموارد قبل إرسالها إلى المتصفح، وهو شيء يجب إعداده على الخادوم. إنّ السبب الذي يساعد على هذا هو استخدام CSS و HTML للكثير من المحتوى المُكرَّر، وكلّما زادت الأنماط التي نملكها في محتوانا كلّما زادت القدرة على ضغطه، فعلى سبيل المثال إن كانت لدينا جملة "Daniel is Awesome" مكررة 100 مرّة في شيفرة موقعنا فيمكنن استبدال النص بـ "12d" وتوفير الكثير من المساحة، وهذا هو جوهر أي عملية ضغط وكلّما زادت الأنماط لدينا (وزاد طولها) كلّما تمكنا من تحقيق ضغط أعلى. 11. تعطيل الربط الساخن Hotlinking قد لا يزيد هذا من سرعة الموقع بشكل مباشر، ولكنّه يخفف من الحمل عن الخادوم خاصّة إن كنّا نملك موقعًا معروفًا، الربط الساخن Hotlinking هو أن يقوم موقع ما باستخدام صورك المرفوعة على خادومك على صفحات موقعه. أي بمعنى آخر بدلًا من أن يقوم هذا الموقع بحفظ الصورة ورفعها على خادومه الخاص يقوم فقط باستخدام رابط الصورة التي رفعتها أنت على موقعك، وهو ما يُمكن اعتباره سرقة للتّدفّق bandwidth بشكل فعّال، وهو تمامًا مثل سرقة Wifi شخص آخر. 12. اختيار استضافة جيدة لن نخوض في هذا الموضوع بالتفصيل لأنّه قد يأخذ عدّة دروس لوحده، إنّ اختيار استضافة جيدة هو فن ومقامرة بعض الشيء ما لم نكن على دراية جيدة جدًّا في هذه المسألة. إن دليلنا المبسط حول هذا الموضوع هو التالي: لا تستخدم الاستضافة المشتركة ما لم تكن مضطرًا إلى ذلك، أو تملك الكثير من المواقع التي لا تستخدمها كلّها، تكلّفك هذه الاستضافات القليل وستحصل على خدمة مماثلة للسعر الذي تدفعه، إنّ الخدمات غير الجديرة بالثقة عرضة لتوقفها عن العمل نظرًا لاستخدام الموارد المفرط من الآخرين. لا نوصي أيضًا بالحصول على استضافة مُخصّصة dedicated hosting، فإن لم تكن تعلم ما تفعله ستخسر وإن حصل ذلك فلن تحتاج إلينا كي نخبرك عن نوع الاستضافة التي تحصل عليها، إن الاستضافة المخصّصة هي غالبًا من أجل الأشخاص الذين يملكون خبرة في التعامل مع وإدارة الخواديم أو من أجل المواقع التي لديها استهلاك كبير جدًّا. إن كنت تملك موقعًا معروفًا جدًّا ويتطلب خواديم مخصّصة له فينبغي عليك النظر في توظيف شخص يعلم حول جميع التقنيات في هذا الموضوع. يبقى لدينا خياران، الـ VPS هو خيار جيّد، أعتقد أنّه يوجد خطط تكلّف 5-50$ شهريًّا، يملك الـ VPS ذي المواصفات الجيّدة قدرات أكثر من الخواديم المنفصلة ذات المواصفات المتدنية، لذا قد تحصل على صفقة جيدة هنا. لا تعاني خواديم الـ VPS (غالبًا) من تأثير الجيران السيئين، فهي تعطينا موارد أكثر وتزوّدنا غالبًا بخدمات إضافيّة مثل النسخ الاحتياطي، التحديثات التلقائيّة، والمزيد. ومن الخيارات الأخرى هي استضافة WordPress المُدارة، يوفّر هذا النوع من الاستضافات منهجية متمركزة حول WordPress، فبإمكاننا على VPS أن نشغل أي تطبيق نريده، أمّا استضافات WordPress المُدارة فهي تسمح فقط بـ WordPress. وكنتيجة لذلك تكون الخواديم مبنية خصوصًا من أجل WordPress وتوفّر تخزين مؤقّت على مستوى الخادوم وأشياء أخرى تجعل من موقعنا يعمل بسرعة كبيرة. ومن ناحية أخرى هناك بعض القيود على الأشياء التي بإمكاننا فعلها، فقد تقوم الاستضافة بتعطيل بعض الإضافات والقوالب من أجل موضوع السرعة والمخاوف الأمنية، في النهاية تخدّم هذه الاستضافات أغراضنا بشكل جيّد ولكنها قد لا تعجب البعض. نوصي بالتحدث إلى خدمة الزبائن وشرح احتياجاتك لهم بالتفصيل، فهم سيساعدونك على أخذ القرار وستأخذ فكرة عن مستوى الدعم الفني الذي ستحصل عليه. 13. مراقبة الموقع لن يزيد هذا من سرعة الموقع ولكن سيعطينا تنبيهًا عند حدوث خطأ وسنكون قادرين على معرفته في الوقت المناسب، إنّ التعامل مع مشكلة السرعة قبل أن تصبح ظاهرة هو طريقة رائعة لجذب المستخدمين. تتمكن خدمات مراقبة النطاق مثل Deez.io و Pingdom من اختبار الموقع بشكل منتظم تلقائيًّا. الخاتمة تحدثنا في هذا القسم عن طرق زيادة سرعة الموقع بالنسبة لغير المطورين وسنكمل في قسم لاحق عن طرق زيادة السرعة بالنسبة للمطورين. ترجمة -وبتصرّف- لـ THE ULTIMATE MEGA GUIDE TO SPEEDING UP WORDPRESS لصاحبه Daniel Pataki.
  6. قمت قبل عدّة سنوات ببناء موقع عميل لا يزال ناجحًا حتى اليوم ولكنّه أصبح بطيئًا بشكل محبط، فقاعدة البيانات مليئة بالفوضى وتستغرق بعض الصفحات 26 ثانية لتحميلها نظرًا لعدد الصور والطلبات الأخرى التي تقوم بها إلى الخادوم. قرّرنا أنّه حان الوقت لفعل شيء حول هذا الموضوع وإعادة بناء الموقع، وتطبيق تقنيات السرعة المُجرَّبة، والتي قلّلت زمن التحميل إلى ثانيتين على الصفحات المعقدة، وإلى 800 ميلي ثانية على الصفحات البسيطة. سنتحدّث في هذه السلسلة عن الإصلاحات التي فعلناها لكي تقوم بتحسين زمن تحميل موقعك الخاص، بما في ذلك تحسينات السرعة العامة والتحسينات المرتبطة بالتطوير. هذه السلسلة هي ليست مجرّد درس لتقديم بعض النصائح حول زيادة سرعة WordPress، ففي هذه السلسلة الشاملة سنتعلّم خطوة بخطوة ونمر على كل جانب لتحسين وزيادة سرعة موقع WordPress. أهمية سرعة الصفحةلن تتحمل تجاهل سرعة الصفحة إن كنت تكسب لقمة العيش من موقعك، فقد قام موقع Loadstorm بوضع بعض نتائج الأبحاث في رسم بياني جميل يُظهِر أنّ زيادة ثانية واحدة في زمن تحميل الصفحة page load تقود إلى خسارة 7% من التحويلات، مشاهدات للصفحة أقل بنسبة 11%، وانخفاض بنسبة 16% في رضا الزبائن. وبقلب هذه الإحصائية يتضح أنّ تقليل زمن تحميل موقعنا بمقدار ثانية واحدة قد يؤدي بسهولة إلى زيادة في الربح بمقدار 7%. قد ينسى الناس أيضًا أنّ جودة خدمة الإنترنت ليست موحّدة في أرجاء العالم، حتى لو استخدمنا CDN (شبكة تسليم محتوى) وقمنا بتحسين كل شيء. فربّما يتم تحميل صفحتنا خلال ثانيتين في نيويورك، وتستغرق 2.3 ثانية عند شخص يعيش في دبلن، ولكن ربّما يتم تحميلها في 4-5 ثوان في الهند. فبتحسين الأمور ربّما نقلل زمن تحميل الصفحة في الولايات المتحدة بمقدار 0.3 ثانية، ولكن ربّما يقلّل ذلك من زمن التحميل بمقدار 1.8 ثانية في الهند والذي يؤدي إلى زيادة في المبيعات، يجب ألّا ننسى أنّ الويب ضخم وأي رقم يتم عرضه هو معدّل وأي عدد نتعامل معه هو عيّنة واحدة من مجموعة متنوعة بشكل كبير. وبالإضافة إلى الفوائد المباشرة فمن المعروف أنّ سرعة الصفحة لها تأثير كبير على تهيئة الموقع لمحركات البحث SEO، لقد أبقت Google هذه التفاصيل مبهمة عن قصد، ولكن تسلّط بعض الأبحاث الضوء على الارتباطات الممكنة، على أيّة حال هنالك شيء واحد مؤكّد وهو أنّ السّرعة الأفضل تعني مرتبة أعلى في نظر Google. إن كنت مهتمًا بمجال البيئة فتستطيع التفكير بهذا كتمرين لتقليل انبعاثات الكربون، ينتج الموقع الأسرع عادة عن معالجة أقل، طلبات أقل، وبيانات أقل، وهذا يعني أن الحواسيب التي تتعامل مع موقعنا تعمل بشكل أقل، مما يؤدي إلى تقليل الحرارة المنبعثة عنها وبالتالي يعني تقليل حاجتها للتبريد، لن يلاحظ هذا التأثير غالبًا على مستوى خادوم وحيد ولكن يمكن قياسه على نطاق واسع. كيفية البدءسنقسم هذه السّلسلة إلى ثلاثة أجزاء، سنتحدث في هذا الجزء حول بعض الاعتبارات العامّة ونجرب ونحصل على الفروق الدقيقة لمشاكل السرعة وأسباب بطء الموقع، سيركز القسمان اللاحقان على التحسينات التي يستطيع أي مستخدم القيام بها والتحسينات التي يستطيع المبرمج القيام بها، سيكون هناك بعض التداخل في القسمين الأخيرين، ونحث غير المبرمجين على الاطلاع على كلا القسمين، يمكن تطبيق العديد من خطط زيادة السرعة عن طريق إرشادات بسيطة بالرغم من أنّها قد تمتلك بعض الشيفرة المتعلقة بها. نأمل في النهاية أن يأخذ الجميع بعض الأفكار ويطبقها مباشرة كي يصبح الويب مكانًا أسرع للجميع. لماذا يكون موقع الإنترنت بطيئا؟إنّ فهم هذا الأمر هو المفتاح لاتّخاذ قرارات ذكيّة، يوجد فرق كبير بين موقع يعمل ببطء لأنّه موجود على خادوم قليل التكلفة، وبين موقع يعمل ببطء بسبب عدم كفاءة الشيفرة أو تحميل الصور بشكل هائل. لاحظ أنّ القائمة التالية لا تحتوي على عناصر يمكن إصلاحها دومًا، سندرج كافة الطبقات المنفصلة التي تضيف إلى سرعتنا، ستكون وظيفتنا لاحقًا هي تحسين هذه السرعة، فلنتعلم الآن حول كافّة المكونات. تقنيات بسيطةتحدّد اللغة والتقنية البسيطة التي نستخدمها لتشغيل موقعنا مدى سرعة معالجة الشيفرة على الخادوم، إن استخدمنا HTML فقط فلن تكون هناك مشكلة، ولكن تستخدم معظم المواقع لغة برمجة من ناحية الخادوم server side programming. قد نستخدم ASP.net، PHP أو ربّما HHVM لتنفيذ شيفرة PHP، لا يوجد الكثير مما يمكننا القيام به لزيادة السرعة في اللغات الأساسيّة. ورغم أنني لست خبيرًا أعتقد أنّ ASP.net تمتلك تقنيًّا القدرة على أن تكون أسرع من PHP، لكن الاختلافات تبقى طفيفة. بدأت HHVM تفوق PHP منذ صدورها، ولكن كلا التقنيتان بدأتا بخوض حرب (وديّة) ويبدو الآن أنّ PHP 7 الجديدة ستتفوق على HHVM والتي نأمل أن تحفّز حلقة زيادة أداء من هاتين التقنيتين تجعلنا نحن المستخدمون النهائيون في غاية السعادة. ومن النقاط التي قد تصنع فرقًا هي الطريقة التي تمّ بها إعداد خادومنا، يمكن على سبيل المثال إعداد الخواديم لترسل البيانات بصيغة مضغوطة معروفة بضغط gzip، وهو إعداد بسيط يمكننا تشغيله وإيقافه، حيث أنّ تشغيله بوضوح يزيد سرعتنا، سننظر إلى مثل هذه التقنيات لاحقًا. نظام إدارة المحتوى Content Management Systemكقاعدة عامّة أي نظام إدارة محتوى CMS أبطأ من موقع ثابت static مصنوع بشكل مناسب بواسطة HTML، ومع أنّه صحيح أنّ التخزين المؤقّت لكامل الصفحات total page caching قد يقلّل فروقات السرعة ففي بعض الأحيان تحتاج التخزينات المؤقّتة إلى نهاية صلاحيتها، ولا يحصل المستخدمون قيد تسجيل الدخول عادةً على إصدارات مُخزّنة مؤقّتًا، كما يستهلك محتوى الإدارة موارد أكثر دومًا. يفيد نظام إدارة المحتوى المبني جيّدًا أكثر ممّا يضر بكثير، فهو أكثر أمانًا ونكون قادرين من خلاله على إضافة المحتوى بسهولة أكثر ويزوّدنا بالكثير من الميّزات التي نستطيع تطبيقها في أي وقت، تندرج جميع أنظمة إدارة المحتوى المعروفة تحت تصنيف مصنوعة بشكل جيّد، لذا فإنّ WordPress، Joomla، Drupal وأنظمة أخرى جيّدة من وجهة نظر السرعة. قد تكون مشاكل السرعة شائعة أكثر في بعض الأنظمة من الأنظمة الأخرى، ولكن يتعلّق هذا عادةً بالشيفرة الإضافيّة التي يتم استخدامها مثل القوالب themes، الإضافات plugins، المُلحقات extensions وما يشابهها، والتي سنلقي نظرة عليها لاحقًا. إنّ السبب الذي يجعل من أنظمة إدارة المحتوى أبطأ من المواقع الثابتة هو أنّها تحتاج إلى الاتصال إلى الخادوم، ويحتاج الخادوم إلى معالجة الطلب وتوليد شيفرة HTML ومن ثمّ إرسالها إلى المتصفّح، وقد توجد خلال هذه العمليّة العديد من استعلامات قواعد البيانات database queries التي تحتاج إلى تنفيذها والتي تزيد أيضًا من زمن التحميل. تمتلك معظم الأنظمة آليات لتحسين هذه العملية ولهذا تميل المواقع إلى تحميلها خلال عدّة ثوان، ممّا يجعل من هذه الأنظمة حلًّا عمليًّا. الملحقات Extensionsونقصد هنا المُلحقات بشكل عام، أي شيفرة مستخدمة على نظام إدارة المحتوى لدينا، تعني هذه بالنسبة لـ WordPress القوالب themes والإضافات plugins، وتُدعى في Joomla وDrupal القوالب templates والمُلحقات extensions. في كثير من الأحيان لا يتم إنشاء القوالب والإضافات من قبل نفس الأشخاص الذين صنعوا نظام إدارة المحتوى، ويعني هذا أنّه إن لم يكن المطورون على دراية بأفضل الأساليب المستخدمة حاليًّا فربّما يرتكبون بعض الأخطاء. توجد أثناء البرمجة العديد من الطرق التي نحصل من خلالها على شيفرة دون المستوى الأمثل بدون ظهور أخطاء فعليًّا. على سبيل المثال إن فكرنا باحتياجاتنا للبيانات ربّما نجد طريقة لاستعلام قاعدة البيانات مرّة واحدة خلال عمليّة ما. وإن لم نفكر جيّدًا ربّما نستخدم ثلاثة استعلامات، وفي الحقيقة قد تكون الاستعلامات الثلاثة أحيانًا أسرع من استعلام واحد بحسب احتياجاتنا، لذا فإنّ اختيار الطرق بعناية هام جدًّا. سنلقي نظرة على التقنيات المحدّدة للبرمجة والتي تبطّئ شيفرتنا، حاليًّا يجب أن نعلم أنّ المُلحقات تضيف طبقة من زمن التحميل لموقعنا. في WordPress يتم تضخيم السلبيات إلى حد ما بسبب حقيقة أن مجتمع WordPress مفتوح جدًّا، وهذا هو الجانب الرائع لـ WordPress والتي لا يجب أن يتم تغييرها ولكن يوجد لها عيوبها، فهي تجعل من السهل المساهمة بشيفرة سيئة، فلن يتمكن شيء من إيقافك (ولا ينبغي أن يوقفك أي شيء) من إنشاء قالب مُبرمَج بشكل سيء ومن ثم بيعه إن أردت. الخواديم والاستضافةالخادوم هو مكوّن كبير في تحديد سرعة الموقع، خاصّة الفترات التي يكون لديك فيها زيارات كثيرة، فلنقم بفصل هذين المصطلحين أولًا ونتعلّم المزيد كيف يؤثران على السرعة. إنّ خادومنا هو عبارة عن حاسوب حقيقي في مكان ما ويمتلك خصائص مشابهة للحواسيب المنزلية، فهو يمتلك ذاكرة، معالج، قرص صلب ومعاملات أخرى تحدّد كيفيّة عمله. إنّ خطة الاستضافة hosting plan هي أساسًا عبارة عن حزمة من الخدمات مربوطة بالخادوم، وتتضمن أشياء مثل النسخ الاحتياطيّة التلقائيّة، إدارة الخادوم، إلخ. ومن أجل زيادة سرعة موقعنا فإنه يجب أن نعرف أهم عامل يتعلّق بخطة الاستضافة، يعني هل موقعك مُستضاف على خطة مشتركة (shared plan)، خادوم VPS، أو خادوم مخصّص. خطة مشتركة، VPS، والخادوم المخصّصتمثل هذه المصطلحات الثلاث أنواعًا مختلفة من منهجيات الاستضافة، وهي تحدّد بشكل مُبسّط عدد الأشخاص الذين يستخدمون نفس الخادوم لاستضافة موقاعهم كما تفعل أنت. على الخدمات المشتركة قد تجد مئات الأشخاص على نفس الخادوم، ويعني هذا تشارك مئات الأشخاص لنفس مساحة القرص الصلب، الذاكرة، سرعة المعالج والتّدفّق bandwidth، لا تتم مشاركة الموارد بالتساوي، فقد يستخدم أحد المواقع حتى 80% من موارد الخادوم، تاركًا 99 مستخدم آخر على الـ 20% الباقية أو حتى أسوأ.تتم مشاركة الـ VPS (الخادوم الخاص الافتراضي Virtual Private Server)، ولكن عادةً بين أعداد مستخدمين أقل مع تقسيم الموارد بالتساوي، فإن كان هناك 5 مستخدمين على نفس الخادوم فسيحصل كل واحد منهم على 20% من الذاكرة على سبيل المثال، وإن حاول أحد المستخدمين تجاوزها فسيفشل موقعه ولكن تبقى مواقع المستخدمين الآخرين تعمل بشكل جيد.على الخادوم المخصّص تكون أنت المستخدم الوحيد للخادوم وكافّة موارده، وهذا يلغي تأثير الجيران السيئين الذي يحصل في الخدمات المشتركة وتمتلك المزيد من الموارد تحت تصرفك من الـ VPS (عادةً).إعدادات الخادوم Server Parametersيمتلك الخادوم الذي يوجد عليه موقعنا بعض الخصائص الرئيسية كما أشرنا والتي تحدد سرعته، وبشكل أساسي كلّما زاد أداء الخادوم كلما تحسّن أداء الموقع الموجود عليه. هناك طبعًا بعض الاستثناءات لهذا، فإن كنّا نملك موقع WordPress صغير مع عدد زيارات يُقدّر بعشرات الآلاف شهريًّا فلن يهمّنا حقًّا إن كانت ذاكرة خادومنا 1 غيغابايت أو 8 غيغابايت، عندما ننظر لاحقًا إلى الأشياء التي يمكن فعلها لزيادة السرعة سنتحدث متى يتم تغيير المضيفين والخواديم، سنناقش هذه المشكلة لاحقًا. ومن إحدى الخصائص التي تصنع فرقًا في السرعة هي مكان الخادوم، وهو أمر منطقي إلى حد ما، فإن كان الخادوم في سان فرانسيسكو سنتلقى البيانات منه بشكل أسرع إن كنّا في سان دييغو (على بُعد 500 ميل) ممّا لو كنّا في ملبورن في أستراليا (على بُعد 8000 ميل). تكون البيانات سريعة جدًّا عندما تمر في كابلات الألياف الضوئيّة وتصل تقريبًا لسرعة الضوء، ولكن حالما تقترب من منزلنا تخفف من سرعتها إلى سرعة مزودات خدمة الإنترنت ISP لدينا، تحتاج أيضًا إلى المرور عبر الجدران الناريّة firewalls والموجّهات routers والأجهزة الأخرى التي تبطّئ من سرعتها. تؤثر المسافة على السرعة عندما يكون هنالك طلبات أكثر، نقصد بهذا أنّ تنزيل ملف بحجم 1 غيغابايت من ملبورن سيستغرق تقريبًا نفس المدّة التي سيستغرقها إن تمّ تنزيله من سان دييغو، ولكن تنزيل 1024 ملف وكل ملف منها حجمه 1 ميغابايت سيأخذ وقتًا أطول بكثير إن كانت المسافة بعيدة. لماذا يهمنّا هذا؟ عندما يتم تحميل الموقع قد يقوم بعدد كبير من الطلبات، يتضمّن هذا ملفّات التنسيق، الصور، ملفّات javascript وملفّات أخرى، وبتقليل الطلبات نستطيع زيادة السرعة إلى الحد الأقصى. حاسوب العميليؤثّر الحاسوب القديم الذي نستخدمه بشكل كبير على سرعة الاتصال المتصوّرة، فمثلًا عند تجربة iPad 2 ستكون سرعة الاتصال عليه أبطأ من iMac. توجد العديد من الأسباب لهذا، ولكن السبب الرئيسي هو عمر الحاسوب، فقد أدّى تدهور مكوّنات iPad في المثال السابق إلى استخدامه الذاكرة بشكل أقل فاعليّة، لذلك فهو يعالج المحتوى بشكل أبطأ وأقل استجابة بشكل عام. لم تكن هذه مشكلة كبيرة حتى وقت قريب لأنّ معظم الحوسبة كانت تتم على الخادوم، ولكن مع ظهور أجهزة عملاء أقوى وتقنيّات ويب جديدة أصبحت المواقع تعتمد على قوّة المعالجة من ناحية العميل client side processing. على سبيل المثال يعني هذا تحريكًا أكثر نعومة وسرعة، ولكن يعني أيضًا معاناة الأجهزة البطيئة. بالمحصلة يتم تحديد سرعة أي موقع عن طريق التقنية الرئيسية المستخدمة فيه، نظام إدارة المحتوى، الخادوم والاستضافة، وحاسوب العميل. الخاتمةتحدّثنا في هذا الجزء عن أسباب بطء الموقع، سنكمل في الأجزاء اللاحقة حول طرق زيادة السرعة بالنسبة لغير المطورين وبالنسبة للمطورين. ترجمة -وبتصرّف- لـ THE ULTIMATE MEGA GUIDE TO SPEEDING UP WORDPRESS لصاحبه Daniel Pataki.
  7. هذا الدّرس هو جزء من سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu، تحدّثنا في الأجزاء الأولى عن الخطوات الأساسيّة لنشر تطبيق، وفي بقيّة الأجزاء تكلمنا عن مواضيع أكثر تقدّمًا مثل قواعد البيانات، عفاريت الطابور queue daemons، وجدولة المهام (عبر cron). سنقوم في هذا الدّرس بالبناء على ما تعلمناه في الدروس السابقة عن طريق تحويل playbook في Ansible من دعمها لتطبيق واحد إلى دعمها لنشر تطبيقات PHP متعدّدة على خادوم أو عدّة خواديم. سنستخدم تطبيقات Lumen بسيطة كجزء أمثلتنا، ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك، من المفضّل أن تستخدم تطبيقات الأمثلة حتى تجد نفسك متآلفًا مع القيام بالتغييرات لِـ playbook. الخطوة الأولى – إضافة المزيد من التطبيقاتفي هذه الخطوة سنقوم بإعداد تطبيقين إضافيين في الـ playbook لدينا. الآن وقد أعدنا تصنيع الـ playbook سنستخدم متغيرات لتعريف التطبيقات، إنّ عملية إضافة تطبيقات جديدة لخادومنا هي عملية سهلة جدًّا، نقوم بإضافتها ببساطة إلى قائمة المتغيرات applications، وهنا تظهر قوة متغيرات Ansible. نفتح playbook من أجل تحريرها: nano php.yml نبحث في أعلى القسم vars عن الكتلة applications: Existing applications variable in php.yml applications: - name: laravel domain: laravel.example.com repository: https://github.com/do-community/do-ansible-adv-php.git branch: example نضيف تطبيقين اثنين: Updated applications variable in php.yml applications: - name: laravel domain: laravel.example.com repository: https://github.com/do-community/do-ansible-adv-php.git branch: example - name: one domain: one.example.com repository: https://github.com/do-community/do-ansible-php-example-one.git branch: master - name: two domain: two.example.com repository: https://github.com/do-community/do-ansible-php-example-two.git branch: master نحفظ الـ playbook ونقوم بتشغيلها: ansible-playbook php.yml --ask-sudo-pass قد تستغرق هذه الخطوة بعض الوقت بينما يقوم الـ composer بإعداد التطبيقات الجديدة، وعندما ينتهي سنلاحظ تغيير عدد من المهام، وإن دققنا أكثر سنلاحظ أنّه سيتم عرض كل عنصر ناتج عن الحلقة، يخبرنا الأول وهو تطبيقنا الأصل بعبارة ok أو skipped، بينما يخبرنا التطبيقان الجديدان بالحالة changed. والأهم من ذلك أنّه إذا زرنا النطاقات الثلاثة لمواقعنا التي أعددناها في متصفح الإنترنت فينبغي أن نلاحظ ثلاثة مواقع مختلفة. الأول يبدو مألوفًا لنا، أما الموقعان الآخران سيعرضان: http://one.example.com/ This is example app one! http://two.example.com/ This is example app two! وبذلك قمنا بنشر تطبيقي ويب جديدين عن طريق تحديث قائمة التطبيقات ببساطة. الخطوة الثانية – استخدام متغيرات المضيفين Host Variablesسنستخرج في هذه الخطوة متغيراتنا إلى متغيرات المضيفين. بالرجوع إلى الوراء نجد أنّ متغيرات الـ playbook جيدة، ولكن ماذا لو أردنا نشر تطبيقات مختلفة على خواديم مختلفة باستخدام نفس الـ playbook؟ نستطيع عمل تحقّق شرطي على كل مهمّة لإيجاد الخادوم الذي يقوم بتشغيل المهمة، أو نستطيع استخدام متغيرات المضيفين، وهي تمامًا كما تبدو عليه: متغيرات تُطبَّق على مضيف معيّن بدلًا من كافّة المضيفين عبر الـ playbook. يمكن تعريف متغيرات المضيف سطريًّا inline بداخل الملف hosts كما فعلنا مع المتغير ansible_ssh_user أو يمكن تعريفها في ملف مخصّص لكل مضيف داخل الدليل host_vars. في البداية نقوم بإنشاء دليل جديد إلى جانب الملف hosts والـ playbook، نقوم بتسمية الدليل بـ host_vars: mkdir host_vars نحتاج بعدها إلى إنشاء ملف من أجل المضيف، الاتفاقية التي تستخدمها Ansible هي من أجل أن يتوافق اسم الملف مع اسم المضيف في الملف hosts، لذلك على سبيل المثال إن كان يبدو الملف hosts لدينا كما يلي: Ansible hosts file your_first_server_ip ansible_ssh_user=sammy فينبغي أن نقوم بإنشاء ملف يُدعى host_vars/your_first_server_ip، فلنقم بإنشائه الآن: nano host_vars/your_first_server_ip تستخدم ملفّات المضيفين YAML من أجل تنسيقها تمامًا كما هو الحال مع الـ playbooks، ويعني هذا أنّنا نستطيع نسخ القائمة applications إلى ملف المضيفين الجديد لدينا بحيث يبدو كما يلي: New host_vars/your_first_server_ip file --- applications: - name: laravel domain: laravel.example.com repository: https://github.com/do-community/do-ansible-adv-php.git branch: example - name: one domain: one.example.com repository: https://github.com/do-community/do-ansible-php-example-one.git branch: master - name: two domain: two.example.com repository: https://github.com/do-community/do-ansible-php-example-two.git branch: master نقوم بحفظ ملف المضيفين الجديد ونفتح الـ playbook لتحريرها: nano php.yml نحدّث أعلى الملف لإزالة كامل القسم applications: Updated top of php.yml --- - hosts: php sudo: yes vars: wwwuser: www-data tasks: . . . نحفظ الـ playbook ونقوم بتشغيلها: ansible-playbook php.yml --ask-sudo-pass وعلى الرغم من أنّنا نقلنا متغيراتنا من الـ playbook إلى ملف المضيفين فيجب أن يبقى الخرج نفسه ولا يجب أن يتم تبليغنا عن تغييرات من قبل Ansible، وكما نرى يعمل host_vars بنفس الطريقة التي يعمل بها vars في الـ playbook، ولكنّه مُخصّص للمضيف. ستكون المتغيرات المُعرّفة في ملفّات host_vars قابلة للوصول عبر كامل الـ playbooks التي تدير الخادوم، وهو مفيد من أجل الخيارات والإعدادات الشائعة، ومع ذلك كن حذرًا من استخدام اسم شائع قد يعني أشياء مختلفة عبر الـ playbooks المختلفة. الخطوة الثالثة – نشر التطبيقات على خادوم آخرسنستخدم في هذه الخطوة ملفات المضيفين الجديدة وننشر تطبيقاتنا على خادوم آخر. نحتاج في البداية إلى تحديث ملف المضيفين hosts بمضيفنا الجديد، نفتحه من أجل تحريره: nano hosts ونقوم بإضافة المضيف الجديد: Ansible hosts file your_first_server_ip ansible_ssh_user=sammy your_second_server_ip ansible_ssh_user=sammy نحفظ الملف ونغلقه. نحتاج بعدها إلى إنشاء ملف مضيفين جديد، كما فعلنا مع أول ملف: nano host_vars/your_second_server_ip تستطيع انتقاء واحد أو أكثر من تطبيقات مثالنا وإضافتها إلى ملف المضيف لديك، فإذا أردت مثلًا نشر مثالنا الأصلي والمثال الثاني إلى خادوم جديد فيجب أن تستخدم: New host_vars/your_second_server_ip file --- applications: - name: laravel domain: laravel.example2.com repository: https://github.com/do-community/do-ansible-adv-php.git branch: example - name: two domain: two.example2.com repository: https://github.com/do-community/do-ansible-php-example-two.git branch: master نقوم بحفظ playbook. وأخيرًا نقوم بتشغيلها: ansible-playbook php.yml --ask-sudo-pass ستستغرق Ansible وقتًا ليتم تشغيلها لأنّها تقوم بإعداد كل شيء على خادومنا الثاني، وعندما تنتهي نفتح تطبيقاتنا التي اخترناها في المتصفح (استخدمنا في هذا المثال laravel.example2.com وtwo.example2.com) وللتأكد من أنّه تم إعدادها بشكل صحيح يجب أن نرى التطبيقات المحدّدة التي اخترناها من أجل ملف المضيفين، وينبغي ألّا تحدث أيّة تغييرات على خادومنا الأصلي. الخاتمةأخذنا في هذا الدرس playbook تطبيق وحيد تعمل بشكل كامل وقمنا بتحويلها لتدعم تطبيقات متعددة عبر عدّة خواديم، وبجمعها مع المواضيع التي تمت تغطيتها في الدروس السابقة يجب أن تمتلك كل ما تحتاجه لكتابة playbook كاملة لنشر تطبيقاتك، وكما هو الحال مع الدروس السابقة فلا زلنا لم نسجل الدخول بشكل مباشر باستخدام SSH. ومن المؤكد أنك لاحظت مدى بساطة إضافة المزيد من التطبيقات والمزيد من الخواديم بعد الانتهاء من تجهيز بنية الـ playbook، وهنا تكمن قوة Ansible وهو ما يجعلها مرنة جدًّا وسهلة الاستخدام. ترجمة -وبتصرّف- لـ How To Deploy Multiple PHP Applications using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  8. هذا الدّرس هو جزء من سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu، تحدّثنا في الأجزاء الأولى عن الخطوات الأساسيّة لنشر تطبيق، وفي بقيّة الأجزاء تكلمنا عن مواضيع أكثر تقدّمًا مثل قواعد البيانات، عفاريت الطابور queue daemons، وجدولة المهام (عبر cron). سنقوم في هذا الدّرس بالبناء على ما تعلمناه في الدروس السابقة عن طريق تحويل الـ playbook في Ansible من دعمها لتطبيق واحد إلى دعمها لنشر تطبيقات PHP متعدّدة على خادوم أو عدّة خواديم، سنتحدث في هذا الجزء عن إعداد المتغيرات، وسنكمل في الجزء اللاحق عن إضافة المزيد من التطبيقات ونشرها. سنستخدم تطبيقات Lumen بسيطة كجزء أمثلتنا، ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك، من المفضّل أن تستخدم تطبيقات الأمثلة حتى تجد نفسك متآلفًا مع القيام بالتغييرات للـ playbook. المتطلبات الأساسيةتحتاج من أجل متابعة الدّرس إلى: الخادومين الاثنين اللذين قمنا بإعدادهما في الأجزاء السابقة.خادوم Ubuntu جديد (ثالث) يتم إعداده مثل خادوم PHP الأصلي الموجود في الأجزاء السابقة، مع مستخدم sudo غير جذري ومفاتيح SSH، حيث سنستخدمه لإظهار كيفيّة نشر تطبيقات متعدّدة إلى خواديم متعدّدة باستخدام Ansible Playbook واحدة، سنشير لعناوين IP لخادوم PHP الأصلي وخادوم PHP الجديد بـ your_first_server_ip و your_second_server_ip على الترتيب.ملف etc/hosts/ مُحدَّث على حاسوبك المحلّي مع إضافة الأسطر التالية له، تستطيع تعلّم المزيد حول هذا الملف في الخطوة السادسة من هذا الدّرس.your_first_server_ip laravel.example.com one.example.com two.example.com your_second_server_ip laravel.example2.com two.example2.comأمثلة المواقع التي سنستخدمها في هذا الدّرس هي laravel.example.com، one.example.com، و two.example.com، إن أردت استخدام نطاقك الخاص ستحتاج لتحديث تسجيلات DNS النشطة لديك بدلًا من ذلك. الخطوة الأولى – إعداد متغيرات الـ Playbookسنقوم في هذه الخطوة بإعداد متغيّرات الـ playbook لتعريف تطبيقنا الجديد. في الدروس السابقة قمنا بكتابة خصائص الإعدادات بشكل حرفي وهو أمر طبيعي بالنسبة للعديد من الـ playbooks التي تقوم بتنفيذ مهام محدّدة من أجل تطبيق محدّد، أمّا عندما نريد دعم عدّة تطبيقات أو توسيع مدى الـ playbook الخاصّة بنا فلن يعود هنالك معنى من كتابة كل شيء حرفيًّا. وكما شاهدنا سابقًا تزوّدنا Ansible بمتغيرات نستطيع استخدامها في تعريفات المهام وقوالب الملفّات، ما لم نشاهده حتى الآن هو كيفيّة تعيين المتغيرات، في أعلى الـ playbook بجانب مُعامِلات hosts وtasks نستطيع تعريف مُعامِل vars وتعيين متغيراتنا هناك. نقوم بالانتقال إلى الدليل ansible-php الذي تحدثنا عنه في الدّروس السابقة: cd ~/ansible-php/ نفتح الـ playbook الحاليّة من أجل تحريرها: nano php.yml ينبغي أن تبدو بداية الملف كما يلي: Top of original php.yml --- - hosts: php sudo: yes tasks: . . . نستطيع من أجل تعريف المتغيرات إضافة القسم vars فقط، بجانب hosts، sudo، وtasks، ولإبقاء الموضوع بسيط سنبدأ مع متغيّر بسيط جدًّا من أجل المستخدم www-data كما يلي: Updated vars in php.yml --- - hosts: php sudo: yes vars: wwwuser: www-data tasks: . . . نقوم بعدها بتحديث كافّة المرّات التي ورد فيها المستخدم www-data ونضع بدلًا منها المتغيّر {{ wwwuser }}. نضغط على CTRL+\ من أجل البحث والاستبدال باستخدام nano، سنشاهد مُحث prompt يقول: Search (to replace):. نكتب www-data ونضغط ENTER، سيتغيّر المُحِث إلى: Replace with:نكتب هنا {{ wwwuser }} ونضغط ENTER مرّة أخرى، سيأخذنا nano عبر كل مثال من www-data ويسألنا: Replace this instanace?نستطيع أن نضغط y لاستبدال كل واحدة منها، أو نضغط a لاستبدالها كلّها. ملاحظة: تأكّد من عدم تغيير تعريف المتغير الذي أضفناه للتو في أعلى الملف، يجب أن يكون هنالك 11 مثال من www-data نحتاج إلى استبدالها. وقبل أن نكمل هنالك شيء نحتاج للانتباه له فيما يتعلّق بالمتغيرات، بإمكاننا بشكل طبيعي إضافتها كما يلي عندما تكون في سطر أطول: Example task in php.yml - name: create /var/www/ directory file: dest=/var/www/ state=directory owner={{ wwwuser }} group={{ wwwuser }} mode=0700 ومع ذلك إن كان المتغيّر هو القيمة الوحيدة في السلسلة نحتاج إلى وضعه ضمن علامتي اقتباس كي يستطيع مُحلِّل YAML فهمه بشكل صحيح: Updated task in php.yml - name: Run artisan migrate shell: php /var/www/laravel/artisan migrate --force sudo: yes sudo_user: "{{ wwwuser }}" when: dbpwd.changed يجب أن يحدث هذا في الـ playbook في كل مرّة نحصل فيها على: sudo_user: {{ wwwuser }}نستطيع استخدام بحث واستبدال عام بنفس الطريقة ووضع: sudo_user: "{{ wwwuser }}" بدلًا من: sudo_user: {{ wwwuser }}ينبغي وجود أربعة أسطر تحتاج إلى هذا التغيير. وبعد أن ننتهي من تغييرها نقوم بحفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass ينبغي ألّا توجد مهام متغيّرة، وهو يعني أنّ المتغيّر wwwuser يعمل بشكل صحيح. الخطوة الثانية – تعريف المتغيرات المتداخلة من أجل الإعدادات المعقدةسننظر في هذا القسم إلى المتغيّرات المتداخلة من أجل خيارات الإعدادات المعقدة. قمنا في الخطوة السابقة بإعداد متغيّر بسيط، ولكن يمكن أيضًا أن نُداخِل بين المتغيّرات وأن نُعرِّف قائمة من المتغيّرات، يزودنا هذا بالوظيفة التي نحتاجها لتعريف قائمة من المواقع التي نرغب بإعدادها على خادومنا. دعونا في البداية ننظر إلى مستودع git الحالي الذي قمنا بإعداده في الـ playbook: Existing git task in php.yml - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/do-community/do-ansible-adv-php.git update=yes version=example نستطيع استخراج المعلومات المفيدة التالية: الاسم name (دليل)، المستودع repository، الفرع branch، والنطاق domain، وبما أنّنا نقوم بإعداد تطبيقات متعدّدة سنحتاج أيضًا إلى اسم نطاق من أجله للإجابة عليه، سنستخدم laravel.example.com ولكن إن كنت تملك نطاقك الخاص فضعه هنا. ينتج عن هذا المتغيرات الأربعة التالية التي نستطيع تعريفها من أجل هذا التطبيق: Application variables name: laravel repository: https://github.com/do-community/do-ansible-adv-php.git branch: example domain: laravel.example.com نفتح الآن الـ playbook من أجل تحريرها: nano php.yml نستطيع في القسم العلوي vars إضافة تطبيقنا إلى قائمة التطبيقات الجديدة: Updated applications variables in php.yml --- - hosts: php sudo: yes vars: wwwuser: www-data applications: - name: laravel domain: laravel.example.com repository: https://github.com/do-community/do-ansible-adv-php.git branch: example ... إن قمنا الآن بتشغيل الـ playbook (باستخدام ansible-playbook php.yml --ask-sudo-pass) فلن يتغير شيء لأنّنا لم نقم بعد بإعداد مهامنا لكي تستخدم المتغير applications الجديد، إن ذهبنا إلى http://laravel.example.com/ في متصفحنا فينبغي أن يظهر تطبيقنا الأصلي. الخطوة الثالثة – المرور على المتغيرات عن طريقة حلقة loop في المهامسنتعلم في هذا القسم كيفيّة المرور على قوائم المتغيرات عبر حلقة loop في المهام. كما أشرنا سابقًا تحتاج قوائم المتغيرات المرور عليها عبر حلقة في كل مهمة نرغب في استخدامها فيها، وكما شاهدنا مع المهمّة install packages نحتاج إلى تعريف حلقة من العناصر ومن ثمّ تطبيق المهمّة لكل عنصر في القائمة. نفتح الـ playbook من أجل تحريرها: nano php.yml سنبدأ ببعض المهام السهلة، ينبغي أن نجد مهمتي env في منتصف الـ playbook تقريبًا: Existing env tasks in php.yml - name: set APP_DEBUG=false lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false - name: set APP_ENV=production lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production نلاحظ أنّها مكتوبة الآن بشكل حرفي مع الدليل laravel، نحتاج إلى تحديثها لكي تستخدم الخاصية name لكل تطبيق، ولفعل هذا نضيف الخيار with_items كي يمر على شكل حلقة خلال قائمة applications لدينا، وضمن المهمّة نفسها سنبدل المرجع laravel بالمتغير {{ item.name }}. ينبغي أن تبدو كما يلي: Updated .env tasks in php.yml - name: set APP_DEBUG=false lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false with_items: applications - name: set APP_ENV=production lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^APP_ENV=' line=APP_ENV=production with_items: applications ننتقل بعدها إلى الأسفل إلى مهمتي Laravel cron، يمكن تحديثهما كما فعلنا تمامًا مع مهام env، سنقوم بإضافة item.name إلى المُعامِل name من أجل مُدخلات لأنّ Ansible تستخدم هذا الحقل لتعرّف بشكل فريد كل مُدخل cron، إن تركناها كما هي فلن نكون قادرين على الحصول على مواقع متعددة على نفس الخادوم لأنّها ستكتب فوق بعضها بشكل ثابت وسيتم حفظ القيمة الأخيرة فقط. ينبغي أن تبدو المهمة كما يلي: Updated cron tasks in php.yml - name: Laravel Scheduler cron: > job="run-one php /var/www/{{ item.name }}/artisan schedule:run 1>> /dev/null 2>&1" state=present user={{ wwwuser }} name="{{ item.name }} php artisan schedule:run" with_items: applications - name: Laravel Queue Worker cron: > job="run-one php /var/www/{{ item.name }}/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1>> /dev/null 2>&1" state=present user={{ wwwuser }} name="{{ item.name }} Laravel Queue Worker" with_items: applications إن قمنا بحفظ وتشغيل الـ playbook الآن (باستخدام ansible-playbook php.yml --ask-sudo-pass) فيجب أن نرى أنّه فقط تم تحديث مهمّتي cron، وهذا بسبب التغيير في المُعامِل name، ولا توجد أيّة تغييرات عدا عن ذلك، وهذا يعني أنّ قائمة تطبيقاتنا تعمل كما هو متوقع، ولم نقم بأيّة تغييرات إلى خادومنا كنتيجة لإعادة تصنيع الـ playbook لدينا. الخطوة الرابعة – تطبيق المتغيرات من الحلقة looped variables في قوالب templatesسنغطي في هذا القسم كيفيّة استخدام المتغيرات من الحلقة في القوالب. نستطيع استخدام هذه المتغيرات بنفس الطريقة تمامًا التي استخدمناها في المهام، كما هو الحال مع جميع المتغيرات الأخرى، تأتي الصعوبة عندما نأخذ بعين الاعتبار مسارات الملفات بالإضافة للمتغيرات، لأنّنا سنحتاج في بعض الأحيان إلى أخذ اسم الملف بعين الاعتبار وحتى تنفيذ أوامر أخرى بسبب الملف الجديد. نحتاج في حالة Nginx إلى إنشاء ملف إعدادات جديد لكل تطبيق وإخبار Nginx أنّه ينبغي تمكينها، نريد أيضًا إزالة ملف إعداداتنا الافتراضي: etc/nginx/sites-available/default/ خلال العمليّة. نفتح في البداية الـ playbook من أجل تحريرها: nano php.yml نقوم بإيجاد المهمة Configure Nginx (قرب منتصف الـ playbook) وتحديثها كما فعلنا مع المهام الأخرى: Updated nginx task in php.yml - name: Configure nginx template: src=nginx.conf dest=/etc/nginx/sites-available/{{ item.name }} with_items: applications notify: - restart php5-fpm - restart nginx وبينما نحن هنا نقوم بإضافة المهمتين الإضافيتين اللتين أشرنا لهما سابقًا، نخبر Nginx في البداية حول ملف إعدادات الموقع الجديد، يتم فعل هذا باستخدام بارتباط رمزي بين أدلة sites-available و sites-enabled في /var/nginx/. نضيف هذه المهمة بعد المهمة Configure nginx: New symlink task in php.yml - name: Configure nginx symlink file: src=/etc/nginx/sites-available/{{ item.name }} dest=/etc/nginx/sites-enabled/{{ item.name }} state=link with_items: applications notify: - restart php5-fpm - restart nginx نرغب بعدها في إزالة ملف إعدادات الموقع المُمكّن افتراضيًّا default كي لا يسبب مشاكل مع ملفّات إعدادات موقعنا الجديد، يتم عمل هذا بسهولة باستخدام الوحدة file: New file task php.yml - name: Remove default nginx site file: path=/etc/nginx/sites-enabled/default state=absent notify: - restart php5-fpm - restart nginx لاحظ أنّنا لم نحتاج إلى وضع applications في حلقة لأنّنا كنّا نبحث عن ملف واحد. يجب أن تبدو كتلة Nginx في الـ playbook كما يلي الآن: Updated nginx tasks in php.yml - name: Configure nginx template: src=nginx.conf dest=/etc/nginx/sites-available/{{ item.name }} with_items: applications notify: - restart php5-fpm - restart nginx - name: Configure nginx symlink file: src=/etc/nginx/sites-available/{{ item.name }} dest=/etc/nginx/sites-enabled/{{ item.name }} state=link with_items: applications notify: - restart php5-fpm - restart nginx - name: Remove default nginx site file: path=/etc/nginx/sites-enabled/default state=absent notify: - restart php5-fpm - restart nginx نحفظ الـ playbook ونفتح الملف nginx.conf من أجل تحريره: nano nginx.conf نقوم بتحديث ملف الإعدادات بحيث يستخدم متغيراتنا: Updated nginx.conf server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /var/www/{{ item.name }}/public; index index.php index.html index.htm; server_name {{ item.domain }}; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/{{ item.name }}/public; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } مع ذلك لم نقم بالانتهاء بعد، أتلاحظ default_server في الأعلى؟ نريد تضمينها فقط من أجل تطبيق laravel لجعله التطبيق الافتراضي، لعمل هذا نستطيع استخدام جملة IF بسيطة لنتحقّق إذا ما كان item.name يساوي laravel وإن كان كذلك نعرض default_server. ستبدو كما يلي: Updated nginx.conf with conditionals server { listen 80{% if item.name == "laravel" %} default_server{% endif %}; listen [::]:80{% if item.name == "laravel" %} default_server ipv6only=on{% endif %}; نحدّث nginx.conf وفقًا لذلك ونحفظه. حان الوقت الآن لتشغيل الـ playbook لدينا: ansible-playbook php.yml --ask-sudo-pass يجب أن تلاحظ أنّه تم تعليم مهام Nginx بأنّها تغيرت، عند الانتهاء من تشغيل الـ playbook نحدّث الموقع في متصفحنا ويجب أن يعرض ما يلي: http://laravel.example.com/ Queue: YES Cron: YES الخطوة الخامسة – وضع متغيرات متعددة في حلقة معاسنقوم في هذه الخطوة بوضع متغيّرات متعدّدة معًا في مهمّة. حان الوقت الآن لمعالجة مثال حلقات أكثر تعقيدًا، خصوصًا المتغيّرات المُسجّلَة، من أجل دعم حالات مختلفة ومنع تشغيل مهام غير ضرورية، تتذكر أنّنا استخدمنا register: cloned في مهمّة استنساخ مستودع git لتسجيل المتغير cloned مع حالة المهمّة، نستخدم بعدها when: cloned|changed في المهام التالية لتحفيز المهام بشكل شرطي، نحتاج الآن إلى تحديث هذه المراجع لتدعم حلقة التطبيقات. نفتح أوّلًا الـ playbook من أجل تحريرها: nano php.yml نبحث عن المهمّة Clone git repository: Existing git task in php.yml - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/do-community/do-ansible-adv-php.git update=yes version=example sudo: yes sudo_user: "{{ wwwuser }}" register: cloned وبما أنّنا نقوم بتسجيل المتغيرات في هذه المهمة فلن نحتاج إلى فعل أي شيء لم نفعله سابقًا: Updated git task in php.yml - name: Clone git repository git: > dest=/var/www/{{ item.name }} repo={{ item.repository }} update=yes version={{ item.branch }} sudo: yes sudo_user: "{{ wwwuser }}" with_items: applications register: cloned نبحث الآن عن المهمة composer create-project: Original composer task in php.yml - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: "{{ wwwuser }}" when: cloned|changed نحتاج الآن إلى تحديثها للمرور عبر حلقة على applications و cloned، يتم فعل هذا باستخدام الخيار with_together وتمرير applications وcloned إليها، وبينما تقوم with_together بالمرور عبر حلقة على المتغيرين فيتم الصول إلى العناصر باستخدام item.#، حيث أنّ # هي فهرس المتغير، فعلى سبيل المثال: with_together: - list_one - list_two يشير item.0 إلى list_one ويشير item.1 إلى list_two. يعني هذا أنّنا نستطيع من أجل applications نستطيع الوصول إلى الخصائص عبر: item.0.name، نحتاج من أجل cloned إلى تمرير النتائج من المهام والتي يمكن الوصول إليها عبر cloned.results ومن ثمّ نستطيع التحقّق إن تم تغييرها من خلال item.1.changed. يعني هذا أنّ المهمة ستصبح: Updated composer task in php.yml - name: composer create-project composer: command=create-project working_dir=/var/www/{{ item.0.name }} optimize_autoloader=no sudo: yes sudo_user: "{{ wwwuser }}" when: item.1.changed with_together: - applications - cloned.results نقوم الآن بحفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass ينبغي ألّا تحدث أيّة تغييرات من هذا التشغيل، ومع ذلك نمتلك الآن متغيرًا مُسجّلًا يعمل بشكل رائع مع حلقة. الخطوة السادسة – المتغيرات المسجلة المعقدة والحلقاتسنتعلم في هذا القسم حول المزيد من المتغيرات المسجلة المعقدة والحلقات. الجزء الأكثر تعقيدًا من التحويل هو مُداولة handling المتغير المسجّل الذي نستخدمه من أجل توليد كلمة السر لقاعدة بيانات MySQL، ولا يوجد أكثر مما فعلناه في هذه الخطوة لم نقم بتغطيته، نحتاج فقط إلى تحديث عدد من المهام في وقت واحد. نفتح الـ playbook من أجل تحريرها: nano php.yml نبحث عن مهام MySQL ونقوم بإضافة المتغيرات البسيطة كما فعلنا في المهمة السابقة: Updated MySQL tasks in php.yml - name: Create MySQL DB mysql_db: name={{ item.name }} state=present with_items: applications - name: Generate DB password shell: makepasswd --chars=32 args: creates: /var/www/{{ item.name }}/.dbpw with_items: applications register: dbpwd - name: Create MySQL User mysql_user: name={{ item.name }} password={{ dbpwd.stdout }} priv={{ item.name }}.*:ALL state=present when: dbpwd.changed - name: set DB_DATABASE lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_DATABASE=' line=DB_DATABASE={{ item.name }} with_items: applications - name: set DB_USERNAME lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_USERNAME=' line=DB_USERNAME={{ item.name }} with_items: applications - name: set DB_PASSWORD lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ dbpwd.stdout }} when: dbpwd.changed - name: Save dbpw file lineinfile: dest=/var/www/{{ item.name }}/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present sudo: yes sudo_user: "{{ wwwuser }}" when: dbpwd.changed - name: Run artisan migrate shell: php /var/www/{{ item.name }}/artisan migrate --force sudo: yes sudo_user: "{{ wwwuser }}" when: dbpwd.changed نضيف بعدها with_together كي نستطيع استخدام كلمة سر قاعدة بياناتنا، ومن أجل توليد كلمة السر نحتاج إلى المرور بحلقة خلال dbpwd.results وسنكون قادرين على الوصول لكلمة السر من item.1.stdout بما أنّه سيتم الوصول لـ applications عبر item.0. نستطيع تحديث الـ playbook وفق ذلك: Updated MySQL tasks in php.yml - name: Create MySQL DB mysql_db: name={{ item.name }} state=present with_items: applications - name: Generate DB password shell: makepasswd --chars=32 args: creates: /var/www/{{ item.name }}/.dbpw with_items: applications register: dbpwd - name: Create MySQL User mysql_user: name={{ item.0.name }} password={{ item.1.stdout }} priv={{ item.0.name }}.*:ALL state=present when: item.1.changed with_together: - applications - dbpwd.results - name: set DB_DATABASE lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_DATABASE=' line=DB_DATABASE={{ item.name }} with_items: applications - name: set DB_USERNAME lineinfile: dest=/var/www/{{ item.name }}/.env regexp='^DB_USERNAME=' line=DB_USERNAME={{ item.name }} with_items: applications - name: set DB_PASSWORD lineinfile: dest=/var/www/{{ item.0.name }}/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ item.1.stdout }} when: item.1.changed with_together: - applications - dbpwd.results - name: Save dbpw file lineinfile: dest=/var/www/{{ item.0.name }}/.dbpw line="{{ item.1.stdout }}" create=yes state=present sudo: yes sudo_user: "{{ wwwuser }}" when: item.1.changed with_together: - applications - dbpwd.results - name: Run artisan migrate shell: php /var/www/{{ item.0.name }}/artisan migrate --force sudo: yes sudo_user: "{{ wwwuser }}" when: item.1.changed with_together: - applications - dbpwd.results بعد أن يتم تحديثها نقوم بحفظها وتشغيلها: ansible-playbook php.yml --ask-sudo-pass بالرغم من جميع التغييرات التي قمنا بها على الـ playbook فلا يجب أن يكون هنالك تغييرات في مهام قاعدة البيانات، ومع التغييرات في هذه الخطوة نكون قد انتهينا من التحويل من playbook تدعم تطبيق وحيد إلى playbook تدعم تطبيقات متعددة. الخاتمةتحدثنا في هذا الجزء عن إعداد المتغيرات، وسنكمل في الجزء اللاحق عن إضافة المزيد من التطبيقات ونشرها إلى خادوم آخر. ترجمة -وبتصرّف- لـ How To Deploy Multiple PHP Applications using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  9. هذا الدّرس هو جزء من سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu، تحدّثنا في أول أجزاء عن الخطوات الأساسيّة من أجل نشر تطبيق، وهي تشكل نقطة بداية من أجل الخطوات المذكورة في هذا الدّرس. سنغطّي في هذا الدّرس إعداد جدولة المهام (crons) وعفاريت الطابور queue daemons، هدفنا في النهاية هو الحصول على خادوم يعمل عليه تطبيق PHP بشكل كامل مع الإعدادات المذكورة آنفًا. سنستخدم إطار عمل Laravel كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك. الخطوة الأولى – إعداد مهام cronسنقوم في هذه الخطوة بإعداد أي مهمّة cron نحتاج لإعدادها. إنّ مهام cron هي عبارة عن أوامر تعمل وفق جدول schedule مُحدَّد ويمكن استخدامها لإنجاز أي عدد من المهام من أجل تطبيقنا، كالقيام بمهام الصيانة أو إرسال تحديثات نشاط البريد الإلكتروني – بشكل أساسي أي شيء نحتاج عمله بشكل دوري بدون تدخل المستخدم يدويًّا، يمكن تشغيل مهام cron بتواتر كل دقيقة أو بشكل غير منتظم كما نريد. يأتي Laravel بشكل افتراضي مع أمر حرفي يُدعى schedule:run، وهو مُصمَّم ليعمل كل دقيقة وينفذ المهام المجدولة المُعرَّفة ضمن التطبيق، يعني هذا أنّنا نحتاج فقط لإضافة مهمّة cron واحدة إن كان تطبيقنا يستفيد من هذه الميّزة. تمتلك Ansible وحدة cron مع العديد من الخيارات المختلفة والتي تُترجَم مباشرة إلى خيارات مختلفة نستطيع إعدادها عبر cron: job: الأمر الذي نريد تنفيذه، مطلوب إن كانت state=present.minute، hour، day، weekday: الدقيقة، الساعة، اليوم، الشهر، أو اليوم من أيام الأسبوع الذي يجب فيه تشغيل الوظيفة، على الترتيب.special_time أوقات خاصّة (reboot، yearly، annually، monthly، weekly، daily، hourly): وقت خاص مُحدَّد بكنية nickname.سيقوم افتراضيًّا بإنشاء مهمّة تعمل كل دقيقة، وهو ما نريده، وهذا يعني أنّ المهمّة التي نريدها تبدو كما يلي: New Ansible task - name: Laravel Scheduler cron: > job="run-one php /var/www/laravel/artisan schedule:run 1>> /dev/null 2>&1" state=present user=www-data name="php artisan schedule:run" إنّ الأمر run-one هو مساعد صغير في Ubuntu يضمن أن يعمل الأمر فقط مرّة واحدة، وهذا يعني أنّه إن كان أمر schedule:run سابق لا يزال قيد التشغيل فلن يتم تشغيله مرّة أخرى، وهذا مفيد لتجنّب حالة تصبح فيها مهمّة cron مقفولة ضمن حلقة، ومع الوقت سيتم تشغيل المزيد من النُسَخ لنفس المهمّة حتى تنفذ موارد الخادوم. نفتح الملف php.yml لتحريره: nano php.yml نضيف المهمّة السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي: Updated php.yml . . . - name: Run artisan migrate shell: php /var/www/laravel/artisan migrate --force sudo: yes sudo_user: www-data when: dbpwd.changed - name: Laravel Scheduler cron: > job="run-one php /var/www/laravel/artisan schedule:run 1>> /dev/null 2>&1" state=present user=www-data name="php artisan schedule:run" handlers: . . . نقوم بحفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass نحدّث الآن الصفحة في متصفحنا، وخلال دقيقة سيتم التحديث وستبدو كما يلي: your_server_ip/'>http://your_server_ip/ Queue: NO Cron: YES يعني هذا أنّ cron تعمل في الخلفية بشكل صحيح، وكجزء من تطبيق المثال هنالك وظيفة cron تعمل كل دقيقة وتقوم بتحديث مُدخَل الحالة في قاعدة البيانات كي يعلم التطبيق أنّها تعمل. الخطوة الثانية – إعداد عفريت الطابور Queue Daemonوكما في حالة الأمر الحرفي schedule:run من الخطوة السابقة، يأتي Laravel مع عامل للطابور يُمكِن تشغيله بالأمر الحرفي queue:work --daemon، سنقوم في هذه الخطوة بإعداد عامل عفريت (بالإنجليزية Daemon وهو برنامج يعمل في خلفيّة النظام) الطابور queue daemon worker من أجل Laravel. يتشابه عمّال الطابور مع وظائف cron في أنّها تقوم بتشغيل المهام في الخلفيّة، ويكمن الفرق في دفع التطبيق للوظائف إلى الطابور، إمّا عبر إجراءات يتم تنفيذها من قبل المستخدم أو من خلال مهام مُجدوَلة عبر وظائف cron، يتم تنفيذ مهام الطابور من قِبَل العامل في وقت واحد، ويتم معالجتها بحسب الطلب عندما يتم العثور عليها في الطابور، تُستخدَم مهام الطابور بشكل شائع من أجل العمل الذي يستغرق وقتًا لتنفيذه، كإرسال رسائل البريد الإلكتروني أو القيام باستدعاءات لواجهة API للخدمات الخارجيّة. وعلى عكس الأمر schedule:run فإنّ هذا الأمر لا يحتاج أن يتم تشغيله كل دقيقة، بل يحتاج بدلًا من ذلك أن يعمل كعفريت daemon في الخلفيّة بشكل ثابت، ومن الطرق الشائعة لفعل هذا هي استخدام حزمة طرف ثالث third-party تُدعى supervisord، ولكن تتطلّب هذه الطريقة فهم كيفيّة إعداد وإدارة النظام المذكور، وهنالك طريقة أسهل لتنفيذها باستخدام cron والأمر run-one. سنقوم بإنشاء مُدخَل cron لبدء عفريت عامل الطابور ونستخدم الأمر run-one لتشغيله، ويعني هذا أن يقوم cron بتشغيل العمليّة في أوّل مرة تعمل فيها، وسيتم تجاهل أي تشغيلات cron لاحقة للأمر عن طريق run-one أثناء تشغيل العامل، وحالما يتوقّف العامل سيسمح run-one للأمر بأن يعمل مرّة أخرى، وسيبدأ عامل الطابور عمله مرّة أخرى، وهي طريقة بسيطة وسهلة الاستخدام بشكل لا يصدّق توفّر علينا الحاجة لتعلّم كيفيّة إعداد واستخدام أداة أخرى. وبأخذ كل ذلك بعين الاعتبار سنقوم بإنشاء مهمّة cron أخرى لتشغيل عامل الطابور لدينا: New Ansible task - name: Laravel Queue Worker cron: > job="run-one php /var/www/laravel/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1>> /dev/null 2>&1" state=present user=www-data name="Laravel Queue Worker" نفتح الملف php.yml من أجل تحريره: nano php.yml نضيف المهمّة السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي: Updated php.yml . . . - name: Laravel Scheduler cron: > job="run-one php /var/www/laravel/artisan schedule:run 1>> /dev/null 2>&1" state=present user=www-data name="php artisan schedule:run" - name: Laravel Queue Worker cron: > job="run-one php /var/www/laravel/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1>> /dev/null 2>&1" state=present user=www-data name="Laravel Queue Worker" handlers: . . . نقوم بحفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass نحدّث الصفحة في متصفحنا، وسيتم بعد دقيقة تحديثها لتبدو كما يلي: your_server_ip/'>http://your_server_ip/ Queue: YES Cron: YES يعني هذا أنّ عامل الطابور يعمل في الخلفيّة بشكل صحيح، تقوم وظيفة cron التي بدأنا بها في الخطوة السابقة بدفع الوظيفة إلى الطابور، تحدّث هذه الوظيفة قاعدة البيانات عند تشغيلها لتظهر بأنّها تعمل. نمتلك الآن مثال يعمل لتطبيق Laravel يتضمّن وظائف cron وعمّال طوابير. الخاتمةلقد قمنا في هذا الدّرس بتغطية بعض أكثر المواضيع تقدمًا عند استخدام Ansible من أجل نشر تطبيقات PHP، يمكن تعديل كافّة المهام المستخدمة بسهولة لتتلاءم مع معظم تطبيقات PHP (بحسب متطلباتها الخاصّة)، ويجب أن تشكّل لك نقطة انطلاق جيّدة لإعداد playbook الخاصّة بك من أجل تطبيقاتك. لم نستخدم أي أمر SSH كجزء من هذا الدّرس (باستثناء التحقّق من تسجيل دخول المستخدم www-data)، وتم إعداد كل شيء تلقائيًّا بما في ذلك كلمة سر مستخدم MySQL، بعد متابعتك لهذا الدّرس أصبح تطبيقك جاهزًا للانطلاق ودعم أدوات لدفع تحديثات الشيفرة. ترجمة -وبتصرّف- لـ How To Deploy an Advanced PHP Application Using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  10. هذا الدّرس هو جزء من سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu، تحدّثنا في أول أجزاء عن الخطوات الأساسيّة من أجل نشر تطبيق، وهي تشكل نقطة بداية من أجل الخطوات المذكورة في هذا الدّرس. سنغطّي في هذا الدّرس إعداد قاعدة البيانات (بما في ذلك كلمة السّر)، هدفنا في النهاية هو الحصول على خادوم يعمل عليه تطبيق PHP بشكل كامل مع الإعدادات المذكورة آنفًا. سنستخدم إطار عمل Laravel كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك. الخطوة الأولى – تثبيت حزم MySQLسنقوم في هذه الخطوة بإعداد قاعدة بيانات MySQL لكي يستخدمها تطبيقنا. إنّ الخطوة الأولى لضمان وجود MySQL مُثبّتة على خادومنا هي ببساطة إضافة الحِزَم المطلوبة إلى مهمّة تثبيت الحِزَم في أعلى الـ playbook لدينا، الحزم التي نحتاجها هي mysql-server، mysql-client، وphp5-mysql، سنحتاج أيضًا إلى python-mysqldb كي تستطيع Ansible التواصل مع MySQL. وبما أنّنا نضيف حِزَم فنحتاج إلى إعادة تشغيل nginx و php5-fpm لضمان قابلية استخدام الحِزَم الجديدة من قبل التطبيق، نحتاج في هذه الحالة أن تكون MySQL متوفرة من أجل PHP لكي تستطيع الاتصال إلى قاعدة البيانات. من الأشياء الرائعة حول Ansible هي أنّنا نستطيع تعديل أي مهمّة من المهام وإعادة تشغيل الـ playbook وسيتم حينها تطبيق التغييرات، يتضمّن هذا قوائم من الخيارات كما نملك مع مهمّة apt. نفتح الملف php.yml من أجل تحريره: nano php.yml نبحث عن المهمّة install packages ونحدّثها لتضم الحِزَم السابقة: Updated php.yml . . . - name: install packages apt: name={{ item }} update_cache=yes state=latest with_items: - git - mcrypt - nginx - php5-cli - php5-curl - php5-fpm - php5-intl - php5-json - php5-mcrypt - php5-sqlite - sqlite3 - mysql-server - mysql-client - php5-mysql - python-mysqldb notify: - restart php5-fpm - restart nginx . . . نقوم بحفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass الخطوة الثانية – إعداد قاعدة بيانات MySQLسنقوم في هذه الخطوة بإنشاء قاعدة بيانات MySQL من أجل تطبيقنا. تستطيع Ansible التخاطب مباشرة مع MySQL باستخدام الوحدات المسبوقة بـ mysql_ (مثل mysql_db، mysql_user)، تزودنا الوحدة mysql_db بطريقة لضمان وجود قاعدة بيانات ذات اسم مُحدّد بحيث نستطيع استخدام مهمّة مثل هذه لإنشاء قاعدة البيانات: New Ansible task - name: Create MySQL DB mysql_db: name=laravel state=present نحتاج أيضًا إلى حساب مستخدم صحيح مع كلمة سر معروفة للسماح لتطبيقنا بالاتصال إلى قاعدة البيانات، إحدى الوسائل لتحقيق هذا هي توليد كلمة السر محليًّا وحفظها في playbook الخاصّة بـ Ansible، ولكنّ هذه الطريقة غير آمنة وتوجد وسيلة أفضل منها. سنقوم بتوليد كلمة السّر باستخدام Ansible على الخادوم ذاته واستخدامها مباشرة عند الحاجة، ولتوليد كلمة سر سنستخدم أداة الأوامر السطرية makepasswd ونطلب منها كلمة سر مكوّنة من 32 حرف، ولأنّ makepasswd لا تأتي بشكل افتراضي مع Ubuntu سنحتاج إلى إضافتها إلى قائمة الحِزَم أيضًا. سنخبر أيضًا Ansible أن تتذكر خَرْج output هذا الأمر (أي تتذكر كلمة السّر) حتى نستطيع استخدامها لاحقًا في الـ playbook الخاصّة بنا، ومع ذلك ولأنّ Ansible لا تعلم إذا ما كان قد تم تنفيذ الأمر shell فسنقوم بإنشاء ملف عند تنفيذ هذا الأمر، ستتحقّق Ansible من وجود الملف وإن وجدته فستفترض أنّه تمّ تشغيل ذلك الأمر ولن يتم تشغيله مرّة أخرى. تبدو المهمّة كما يلي: New Ansible task - name: Generate DB password shell: makepasswd --chars=32 args: creates: /var/www/laravel/.dbpw register: dbpwd نحتاج بعدها لإنشاء مستخدم قاعدة بيانات MySQL الفعلي مع كلمة السّر التي حدّدناها، يتم عمل ذلك باستخدام الوحدة mysql_user ونستطيع استخدام الخيار stdout على المتغيّر الذي عرّفناه خلال مهمّة توليد كلمة السّر للحصول على الخَرْج الخام لأمر الصدفة shell، مثل هذا: dbpwd.stdout. يقبل الأمر mysql_user اسم المستخدم والصلاحيّات المطلوبة، نريد في حالتنا إنشاء مستخدم يُدعى laravel وإعطاء هذا المستخدم صلاحيّات كاملة على الجدول laravel، نحتاج أيضًا إلى إخبار المهمّة أن يتم تشغيلها فقط عندما يتم تغيير المتغيّر dbpwd، والذي سيحدث فقط عند تشغيل مهمّة توليد كلمة السّر. يجب أن تبدو المهمّة كما يلي: New Ansible task - name: Create MySQL User mysql_user: name=laravel password={{ dbpwd.stdout }} priv=laravel.*:ALL state=present when: dbpwd.changed وبوضع كل ذلك معًا نفتح الملف php.yml من أجل تحريره كي نستطيع إضافة المهمّة السابقة: nano php.yml نبحث في البداية عن المهمّة install packages ونقوم بتحديثها لتتضمّن الحزمة makepasswd: Updated php.yml . . . - name: install packages apt: name={{ item }} update_cache=yes state=latest with_items: - git - mcrypt - nginx - php5-cli - php5-curl - php5-fpm - php5-intl - php5-json - php5-mcrypt - php5-sqlite - sqlite3 - mysql-server - mysql-client - php5-mysql - python-mysqldb - makepasswd notify: - restart php5-fpm - restart nginx . . . نضيف بعدها مهام توليد كلمة السّر، إنشاء قاعدة بيانات MySQL، وإنشاء مستخدم في نهاية الملف: Updated php.yml . . . - name: UFW limit <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> ufw: rule=limit port=<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> - name: UFW open HTTP ufw: rule=allow port=http - name: Create MySQL DB mysql_db: name=laravel state=present - name: Generate DB password shell: makepasswd --chars=32 args: creates: /var/www/laravel/.dbpw register: dbpwd - name: Create MySQL User mysql_user: name=laravel password={{ dbpwd.stdout }} priv=laravel.*:ALL state=present when: dbpwd.changed handlers: . . . لا تقم بتشغيل الـ playbook الآن، ربّما تكون قد لاحظت أنّه بالرغم من أنّنا أنشأنا مستخدم وقاعدة بيانات MySQL فلم نفعل أي شيء مع كلمة السّر، سنغطّي هذا الموضوع في الخطوة القادمة، عند استخدام مهام shell ضمن Ansible فمن المهم دومًا أن نتذكّر متابعة سير العمل الذي يتعلّق بخَرْج ونتائج المهمّة بأكمله قبل تشغيلها لنتجنّب الاضطرار إلى تسجيل الدخول يدويًّا وإعادة تعيين الحالة. الخطوة الثالثة – إعداد تطبيق PHP من أجل قاعدة البياناتسنقوم في هذه الخطوة بحفظ كلمة سر قاعدة بيانات MySQL في الملف .env من أجل التطبيق. سنحدّث الملف .env ليتضمن اعتمادات (credentials) قاعدة بياناتنا التي أنشأناها حديثًا، يحتوي ملف .env الخاص بـ Laravel الأسطر التالية بشكل افتراضي: Laravel .env file DB_HOST=localhost DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret نستطيع الإبقاء على السطر DB_HOST كما هو، ولكن سنحدّث الأسطر الثلاثة الأخرى باستخدام المهام التالية، وهي مشابهة جدًّا للمهام التي استخدمناها في الدّرس السابق من أجل تعيين APP_ENV و APP_DEBUG: New Ansible tasks - name: set DB_DATABASE lineinfile: dest=/var/www/laravel/.env regexp='^DB_DATABASE=' line=DB_DATABASE=laravel - name: set DB_USERNAME lineinfile: dest=/var/www/laravel/.env regexp='^DB_USERNAME=' line=DB_USERNAME=laravel - name: set DB_PASSWORD lineinfile: dest=/var/www/laravel/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ dbpwd.stdout }} when: dbpwd.changed وكما فعلنا مع مهمّة إنشاء مستخدم MySQL فقد استخدمنا متغيّر كلمة السر التي تمّ توليدها (dbpwd.stdout) لنشر الملف مع كلمة السّر، وأضفنا الخيار when لضمان أن يتم تشغيلها فقط عند تغيير dbpwd. وبما أنّ الملف .env موجود مسبقًا قبل إضافة مهمّة توليد كلمة السّر، فسنحتاج إلى حفظ كلمة السّر إلى ملف آخر، تبحث مهمّة توليد كلمة السّر عن وجود الملف (والذي أعددناه مسبقًا ضمن المهمّة)، سنستخدم أيضًا الخيارات sudo وsudo_user لإخبار Ansible أن يقوم بإنشاء الملف عن طريق المستخدم www-data: New Ansible task - name: Save dbpw file lineinfile: dest=/var/www/laravel/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present sudo: yes sudo_user: www-data when: dbpwd.changed نفتح الملف php.yml من أجل تحريره: nano php.yml نضيف المهام السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي: Updated php.yml . . . - name: Create MySQL User mysql_user: name=laravel password={{ dbpwd.stdout }} priv=laravel.*:ALL state=present when: dbpwd.changed - name: set DB_DATABASE lineinfile: dest=/var/www/laravel/.env regexp='^DB_DATABASE=' line=DB_DATABASE=laravel - name: set DB_USERNAME lineinfile: dest=/var/www/laravel/.env regexp='^DB_USERNAME=' line=DB_USERNAME=laravel - name: set DB_PASSWORD lineinfile: dest=/var/www/laravel/.env regexp='^DB_PASSWORD=' line=DB_PASSWORD={{ dbpwd.stdout }} when: dbpwd.changed - name: Save dbpw file lineinfile: dest=/var/www/laravel/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present sudo: yes sudo_user: www-data when: dbpwd.changed handlers: . . . لا تقم بتشغيل الـ playbook الآن، فقد بقيت لدينا خطوة واحدة يجب إكمالها قبل أن نتمكّن من تشغيل الـ playbook. الخطوة الرابعة – تهجير قاعدة البيانات Migrating the Databaseسنقوم في هذه الخطوة بتنفيذ تهجير قاعدة البيانات database migrations من أجل إعداد جداول قاعدة البيانات. يتم فعل هذا في Laravel عن طريق تنفيذ الأمر migrate (على سبيل المثال php artisan migrate --force) بداخل دليل Laravel، لاحظ أنّنا أضفنا العَلَم force-- لأنّ بيئة production تحتاجه. تبدو مهمّة Ansible للقيام بهذا كما يلي: New Ansible task - name: Run artisan migrate shell: php /var/www/laravel/artisan migrate --force sudo: yes sudo_user: www-data when: dbpwd.changed حان الوقت الآن لتحديث playbook الخاصّة بنا، نفتح الملف php.yml لتحريره: nano php.yml نضيف المهام السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي: Updated php.yml . . . - name: Save dbpw file lineinfile: dest=/var/www/laravel/.dbpw line="{{ dbpwd.stdout }}" create=yes state=present sudo: yes sudo_user: www-data when: dbpwd.changed - name: Run artisan migrate shell: php /var/www/laravel/artisan migrate --force sudo: yes sudo_user: www-data when: dbpwd.changed handlers: . . . بإمكاننا أخيرًا حفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass عند الانتهاء من تنفيذ هذا نقوم بتحديث الصفحة في متصفحنا ويجب أن نرى عندها رسالة تقول: your_server_ip/'>http://your_server_ip/ Queue: NO Cron: NO يعني هذا أنّ تم إعداد قاعدة البيانات بشكل صحيح وأنّها تعمل كما هو متوقع، ولكنّنا لم نقم حتى الآن بإعداد مهام cron أو عفريت الطابور queue daemon، والتي سنقوم بها في الدرس القادم. الخاتمةتحدّثنا في هذا الدّرس عن طريقة إعداد قاعدة بيانات MySQL وإعداد تطبيق PHP من أجلها ومن ثمّ تهجير قاعدة البيانات من أجل نشر تطبيق PHP متقدّم باستخدام Ansible. ترجمة -وبتصرّف- لـ How To Deploy an Advanced PHP Application Using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  11. هذا الدّرس هو جزء من سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu، تحدّثنا في الجزئين السّابقين عن تثبيت Ansible وإعداده ومن ثم عن إعداد Laravel وNginx. سنغطّي في هذا الدّرس إعداد مفاتيح SSH لتدعم أدوات نشر وتوزيع الشيفرة، وإعداد الجدار الناري للنظام، هدفنا في النهاية هو الحصول على خادوم يعمل عليه تطبيق PHP بشكل كامل مع الإعدادات المذكورة آنفًا. المتطلبات الأساسيةيبدأ هذا الدّرس مباشرة من حيث انتهى الجزء السّابق من هذه السلسلة، ونحتاج كافّة الملفّات والإعدادات التي تم الحصول عليها في ذلك الجزء، إن لم تقم بإكمال أول قسمين من هذه السلسلة فنرجو أن تفعل ذلك قبل متابعة هذا الدّرس. الخطوة الأولى – تبديل مستودع التطبيقسنقوم في هذه الخطوة بتحديث مستودع Git إلى مثال عن مستودع مُخصَّص قليلًا. بما أنّ تثبيت Laravel الافتراضي لا يتطلّب الميّزات المتقدمة التي سنقوم بإعدادها في هذا الدّرس فسنقوم بتبديل المستودع الموجود حاليًّا إلى مثال عن مستودع مع إضافة شيفرة للتنقيح debugging code فقط من أجل أن نظهر متى يعمل كل شيء، يُوجد المستودع الذي سنستخدمه على الرابط https://github.com/do-community/do-ansible-adv-php. نقوم بتغيير الدليل إلى ansible-php: cd ~/ansible-php/ نفتح playbook الموجودة حاليًّا من أجل تحريرها: nano php.yml نقوم بإيجاد وتحديث المهمّة “Clone git repository” بحيث تبدو كما يلي: Updated Ansible task - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/do-community/do-ansible-adv-php update=yes version=example sudo: yes sudo_user: www-data register: cloned نحفظ ونشغل الـ playbook: ansible-playbook php.yml --ask-sudo-pass وبعد أن يتم تشغيلها نزور خادومنا في متصفح الويب لدينا (على الرابط http://your_server-ip بعد وضع عنوان خادومك)، ينبغي أن نشاهد رسالة تقول لم يتم العثور على التعريف "could not find driver". يعني هذا أنّنا نجحنا في استبدال المستودع الافتراضي بمثال مستودعنا، ولكن لا يستطيع التطبيق الاتصال بقاعدة البيانات، وهو ما نتوقع مشاهدته هنا، وسنقوم بتثبيت وإعداد قاعدة البيانات لاحقًا في هذا الدّرس. الخطوة الثانية – إعداد مفاتيح SSH من أجل النشرسنقوم في هذه الخطوة بإعداد مفاتيح SSH والتي يُمكن استخدامها من أجل نشر شيفرة التطبيق. ومع أنّ Ansible رائعة من أجل المحافظة على الإعدادات وإعداد الخواديم والتطبيقات، فيتم عادةً استخدام أدوات مثل Envoy و Rocketeer من أجل دفع تغييرات الشيفرة إلى الخادوم وتنفيذ أوامر التطبيق عن بُعد، تتطلّب أغلب هذه الأدوات اتصال SSH يتمكن من النفاذ إلى تثبيت التطبيق بشكل مباشر، يعني هذا في حالتنا أنّنا نحتاج إلى إعداد مفاتيح SSH من أجل المستخدم www-data. سنحتاج إلى ملف مفتاح عام من أجل المستخدم الذي نرغب بدفع الشيفرة منه، يُوجد هذا الملف بشكل نموذج في المسار ssh/id_rsa.pub./~، ننسخ هذا الملف إلى الدليل ansible-php: cp ~/.ssh/id_rsa.pub ~/ansible-php/deploykey.pubبإمكاننا استخدام الوحدة authorized_key لـ Ansible من أجل تثبيت مفتاحنا العام داخل var/www/.ssh/authorized_keys/ والذي سيسمح لأدوات النشر بالاتصال والنفاذ إلى تطبيقنا، تحتاج الإعدادات فقط إلى معرفة مكان المفتاح، باستخدام lookup، وإلى معرفة المستخدم الذي سيتم تثبيت المفتاح لأجله (www-data في حالتنا). New Ansible task - name: Copy public key into /var/www authorized_key: user=www-data key="{{ lookup('file', 'deploykey.pub') }}" نحتاج أيضًا لإعداد صدفة shell المستخدم www-data كي نستطيع فعليًّا تسجيل الدخول، وإلّا سيسمح SSH بالاتصال ولكن لن يتم عرض صدفة shell للمستخدم، يُمكن عمل هذا باستخدام الوحدة user وتعيين الصدفة إلى /bin/bash (أو الصدفة المفضلة لديك): New Ansible task - name: Set www-data user shell user: name=www-data shell=/bin/bash نفتح الآن الـ playbook لتحريرها من أجل إضافة المهام الجديدة: nano php.yml نضيف المهام السابقة إلى الـ playbook التي تُدعى php.yml، يجب أن تبدو نهاية الملف متطابقة مع التالي: Updated php.yml . . . - name: Configure nginx template: src=nginx.conf dest=/etc/nginx/sites-available/default notify: - restart php5-fpm - restart nginx - name: Copy public key into /var/www authorized_key: user=www-data key="{{ lookup('file', 'deploykey.pub') }}" - name: Set www-data user shell user: name=www-data shell=/bin/bash handlers: . . . نقوم بحفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass عندما تنتهي Ansible من ذلك ينبغي أن نكون قادرين على الدخول باستخدام SSH عن طريق المستخدم www-data: ssh www-data@your_server_ip إن استطعنا تسجيل الدخول بنجاح فهي تعمل بشكل صحيح، بإمكاننا الآن تسجيل الخروج عن طريق إدخال logout أو ضغط CTRL+D. لن نحتاج إلى استخدام هذا الاتصال في أي خطوات لاحقة، ولكن يبقى مفيدًا إن قمنا بإعداد أدوات أخرى، كما أشرنا سابقًا، أو من أجل التنقيح العام general debugging وصيانة التطبيق كما هو مطلوب. الخطوة الثالثة – إعداد الجدار الناريسنقوم في هذه الخطوة بإعداد الجدار الناري على الخادوم للسماح فقط بالاتصالات من أجل HTTP وSSH. يأتي Ubuntu مع جدار ناري يُدعى UFW (الجدار الناري غير المعقد Uncomplicated Firewall) مُثبَّت عليه بشكل افتراضي، وتدعمه Ansible بالوحدة ufw، يمتلك عدد من الميزات القوية وتمّ تصميمه ليكون بسيطًا قدر الإمكان وهو ملائم بشكل مثالي لخواديم الويب المحتواة ذاتيًّا والتي تحتاج فقط إلى عدة منافذ مفتوحة، نرغب في حالتنا بأن يكون المنفذ 80 (من أجل HTTP) والمنفذ 22 (من أجل SSH) مفتوحًا، وربّما قد تريد المنفذ 443 مفتوحًا من أجل HTTPS. تمتلك الوحدة ufw عددًا من الخيارات المختلفة تقوم بتنفيذ مهام مختلفة، وهذه المهام التي نريد تنفيذها هي: تمكين UFW ورفض كامل حركة مرور البيانات traffic القادمة افتراضيًّا.فتح منفذ SSH ولكن مع تحديده لمنع هجمات القوة القاسية brute force attacks.فتح منفذ HTTP.يُمكِن فعل هذا باستخدام المهام التالية على الترتيب: New Ansible tasks - name: Enable UFW ufw: direction=incoming policy=deny state=enabled - name: UFW limit SSH ufw: rule=limit port=ssh - name: UFW open HTTP ufw: rule=allow port=http </code>نفتح الملف php.yml من أجل تحريره: nano php.ymlنضيف المهام السابقة إلى الـ playbook، ينبغي أن تتطابق نهاية الملف مع التالي: Updated php.yml . . . - name: Copy public key into /var/www authorized_key: user=www-data key="{{ lookup('file', 'deploykey.pub') }}" - name: Set www-data user shell user: name=www-data shell=/bin/bash - name: Enable UFW ufw: direction=incoming policy=deny state=enabled - name: UFW limit SSH ufw: rule=limit port=ssh - name: UFW open HTTP ufw: rule=allow port=http handlers: . . . نقوم بحفظ وتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass بعد أن يتم هذا بنجاح يجب أن نكون قادرين على الاتصال عبر SSH (باستخدام Ansible) أو HTTP إلى خادومنا، ستكون المنافذ الأخرى مقفلة الآن. نستطيع التحقّق من حالة UFW في أي وقت عن طريق تنفيذ هذا الأمر: ansible php --sudo --ask-sudo-pass -m shell -a "ufw status verbose" وبتقسيم أمر Ansible السابق من أجل فهمه نجد: ansible: تقوم بتنفيذ مهمّة Ansible خام بدون playbook.php: تقوم بتنفيذ المهمّة على المضيفين في هذه المجموعة.--sudo: تنفّذ الأمر كـ sudo.--ask-sudo-pass: تقوم بالحث prompt من أجل كلمة سر sudo.-m shell: تقوم بتشغيل وحدة الصدفة shell.-a "ufw status verbose“: الخيارات التي يجب تمريرها إلى الوحدة، وبما أنّها أمر shell نقوم بتمرير الأمر الخام raw (أي ufw status verbose) مباشرة بدون أي خيارات key=value.يجب أن يُعيد شيئًا مشابهًا لهذا: UFW status output your_server_ip | success | rc=0 >> Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), disabled (routed) New profiles: skip To Action From -- ------ ---- 22 LIMIT IN Anywhere 80 ALLOW IN Anywhere 22 (v6) LIMIT IN Anywhere (v6) 80 (v6) ALLOW IN Anywhere (v6) ترجمة -وبتصرّف- لـ How To Deploy an Advanced PHP Application Using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  12. سنواصل في هذا الدّرس حديثنا حول نشر تطبيق PHP باستخدام Ansible. هذا الدّرس هو الجزء الثّاني للسلسلة، إذا لم تقرأ الجزء الأول فمن الأفضل أن تشرع به أوّلا، حيث نُعالج فيه تثبيت Ansible وإعداده. إذا لم تكن لديك أيّة خلفية مُسبقة حول Ansible فمن الأفضل أن تبدأ مع مقال كيفيّة تثبيت وإعداد Ansible على Ubuntu. سنتحدث في هذا القسم من الدّرس عن كيفية الحصول على إطار عمل Laravel وإعداده وإعداد خادوم Nginx لتخديم تطبيق PHP. سنستخدم إطار عمل Laravel كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك. المتطلبات الأساسيةيبدأ هذا الدّرس مباشرة من حيث انتهى الجزء الأول من هذه السلسلة، ونحتاج كافّة الملفّات والإعدادات التي تم الحصول عليها في ذلك الجزء، إن لم تقم بإكمال أول درس من هذه السلسلة فنرجو أن تفعل ذلك قبل متابعة هذا الدّرس. الخطوة الأولى – استنساخ مستودع Gitفي هذا القسم سنقوم باستنساخ clone مستودع إطار عمل Laravel إلى الخادوم الخاص بنا باستخدام Git، سنشرح مثل الخطوة الثالثة كافّة الأقسام التي سنقوم بإضافتها إلى الـ playbook، ونضمّن بعدها كامل ملف php.yml من أجلك لتقوم بنسخه ولصقه. وقبل أن نستنسخ مستودع Git الخاص بنا نحتاج إلى التأكّد من وجود الدليل var/www/، نستطيع فعل هذا عن طريق إنشاء مهمّة مع وحدة الملف: - name: create /var/www/ directory file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700 نحتاج كما أشرنا سابقًا إلى استخدام الوحدة Git لاستنساخ المستودع إلى الخادوم الخاص بنا، وهي عمليّة بسيطة لأنّ كل ما نحتاجه بشكل طبيعي من أجل الأمر git clone هو مستودع المصدر source repository، في هذه الحالة سنعرّف أيضًا الوجهة destination ونخبر Ansible بعدم تحديث المستودع في حال وجوده مسبقًا عن طريق تعيين update=no، وبما أنّنا نستخدم Laravel سنستعمل رابط مستودع git التالي: https://github.com/laravel/laravel.git نحتاج مع ذلك إلى تشغيل المهمّة عن طريق المستخدم www-data للتأكّد من أنّ الصلاحيّات صحيحة، ولعمل هذا نستطيع إخبار Ansible أن ينفّذ الأمر كمستخدم محدّد باستخدام sudo، ستبدو المهمّة النهائية كما يلي: - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data ملاحظة: من أجل المستودعات المعتمدة على SSH نستطيع إضافة accept_hostkey=yes لمنع التحقّق من المضيف على SSH من تعليق المهمّة. نفتح الملف php.yml لتحريره: nano php.yml نضيف المهام السابقة إلى الـ playbook، يجب أن يبدو الملف النهائي كما يلي: ... - name: enable php5 mcrypt module shell: php5enmod mcrypt args: creates: /etc/php5/cli/conf.d/20-mcrypt.ini - name: create /var/www/ directory file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700 - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نحفظ الـ playbook ونغلقها، ثمّ نقوم بتشغيلها: ansible-playbook php.yml --ask-sudo-pass الخطوة الثانية – إنشاء تطبيق باستخدام Composerسنستخدم في هذه الخطوة Composer لتثبيت تطبيق PHP واعتمادياته dependencies. يمتلك Composer الأمر create-project الذي يقوم بتثبيت كافّة الاعتماديات المطلوبة ومن ثمّ يُشغِّل خطوات إنشاء المشروع المُعرَّفة في القسم post-create-project-cmd من الملف composer.json، وهي الطريق المفضّلة للتأكّد من إعداد التطبيق بشكل صحيح لاستخدامه لأول مرّة. نستطيع استخدام مهمّة Ansible التالية لتنزيل وتثبيت Composer بشكل عمومي كـ usr/local/bin/composer/، سيكون بعدها قابلًا للنفاذ من قبل أي شخص يستخدم الخادوم بما فيهم Ansible: - name: install composer shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer args: creates: /usr/local/bin/composer ومع وجود Composer مُثبّتًا لدينا فهنالك وحدة لـ Composer يُمكننا استخدامها، في حالتنا نريد إخبار Composer عن مكان مشروعنا (باستخدام المُعامِل working_dir)، ونريد أيضًا تنفيذ الأمر create-project، نحتاج أيضًا لإضافة المُعامِل optimize_autoloader=no لأنّ هذا العَلَم غير مدعوم من قبل الأمر create-project، وكما في حالة الأمر git يجب علينا تنفيذ هذا عن طريق المستخدم www-data للتأكّد من صلاحيّة الأذونات permissions، وبوضع كل ذلك معًا نحصل على هذه المهمّة: - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data ملاحظة: قد تستغرق المهمّة create-project قدرًا كبيرًا من الوقت على خادوم جديد، حيث يمتلك الـ Composer ذاكرة تخزين مؤقّت فارغة ويحتاج إلى تنزيل كل شيء من جديد. نفتح الآن الملف php.yml لتحريره: nano php.yml نضيف المهام السابقة في نهاية القسم tasks فوق handlers بحيث تتوافق نهاية الـ playbook مع التالي: ... - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data - name: install composer shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer args: creates: /usr/local/bin/composer - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نقوم أخيرًا بتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass ما الذي سيحدث إن قمنا بتشغيل Ansible مرّة أخرى الآن؟ سيتم تشغيل composer create-project مرّة أخرى، وفي حالة Laravel يعني هذا APP_KEY جديد، لذا نريد بدلًا من ذلك تعيين المهمّة لتعمل فقط بعد استنساخ clone جديد، نستطيع ضمان أنّها تعمل فقط مرّة واحدة عن طريق تسجيل متغيّر يحتوي نتائج المهمّة git clone ومن ثمّ التحقّق من هذه النتائج داخل المهمّة composer create-project، إن تمّ تغيير المهمّة git clone فسيتم تنفيذ composer create-project، أمّا إن لم يحدث ذلك فسيتم تخطّيها. ملاحظة: يبدو أنّه يوجد خطأ برمجي في بعض إصدارات وحدة composer في Ansible، وربّما تعيد الخَرْج OK بدلًا من Changed، حيث تتجاهل أنّه تمّ تنفيذ scripts على الرغم من أنّه لم يتم تثبيت اعتماديات. نفتح الملف php.yml من أجل تحريره: nano php.yml نبحث عن المهمّة git clone، نضيف الخيار register لحفظ نتائج المهمّة إلى المتغير cloned كما يلي: - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data register: cloned </code>نبحث بعدها عن المهمّة composer create-project، نضيف الخيار when للتحقّق من المتغيّر cloned لنرى إن تغيّرت قيمته أم لا: - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data when: cloned|changed نقوم بحفظ الـ playbook وتشغيلها: ansible-playbook php.yml --ask-sudo-pass سيوقف الـ Composer الآن تغيير APP_KEY في كل مرّة يتم تشغيله فيها. الخطوة الثالثة – تحديث متغيرات البيئةفي هذه الخطوة سنقوم بتحديث متغيّرات البيئة Environment Variables من أجل تطبيقنا. يأتي Laravel مع ملف env. بشكل افتراضي والذي يقوم بتعيين قيمة APP_ENV إلى local وقيمة APP_DEBUG إلى true، نحتاج إلى تبديل هذه القيم إلى production و false على الترتيب، يُمكِن فعل هذا ببساطة باستخدام الوحدة lineinfile مع المهام التالية: - name: set APP_DEBUG=false lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false - name: set APP_ENV=production lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production نفتح الملف php.yml لتحريره: nano php.yml نضيف هذه المهمّة إلى الـ playbook، يجب أن تبدو نهاية الملف متطابقة مع التالي: ... - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data when: cloned|changed - name: set APP_DEBUG=false lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false - name: set APP_ENV=production lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نقوم بحفظ الـ playbook وتشغيلها: ansible-playbook php.yml --ask-sudo-pass إنّ الوحدة lineinfile مفيدة جدًا من أجل التطويعات tweaks السريعة لأي ملف نصّي، وهي رائعة للتأكّد من تعيين متغيّرات بيئة كهذه بشكل صحيح. الخطوة الرابعة – إعداد Nginxسنقوم في هذا القسم بإعداد Nginx لتخديم تطبيق PHP. إن زرت الآن الخادوم الخاص بك في متصفّح الإنترنت (على سبيل المثال http://your_server_ip )، فسترى صفحة Nginx الافتراضيّة بدلاً من صفحة المشروع الجديد في Laravel، حدث هذا لأنّنا لا زلنا نحتاج إلى إعداد خادوم ويب Nginx لدينا لتخديم التطبيق من الدليل var/www/laravel/public/، لفعل هذا نحتاج لتحديث إعدادات Nginx الافتراضيّة بهذا الدليل وإضافة دعم من أجل php-fpm بحيث يستطيع التعامل مع PHP scripts. نقوم بإنشاء ملف جديد يُدعى nginx.conf: nano nginx.conf نحفظ كتلة الخادوم التالية بداخل هذا الملف، تستطيع متابعة الخطوة الرابعة من هذا الدّرس من أجل المزيد من التفاصيل حول إعدادات Nginx، تُحدِّد التعديلات التالية مكان دليل Laravel العام وتتحقّق من استخدام Nginx لاسم المضيف الذي عرّفناه في الملف hosts كـ server_name مع المتغيّر inventory_hostname. nginx.conf server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /var/www/laravel/public; index index.php index.html index.htm; server_name {{ inventory_hostname }}; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/laravel/public; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } نحفظ الملف nginx.conf ونغلقه. بإمكاننا الآن استخدام وحدة القالب template module لدفع ملف الإعدادات الجديدة عبرها، تبدو وحدة template مشابهة جدًا للوحدة copy، ولكن يوجد فرق كبير بينهما، فالوحدة copy ستنسخ ملف أو عدّة ملفّات بدون القيام بأيّة تغييرات، بينما تنسخ الوحدة template ملفًّا واحدًا وتقوم بتحليل كافّة الملفّات الموجودة بداخله، ولأنّنا استخدمنا {{ inventory_hostname }} داخل ملف إعداداتنا سنستخدم الوحدة template بحيث يتم تحليلها بداخل عنوان IP الذي استخدمناه في الملف hosts، وبهذه الطريقة لا يتوجّب علينا كتابة شيفرة محدّدة لملفّات الإعدادات التي تستخدمها Ansible. ومع ذلك فكما هو معتاد عند كتابة المهام نحتاج إلى أن نأخذ بعين الاعتبار ما سيحدث على الخادوم، ولأنّنا نقوم بتغيير إعدادات Nginx نحتاج لإعادة تشغيل Nginx و php-fpm، يتم هذا باستخدام الخيار notify: - name: Configure nginx template: src=nginx.conf dest=/etc/nginx/sites-available/default notify: - restart php5-fpm - restart nginx نفتح ملف php.yml: nano php.yml نضيف مهمّة nginx هذه في نهاية قسم المهام، ينبغي أن يبدو الملف php.yml كما يلي: php.yml --- - hosts: php sudo: yes tasks: - name: install packages apt: name={{ item }} update_cache=yes state=latest with_items: - git - mcrypt - nginx - php5-cli - php5-curl - php5-fpm - php5-intl - php5-json - php5-mcrypt - php5-sqlite - sqlite3 - name: ensure php5-fpm cgi.fix_pathinfo=0 lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0 notify: - restart php5-fpm - restart nginx - name: enable php5 mcrypt module shell: php5enmod mcrypt args: creates: /etc/php5/cli/conf.d/20-mcrypt.ini - name: create /var/www/ directory file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700 - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data register: cloned - name: install composer shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer args: creates: /usr/local/bin/composer - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data when: cloned|changed - name: set APP_DEBUG=false lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false - name: set APP_ENV=production lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production - name: Configure nginx template: src=nginx.conf dest=/etc/nginx/sites-available/default notify: - restart php5-fpm - restart nginx handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نقوم بحفظ الـ playbook وتشغيلها مرّة أخرى: ansible-playbook php.yml --ask-sudo-pass حالما تكتمل نعود إلى متصفحنا ونقوم بتحديثه، ينبغي أن نرى الآن صفحة المشروع الجديد في Laravel. الخاتمةيُغطّي هذا الدرس نشر تطبيق PHP مع مستودع عام، وبينما يكون هذا مثاليًّا من أجل تعلّم كيفيّة عمل Ansible، فإنّك لن تعمل دائمًا على مشاريع مفتوحة المصدر بشكل كامل مع مستودعات مفتوحة، ويعني هذا أنّك ستحتاج إلى استيثاق git clone في الخطوة الثالثة مع مستودعك الخاص، يُمكِن فعل هذا بسهولة باستخدام مفاتيح SSH. على سبيل المثال بعدما تقوم بإنشاء وإعداد مفاتيح نشر SSH على مستودعك تستطيع استخدام Ansible لنسخها وإعدادها على خادومك قبل مهمّة git clone: - name: create /var/www/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/ directory file: dest=/var/www/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/ state=directory owner=www-data group=www-data mode=0700 - name: copy private <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> key copy: src=deploykey_rsa dest=/var/www/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/id_rsa owner=www-data group=www-data mode=0600يجب أن يسمح هذا للخادوم بالاستيثاق بشكل صحيح ونشر تطبيقك. لقد قمنا للتو بنشر تطبيق PHP بسيط على خادوم ويب Nginx معتمد على Ubuntu باستخدام Composer لإدارة الاعتماديّات، وتمّ كل هذا بدون الحاجة للدخول مباشرة إلى الخادوم الخاصّ بنا وتنفيذ أي أمر بشكل يدوي. ترجمة -وبتصرّف- لـ How To Deploy a Basic PHP Application Using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  13. ستغطّي هذه السّلسلة عمليّة نشر تطبيق PHP بسيط باستخدام Ansible، الهدف النّهائي سيكون الحصول على خادوم ويب جديد يُخدِّم تطبيق PHP بسيط بدون أي اتصال عبر SSH أو تشغيل يدوي للأوامر على الخادوم الهدف، سنغطي في هذا القسم من الدرس تثبيت Ansible وإعداد البيئة بشكل عام. سنستخدم إطار عمل Laravel كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك. المتطلبات الأساسيةسنستخدم Ansible لتثبيت وإعداد Nginx، PHP، وخدمات أخرى على خادوم Ubuntu 14.04 ، يعتمد هذا الدّرس على معرفتك الأساسية بـ Ansible لذا إن كنت جديدًا عليها فبإمكانك قراءة درس Ansible الأساسي أولًا. ستحتاج لمتابعة هذا الدّرس إلى: خادوم Ubuntu 14.04 بأي حجم والذي سنستخدمه لإعداد ونشر تطبيق PHP الخاص بنا عليه، ستتم الإشارة إلى عنوان IP هذا الجهاز بـ your_server_ip خلال هذا الدّرس.خادوم Ubuntu 14.04 والذي سنستخدمه من أجل Ansible، وهو الخادوم الذي سنبقى في وضعية تسجيل دخول عليه في كامل هذا الدّرس.إعداد مستخدم غير جذري مع صلاحيّات sudo لكل خادوم.مفاتيح SSH من أجل خادوم Ansible لتصريح تسجيل الدخول على خادوم نشر PHP، ويُمكِن إعدادها باتّباع هذه السلسلة وتطبيقها على خادوم Ansible الخاص بنا.الخطوة الأولى – تثبيت Ansibleيُمكِن إنجاز هذه الخطوة بسهولة عن طريق تثبيت PPA (أرشيف الحِزَم الشخصي Personal Package Archive) وتثبيت حزمة Ansible باستخدام apt. نُضيف أوّلًا PPA باستخدام الأمر apt-add-repository: sudo apt-add-repository ppa:ansible/ansibleوبعد انتهائه نقوم بتحديث ذاكرة التخزين المؤقّت cache لـ apt: sudo apt-get update نقوم بتثبيت Ansible أخيرًا: sudo apt-get install ansibleحالما يتم تثبيت Ansible نقوم بإنشاء دليل جديد للعمل بداخله وضبط الإعدادات الأساسيّة، تستخدم Ansible افتراضيًّا ملف مضيفين hosts موجود في المسار etc/ansible/hosts/، وهو يحتوي كافّة الخواديم التي يُديرها، وبينما يكون هذا الملف مناسبًا لبعض حالات الاستخدام فهو عام global، وهو ما لا نريده هنا. سنقوم من أجل هذا الدّرس بإنشاء ملف مضيفين محلّي local واستخدامه بدلًا من الملف السابق، نستطيع فعل هذا عن طريق إنشاء ملف إعدادات Ansible جديد بداخل دليل العمل لدينا، والذي بإمكاننا استخدامه لإخبار Ansible بأن تبحث عن ملف المضيفين داخل نفس الدليل. نُنشِئ مُجلّدًا جديدًا (سنستخدمه لبقيّة هذا الدّرس): mkdir ~/ansible-php ننتقل إلى داخل المُجلّد الجديد: cd ~/ansible-php/نُنشِئ ملفًّا جديدًا يُدعى ansible.cfg ونفتحه من أجل تحريره باستخدام nano أو أي مُحرِّر نصوص تفضله: nano ansible.cfgنضيف خيار الإعدادات hostfile مع القيمة hosts في المجموعة [defaults] عن طريق نسخ ما يلي إلى الملف ansible.cfg: ansible.cfg [defaults] hostfile = hostsنحفظ الملف ansible.cfg ونغلقه، نقوم بعدها بإنشاء الملف hosts والذي يحتوي على عنوان IP لخادوم PHP حيث سيتم نشر تطبيقنا. nano hostsننسخ ما يلي لإضافة قسم من أجل php مع وضع عنوان IP الخاص بخادومك بدلًا من your_server_ip ووضع اسم المستخدم غير الجذري الذي قمت بإنشائه في المتطلبات الأساسيّة على خادوم PHP بدلًا من sammy: hosts [php] your_server_ip ansible_ssh_user=sammy نحفظ ونغلق الملف hosts، فلنقم بإجراء تحقّق أبسط للتأكد من قدرة Ansible على الاتصال بالمضيف كما هو متوقّع عن طريق استدعاء الوحدة ping على المجموعة php الجديدة: ansible php -m pingربّما تحصل على تحقّق من استيثاق مُضيف SSH اعتمادًا على كونك قد سجلّت الدخول إلى هذا المُضيف من قبل، ينبغي أن تعود ping باستجابة ناجحة تبدو كما يلي: Output 111.111.111.111 | success >> { "changed": false, "ping": "pong" تمّ الآن تثبيت وإعداد Ansible بنجاح، نستطيع الانتقال إلى إعداد خادوم الويب لدينا. الخطوة الثانية – تثبيت الحزم المطلوبةسنقوم في هذه الخطوة بتثبيت بعض حِزَم النظام المطلوبة باستخدام Ansible و apt، سنثبت تحديدًا git، nginx، sqlite3، mcrypt، وبعض حِزَم php5-*. نحتاج قبل إضافة الوحدة apt لتثبيت الحِزَم التي نريدها إلى إنشاء playbook بسيط (وهو عبارة عن قواعد تُحدِّد إعدادات Ansible)، سنبني على هذا الـ playbook مع تقدّمنا في هذا الدّرس، نقوم بإنشاء playbook جديد يُدعى php.yml: nano php.yml نلصق الإعدادات التالية، يُحدِّد أول سطرين مجموعة المضيفين التي نرغب باستخدامها (php) وتتحقّق من أنّها تنفّذ الأوامر باستخدام sudo افتراضيًّا، تُضيف باقي الأسطر وحدة بالحِزَم التي نحتاجها، تستطيع تخصيصها من أجل تطبيقاتك الخاصّة أو استخدام الإعدادات التالية إن كنت تتبع مثال تطبيق Laravel: --- - hosts: php sudo: yes tasks: - name: install packages apt: name={{ item }} update_cache=yes state=latest with_items: - git - mcrypt - nginx - php5-cli - php5-curl - php5-fpm - php5-intl - php5-json - php5-mcrypt - php5-sqlite - sqlite3نحفظ الملف php.yml، ونقوم أخيرًا بتشغيل ansible-playbook لتثبيت الحِزَم على الخادوم، يجب ألّا ننسى استخدام الخيار --ask-sudo-pass إن كان يتطلّب مستخدم sudo على خادوم PHP كلمة سر: ansible-playbook php.yml --ask-sudo-passالخطوة الثالثة – تعديل ملفات إعدادات النظامسنقوم في هذا القسم بتعديل بعض ملفّات إعدادات النظام على خادوم PHP، أهم خيار إعدادات يُمكِن تغييره (بغض النظر عن ملفّات Nginx، والتي سيتم تغطيتها في خطوة لاحقة) هو الخيار cgi.fix_pathinfo في php5-fpm، لأنّ القيمة الافتراضيّة له تُشكِّل خطرًا أمنيًّا. سنوضّح أوّلًا جميع الأقسام التي سنضيفها إلى هذا الملف، ونضمّن بعدها كامل الملف php.yml من أجلك لكي تقوم بنسخه ولصقه. يُمكِن استخدام الوحدة lineinfile للتأكّد من أنّ قيمة الإعدادات ضمن الملف مطابقة تمامًا لما نتوقعه، يُمكِن عمل هذا باستخدام تعبير نمطي regular expression عام بحيث تتمكّن Ansible من فهم معظم الصيغ التي من المحتمل أن يكون فيها المُعامِل، سنحتاج أيضًا لإعادة تشغيل php5-fpm وnginx لضمان تطبيق التغييرات، لذا نحتاج إلى إضافة مُداوِلَين handlers اثنين أيضًا في قسم جديد للمداولات handlers، تكون المداولات مثاليّة لهذا لأنّه يتم إطلاقها فقط عند تغيير المهمّة، ويتم أيضًا تشغيلها في نهاية الـ playbook، لذا يُمكن لمهام متعدّدة استدعاء نفس المُداوِل وسيعمل فقط مرّة واحدة. يبدو القسم الذي يُنفِّذ ما سبق كما يلي: name: ensure php5-fpm cgi.fix_pathinfo=0 lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0 notify: - restart php5-fpm - restart nginx handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restartedملاحظة: خطأ برمجي bug في إصدار Ansible 1.9.1 يوجد خطا برمجي في إصدار Ansible 1.9.1 يمنع php5-fpm من إعادة تشغيلها مع الوحدة service، وقد استخدمنا هذا في مُداولاتنا. وحتى يتم إصدار إصلاح له نستطيع الالتفاف على هذه المشكلة عن طريق تغيير المُداوِل restart php5-fpm من استخدام الأمر service إلى استخدام الأمر shell كما يلي: - name: restart php5-fpm shell: service php5-fpm restartسيتجاوز هذا المشكلة ويعيد تشغيل php5-fpm بشكل صحيح. نحتاج بعد ذلك أيضًا إلى التأكّد من تمكين الوحدة php5-mcrypt، يُمكن فعل هذا عن طريق تنفيذ script يُدعى php5enmod باستخدام صدفة المهام shell task والتحقّق من وجود الملف 20-mcrypt.ini في مكانه عند تمكينه، لاحظ أنّنا نخبر Ansible أنّ المهمّة تقوم بإنشاء ملف مُحدَّد، فإن كان هذا الملف موجودًا فلن يتم تشغيل المهمّة: name: enable php5 mcrypt module shell: php5enmod mcrypt args: creates: /etc/php5/cli/conf.d/20-mcrypt.iniنفتح الآن الملف php.yml لتحريره مرّة أخرى: nano php.ymlنضيف المهام والمداولات السابقة بحيث يتطابق الملف مع التالي: --- - hosts: php sudo: yes tasks: - name: install packages apt: name={{ item }} update_cache=yes state=latest with_items: - git - mcrypt - nginx - php5-cli - php5-curl - php5-fpm - php5-intl - php5-json - php5-mcrypt - php5-sqlite - sqlite3 - name: ensure php5-fpm cgi.fix_pathinfo=0 lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0 notify: - restart php5-fpm - restart nginx - name: enable php5 mcrypt module shell: php5enmod mcrypt args: creates: /etc/php5/cli/conf.d/20-mcrypt.ini handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نقوم أخيرًا بتشغيل playbook: ansible-playbook php.yml --ask-sudo-pass يمتلك الآن الخادوم كافّة الحِزَم المطلوبة مُثبّتة عليه ومجموعة الإعدادات الأساسيّة جاهزة للانطلاق. الخاتمةتحدثنا في القسم الأول من هذا الدّرس عن طريقة تثبيت Ansible وإعداد البيئة بشكل عام من أجل التحضير لعمليّة نشر تطبيق PHP بسيط باستخدام Ansible، وسنكمل في القسم الثاني الحصول على Laravel وإعداده وإعداد خادوم Nginx لتخديم تطبيق PHP. ترجمة -وبتصرّف- لـ How To Deploy a Basic PHP Application Using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  14. تمّ تصميم أنظمة إدارة الإعدادات لتجعل التحكّم بعدد كبير من الخواديم أمرًا سهلًا لمديري الأنظمة وفرق العمليّات، فهي تسمح لنا بالتحكّم بالعديد من الأنظمة المختلفة بطريقة مؤتمتة من موقع مركزي واحد. وبينما تتوافر العديد من أنظمة إدارة الإعدادات الشائعة من أجل أنظمة Linux، مثل Chef وPuppet، فهي غالبًا معقدة أكثر من حاجة الناس، تُشكّل Ansible بديلًا رائعًا لهذه الخيارات لأنّها تحتوي على عقبات أقل بكثير عند البدء معها. سنناقش في هذا الدّرس كيفيّة تثبيت Ansible على خادوم Ubuntu وسنمر على بعض الأساسيات حول كيفيّة استخدام هذه البرمجيّة. كيف تعمل Ansible؟تعمل Ansible عن طريق إعداد أجهزة العملاء من خلال حاسوب يمتلك مكوّنات Ansible مثبّتة ومُعدّة عليه. تتواصل عبر قنوات SSH الاعتياديّة من أجل استعادة المعلومات من الأجهزة عن بُعد remote، إصدار الأوامر، ونسخ الملفّات، ولهذا السبب لا يتطلّب نظام Ansible تثبيت أي برمجيّات إضافيّة على حواسيب العملاء. هذه هي إحدى الطرق التي تُبسِّط فيها Ansible إدارة الخواديم، فيُمكِن إحضار أي خادوم يمتلك منفذ SSH مُعرَّض تحت مظلّة إعدادات Ansible بغض النظر عن الطور الذي يتواجد فيه ضمن دورة حياته. أي حاسوب نستطيع إدارته عبر SSH نستطيع أيضًا إدارته عبر Ansible. تتخذ Ansible نهج الوحدات modules ممّا يجعل من السهل تمديدها كي تستخدم وظائف من النظام الأساسي للتعامل مع حالات محدّدة، يُمكِن كتابة الوحدات باستخدام أيّة لغة وهي تتخاطب بواسطة JSON المعياريّة. إنّ ملفّات الإعدادات مكتوبة بشكل رئيسي بصيغة تسلسل البيانات YAML نظرًا لطبيعتها التعبيرية وتشابهها مع لغات الرقم markup الشائعة، تتمكن Ansible من التفاعل مع العملاء إمّا من خلال أداة سطر الأوامر أو عبر scripts للإعدادات تُدعى Playbooks. تثبيت Ansible على Ubuntuللبدء باستكشاف Ansible كوسيلة لإدارة خواديمنا المختلفة نحتاج إلى تثبيت برمجيّة Ansible على جهاز واحد على الأقل، سنستخدم خادوم Ubuntu من أجل هذا القسم. إنّ أفضل طريقة للحصول على Ansible في Ubuntu هي إضافة PPA المشروع (أرشيف الحِزَم الشخصية personal package archive) إلى نظامنا. للقيام بذلك على نحو فعال نحتاج لتثبيت الحزمة python-software-properties والتي ستعطينا القدرة على العمل مع PPA بسهولة: sudo apt-get update sudo apt-get install python-software-propertiesبعد أن يتم تثبيت الحزمة نستطيع إضافة Ansible PPA بكتابة الأمر التالي: sudo add-apt-repository ppa:rquillo/ansible نضغط ENTER لقبول إضافة الـ PPA. نحتاج بعدها لتحديث دليل حِزَم نظامنا بحيث يكون على دراية بالحِزَم المتوفرة في PPA، نستطيع بعدها تثبيت برمجيّة Ansible: sudo apt-get update sudo apt-get install ansible نمتلك الآن كافّة البرمجيّات المطلوبة لإدارة خواديمنا من خلال Ansible. إعداد مفاتيح SSHتتخاطب Ansible بالدرجة الأولى كما أشرنا سابقًا مع حواسيب العملاء عبر SSH، وعلى الرغم من أنّها تمتلك القدرة على التعامل مع استيثاق SSH authentication مُعتمِد على كلمة السر فتساعد مفاتيح SSH على إبقاء الأمور أبسط. بإمكاننا إعداد مفاتيح SSH بطريقتين مختلفتين اعتمادًا على إذا ما كنّا نمتلك مسبقًا المفتاح الذي نريد استخدامه. 1- إنشاء زوج مفاتيح SSH جديدإن لم تكن تمتلك مسبقًا زوج مفاتيح SSH ترغب في استخدامه من أجل إدارة Ansible فبإمكانك إنشاء واحد الآن على خادوم Ansible. سنقوم بإنشاء زوج مفاتيح SSH على خادوم Ansible من أجل استيثاقه مع المضيفين الذين يديرهم. نقوم بإنشاء زوج مفاتيح RSA key-pair بكتابة ما يلي عن طريق المستخدم الذي نتحكّم بـ Ansible من خلاله: ssh-keygen سيتم سؤالنا عن تحديد موقع الملف لزوج المفاتيح التي تم إنشاؤها، عبارة سر passphrase، وتأكيد عبارة السّر، نضغط Enter في جميع هذه المراحل لقبول القيم الافتراضيّة. ستكون المفاتيح الجديدة متاحة في دليل ~/.ssh الخاص بالمستخدم، يُدعى المفتاح العام (والذي يمكننا مشاركته) بـ id_rsa.pub، يُدعى المفتاح الخاص (والذي نبقيه بأمان) بـ id_rsa. نستطيع إضافتها إلى لوحة تحكّم DigitalOcean على سبيل المثال (إن كنت على Digital Ocean) للسماح لنا بتضمين مفتاح SSH الخاص بنا في الخواديم الجديدة التي أنشأناها، سيسمح هذا لخادوم Ansible بالدخول إلى الخواديم الجديدة عبر SSH فورًا بدون الحاجة لأي استيثاق آخر. لفعل هذا نضغط على الرابط “SSH Keys” الموجود في قائمة التصفح على اليسار، نضغط في الشاشة الجديدة على زر “Add SSH Key” الموجود في الزاوية العلوية اليمنى: ندخل الاسم الذي نريد ربطه مع هذا المفتاح في الحقل العلوي، ونكتب على خادوم Ansible ما يلي للحصول على محتويات مفتاحنا العام: cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzmGgsqjSFuOBbjZB1sgquKpp3Ty+FgqoLrzjKbbk9VGOH6kM37aAhyxxmTQfe69lhYi/WCai+mrXOyY9IiQbUfZ4jsfPE9DS3zHhmnGiBWA7pedCTJ/Nhf06dmhAJIbExW3uDghbPbzbSA5Ihn1x0F5FXtSMDoFtyjcwUwJxc2z/kk9TKcFSl8qqf4IYBYE7c+EKaYRBjjDP4AQmiwjTPuipsmub7C0OGF0dTMatIa0lok6rwy91nmhCQV6polG0+Fsk4YrY8Yh5xz6wE0lOvc8BwP9nL0zsnw6Ey0MHV9BbMqtyD6x/fCurpIkMHJK4nv79rToSWA0AwoP/bJXh7 demo@ansible0 السلسلة النصية التي تعود لنا هي التي نحتاج لصقها في الحقل الثاني في لوحة تحكّم DigitalOcean: نضغط على “Create SSH Key” لإضافة مفتاحنا إلى لوحة التحكم، نستطيع الآن تضمين مفتاح SSH العام إلى الخواديم الجديدة التي نضيفها مما يسمح لنا بالتواصل مع خادوم Ansible، نحتاج فقط إلى اختيار المفتاح في القسم “Add optional SSH Keys” من عملية إنشاء خادوم جديد: 2- نقل زوج مفاتيح SSH موجود إلى Ansibleإن كنت تمتلك مسبقًا زوج مفاتيح SSH تريد استخدامه من أجل الاستيثاق مع خواديمك فبإمكانك نقل الإعتمادات credentials إلى خادوم Ansible الجديد بدلًا من إنشاء زوج جديد، يمتلك هذا ميّزة بأن يجعلها تعمل تلقائيًّا مع أي خواديم قمت بإعدادها مسبقًا لتستخدم هذا المفتاح. وعلى الحاسوب الآخر حيث قمنا بإعداد استيثاق مفتاح SSH من أجل الخواديم نحصل على المفتاح العام بكتابة ما يلي: cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzmGgsqjSFuOBbjZB1sgquKpp3Ty+FgqoLrzjKbbk9VGOH6kM37aAhyxxmTQfe69lhYi/WCai+mrXOyY9IiQbUfZ4jsfPE9DS3zHhmnGiBWA7pedCTJ/Nhf06dmhAJIbExW3uDghbPbzbSA5Ihn1x0F5FXtSMDoFtyjcwUwJxc2z/kk9TKcFSl8qqf4IYBYE7c+EKaYRBjjDP4AQmiwjTPuipsmub7C0OGF0dTMatIa0lok6rwy91nmhCQV6polG0+Fsk4YrY8Yh5xz6wE0lOvc8BwP9nL0zsnw6Ey0MHV9BbMqtyD6x/fCurpIkMHJK4nv79rToSWA0AwoP/bJXh7 demo@ansible0نحتاج على خادوم Ansible إلى إنشاء دليل مخفي لتخزين المفاتيح، نقوم بتسميته .ssh كي يعلم برنامج SSH أين يجده: mkdir ~/.ssh نقوم بقفل النفاذ إلى هذا الدليل لكي نتمكن نحن فقط من دخوله أو الكتابة إليه: chmod 700 ~/.ssh ننتقل الآن إلى الدليل ونفتح ملفًّا يُدعى id_rsa.pub باستخدام محرّر النصوص: cd ~/.ssh nano id_rsa.pubنلصق خَرْج مفتاحنا العام من حاسوبنا الرئيسي إلى هذا الملف: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzmGgsqjSFuOBbjZB1sgquKpp3Ty+FgqoLrzjKbbk9VGOH6kM37aAhyxxmTQfe69lhYi/WCai+mrXOyY9IiQbUfZ4jsfPE9DS3zHhmnGiBWA7pedCTJ/Nhf06dmhAJIbExW3uDghbPbzbSA5Ihn1x0F5FXtSMDoFtyjcwUwJxc2z/kk9TKcFSl8qqf4IYBYE7c+EKaYRBjjDP4AQmiwjTPuipsmub7C0OGF0dTMatIa0lok6rwy91nmhCQV6polG0+Fsk4YrY8Yh5xz6wE0lOvc8BwP9nL0zsnw6Ey0MHV9BbMqtyD6x/fCurpIkMHJK4nv79rToSWA0AwoP/bJXh7 demo@ansible0 نقوم بحفظ وإغلاق الملف، ونتحقّق من امتلاكه للأذونات الصحيحة بكتابة: chmod 644 id_rsa.pub الآن وبالعودة إلى حاسوبنا المحلّي المضبوط من أجل نفاذ مفاتيح SSH نكتب: cat ~/.ssh/id_rsa -----BEGIN RSA PRIVATE KEY----- MIIEpgIBAAKCAQEA85hoLKo0hbjgW42QdbIKriqad08vhYKqC684ym25PVRjh+pD N+2gIcl8Zk0H3uvZYWIv1gmsfpq1zsmPSIkG1H2eI7HzxPQ0qMx4ZpxogVgO6XnQ kyfzYX9OnZoQCSGxMVt7g4IWz2820gOSIZ9cdBeRV7UjA6Bbco3MFMCcXNs/5JPU ynBUpfKqn+CGAWBO3PhCmmEQY4wz+AEJosI0z7oqbJrm/AtDhhdHUzGrSGtJaJOq . . . . . . cqsqOEzXAoGBAPMJJ8RrKUBuSjVNkzebst9sBgNadmaoQUoMHUDr8KpCZhWAoHB7 1VKmq7VSphQSruI31qy2M88Uue1knC/nQr1bE1DITZgezETSsDqsAMBo8bqDN6TT qVJgG+TS9BRC+IowuzMVV5mzrfJjkrb+GG+xWSXrTLZMbeeTf+D0SfVo -----END RSA PRIVATE KEY----- سيكون الخَرْج طويلًا جدًّا. نعود الآن إلى خادوم Ansible، نحتاج إلى إنشاء ملف جديد في الدليل ~/.ssh: nano id_rsa نقوم بداخله بلصق نتائج الأمر السابق على حاسوبنا المحلّي: -----BEGIN RSA PRIVATE KEY----- MIIEpgIBAAKCAQEA85hoLKo0hbjgW42QdbIKriqad08vhYKqC684ym25PVRjh+pD N+2gIcl8Zk0H3uvZYWIv1gmsfpq1zsmPSIkG1H2eI7HzxPQ0qMx4ZpxogVgO6XnQ kyfzYX9OnZoQCSGxMVt7g4IWz2820gOSIZ9cdBeRV7UjA6Bbco3MFMCcXNs/5JPU ynBUpfKqn+CGAWBO3PhCmmEQY4wz+AEJosI0z7oqbJrm/AtDhhdHUzGrSGtJaJOq . . . . . . cqsqOEzXAoGBAPMJJ8RrKUBuSjVNkzebst9sBgNadmaoQUoMHUDr8KpCZhWAoHB7 1VKmq7VSphQSruI31qy2M88Uue1knC/nQr1bE1DITZgezETSsDqsAMBo8bqDN6TT qVJgG+TS9BRC+IowuzMVV5mzrfJjkrb+GG+xWSXrTLZMbeeTf+D0SfVo -----END RSA PRIVATE KEY----- نتأكّد من تضمين أسطر التحديد الموجودة في البداية والنهاية، فهي مطلوبة لكي يكون ملف المفتاح صالحًا، نحفظ الملف ونغلقه. نحتاج لتغيير الأذونات لإبقاء هذا الملف بأمان: chmod 600 id_rsa ستكون Ansible عند هذه النقطة قادرة على استخدام مفاتيح SSH هذه من أجل التواصل مع أي خادوم يمتلك المفتاح مُضمَّنًا عليه. إعداد مضيفي Ansibleتقوم Ansible بتتبّع جميع الخواديم التي يعلم عنها عن طريق ملف المضيفين “hosts”، نحتاج إلى إعداد هذا الملف أوّلًا قبل أن نتمكّن من بدء التواصل مع حواسيبنا الأخرى. نفتح الملف مع صلاحيّات جذريّة root كما يلي: sudo nano /etc/ansible/hosts سنرى ملفًّا يمتلك الكثير من أمثلة الإعدادات، وسيعمل أيّ منها لدينا فعليًّا، لذلك من أجل البدء نقوم بتعليق كافّة أسطر هذا الملف بإضافة “#” قبل كل سطر. سنبقي هذه الأمثلة في هذا الملف لتساعدنا في الإعداد إن أردنا تنفيذ حالات أكثر تعقيدًا في المستقبل. بعد أن يتم تعليق كافّة الأسطر نستطيع البدء بإضافة المضيفين الفعليين لدينا. يكون ملف المضيفين مرنًا إلى حدٍّ ما ويمكن إعداده بعدّة طرق مختلفة، تبدو الصياغة التي سنستخدمها كما يلي: [group_name] alias ansible_ssh_host=server_ip_address إنّ group_name هو وسم تنظيمي يسمح لنا بالإشارة لأي من الخواديم المدرجة بكلمة واحدة، الكنية هي مجرّد اسم للإشارة إلى ذلك الخادوم. لذا نتخيل في حالتنا أننا نمتلك ثلاثة خواديم نريد إعدادها مع Ansible، تكون هذه الخواديم قابلة للوصول من خلال خادوم Ansible بكتابة: ssh root@server_ip_address لن يتم سؤالنا عن كلمة سر إن أعددنا هذا بشكل صحيح، سنفترض أنّ عناوين IP لخواديمنا هي 192.0.2.1، 192.0.2.2، و192.0.2.3، سنقوم بإعداد هذا بحيث نستطيع الإشارة إليها بشكل مفرد كـ host1، host2، وhost3، أو كمجموعة باسم servers. هذه هي الكتلة التي ينبغي إضافتها إلى ملف المضيفين من أجل تحقيق هذا: [servers] host1 ansible_ssh_host=192.0.2.1 host2 ansible_ssh_host=192.0.2.2 host3 ansible_ssh_host=192.0.2.3 يمكن للمضيفين أن يكونوا ضمن مجموعات متعدّدة، وتستطيع المجموعات إعداد مُعامِلات parameters من أجل كل أعضائها، فلنجرّب هذا الآن. إن حاولنا مع إعداداتنا الحاليّة الاتصال بأي من المضيفين عن طريق Ansible فسيفشل الأمر (بافتراض أنّك لا تعمل عن طريق المستخدم الجذري root)، يحدث هذا لأنّه تم تضمين مفاتيح SSH من أجل المستخدم الجذري على الأنظمة البعيدة وستحاول Ansible الاتصال بشكل افتراضي بواسطة المستخدم الحالي، ستعطينا محاولة الاتصال هذا الخطأ: host1 | FAILED => SSH encountered an unknown error during the connection. We recommend you re-run the command using -vvvv, which will enable SSH debugging output to help diagnose the issue نستخدم على خادوم Ansible مستخدمًا يُدعى demo، ستحاول Ansible الاتصال إلى كل مضيف باستخدام ssh demo@server، لن يعمل هذا إن كان المستخدم demo غير موجود على النظام البعيد. نستطيع إنشاء ملف يُخبِر جميع الخواديم في المجموعة servers بالاتصال عن طريق المستخدم الجذري root. لفعل هذا نقوم بإنشاء دليل في بنية إعدادات Ansible يُدعى group_vars، ونستطيع ضمن هذا المجلّد إنشاء ملفّات مُنسّقة عن طريق YAML لكل مجموعة نريد إعدادها: sudo mkdir /etc/ansible/group_vars sudo nano /etc/ansible/group_vars/serversبإمكاننا وضع إعداداتنا هنا، تبدأ ملفّات YAML بـ “—” لذا تأكّد ألّا تنسى ذلك الجزء: --- ansible_ssh_user: rootنحفظ الملف ونغلقه عند الانتهاء. إن أردنا تحديد تفاصيل الإعدادات لكل خادوم بغض النظر عن مجموعته المرتبط بها فبإمكاننا وضع هذه التفاصيل في ملف في المسار /etc/ansible/group_vars/all، يمكن إعداد المضيفين بشكل مفرد بواسطة إنشاء ملفّات في دليل في المسار /etc/ansible/host_vars. استخدام أوامر Ansible بسيطةالآن بعد أن قمنا بإعداد المضيفين وضبطنا تفاصيل الإعدادات بشكلٍ كافٍ للسماح لنا بالاتصال بنجاح إلى مضيفينا، فبإمكاننا تجربة الأمر الأول لنا. نقوم بعمل ping لكل الخواديم التي أعددناها عن طريق كتابة: ansible -m ping allhost1 | success >> { "changed": false, "ping": "pong" } host3 | success >> { "changed": false, "ping": "pong" } host2 | success >> { "changed": false, "ping": "pong" } وهو اختبار بسيط للتأكّد من امتلاك Ansible لاتصال مع كافّة مضيفيه. تعني “all” كافّة المضيفين، وكان بإمكاننا بسهولة تحديد مجموعة كما يلي: ansible -m ping serversنستطيع أيضًا تحديد مضيف بشكل فردي: ansible -m ping host1بإمكاننا تحديد عدّة مضيفين بفصلهم بواسطة نقطتين: ansible -m ping host1:host2المقطع -m ping من الأمر هو تعليمة لـ Ansible كي تستخدم الوحدة “ping”، وهي بشكل مبسّط عبارة عن أوامر نستطيع تنفيذها على مضيفينا عن بُعد، تعمل الوحدة “ping” بعدّة طرق مثل أداة ping العاديّة في Linux، ولكن تقوم بدلًا من ذلك بالتحقّق من أجل اتصال Ansible. لا تأخذ الوحدة ping فعليًّا أيّة مُعطيات arguments، ولكن بإمكاننا تجربة أمر آخر لنرى كيفيّة عمل ذلك، نقوم بتمرير المعطيات إلى script بكتابة –a. تسمح لنا وحدة الصدفة “shell” بإرسال أمر طرفيّة terminal إلى المضيف البعيد واستعادة النتائج، على سبيل المثال لإيجاد استخدام الذاكرة على جهاز مضيفنا host1 نستطيع استخدام: ansible -m shell -a 'free -m' host1 host1 | success | rc=0 >> total used free shared buffers cached Mem: 3954 227 3726 0 14 93 -/+ buffers/cache: 119 3834 Swap: 0 0 0 الخاتمةينبغي أن تمتلك الآن خادوم Ansible مضبوطًا للتواصل مع الخواديم التي ترغب بالتحكم بها، تحقّقنا قدرة Ansible على التواصل مع كل مضيف واستخدمنا الأمر ansible لتنفيذ مهام بسيطة عن بُعد. وعلى الرغم من أنّ هذا مفيد لنا، لم نقم بتغطية أقوى ميّزة في Ansible في هذا الدّرس وهي الـ Playbooks، لقد قمنا بإعداد أساس رائع من أجل العمل مع خواديمنا من خلال Ansible، ولكن الجزء الأكبر سيتم الحديث عنه في درس لاحق عند تغطية كيفيّة استخدام الـ Playbooks لأتمتة الإعدادات لحواسيبنا عن بُعد. ترجمة -وبتصرّف- لـ How to Install and Configure Ansible on an Ubuntu 12.04 VPS لصاحبه Justin Ellingwood.
  15. من التحديات الشائعة التي نصادفها عند التعامل مع أنظمة قواعد البيانات النشطة active هو القيام بنسخ احتياطيّة ساخنة hot backups، وهو إنشاء نسخ احتياطيّة بدون إيقاف خدمة قاعدة البيانات أو جعلها قابلة للقراءة فقط، ينتج عادة عن نسخ ملفّات قاعدة البيانات النشطة ببساطة نسخة من قاعدة البيانات غير مستقرّة داخليًّا، أي تكون غير قابلة للاستخدام أو فاقدة لبعض المعاملات transactions التي حدثت خلال هذا النسخ، من ناحية أخرى فإنّ إيقاف قاعدة البيانات من أجل النسخ الاحتياطي المُجدوَل يجعل الأجزاء المعتمدة على قاعدة البيانات من تطبيقنا غير متوفّرة. Percona XtraBackup هو أداة مفتوحة المصدر تُستَخدم للالتفاف على هذه المشكلة وإنشاء نُسَخ احتياطيّة كاملة full backups أو تزايديّة incremental backups لقواعد بيانات قيد التشغيل من نوع MySQL، MariaDB، و Percona Server، وهي معروفة أيضًا باسم النُسَخ الاحتياطيّة الساخنة hot backups. وعلى النقيض من النُّسَخ الاحتياطيّة المنطقيّة logical backups التي تنتجها أدوات مثل mysqldump، تقوم أداة XtraBackup بإنشاء نُسَخ احتياطيّة ملموسة physical backups لملفّات قواعد البيانات، أي تقوم بعمل نسخة لملفّات البيانات، وتطبّق بعدها سجل المعاملات (transaction log (a.k.a. redo log على النُّسخ الاحتياطيّة الملموسة لتُعيد ملء أي مُعاملات نشطة لم تكتمل خلال إنشاء النُّسَخ الاحتياطيّة، مما يُؤدّي إلى نُسَخ احتياطيّة مستقرّة لقاعدة بيانات قيد التشغيل، يُمكِن بعدها النسخ الاحتياطي لنسخة قاعدة البيانات الاحتياطيّة إلى موقع بعيد remote location باستخدام rsync أو نظام نسخ احتياطي مثل Bacula. سنتعلّم في هذا الدّرس كيفيّة القيام بنسخة احتياطيّة كاملة وساخنة لقواعد بيانات MySQL أو MariaDB باستخدام Percona XtraBackup على Ubuntu، تمّت أيضًا تغطية عمليّة استعادة قاعدة البيانات من نسخة احتياطيّة. المتطلبات الأساسيةيجب أن تمتلك ما يلي من أجل متابعة هذا الدّرس: صلاحيّات مستخدم جذر Superuser على نظام Ubuntuقاعدة بيانات MySQL أو MariaDB قيد التشغيلالنفاذ إلى المستخدم المُدير (admin (root لقاعدة بياناتكومن أجل القيام بنسخة احتياطيّة ساخنة لقاعدة بياناتك يجب أيضًا أن تستخدم مُحرِّك التخزين InnoDB لأنّ XtraBackup تعتمد على سجل معاملات يُحافِظ عليه InnoDB، إن كانت قواعد بياناتك تستخدم مُحرِّك التخزين MyISAM فلا يزال بإمكانك استخدام XtraBackup ولكن سيتم قفل قاعدة البيانات لفترة قصيرة من الوقت في أواخر عمليّة النسخ الاحتياطي. 1- التحقق من محرك التخزينإن لم تكن متأكدًا من مُحرِّك التخزين الذي تستخدمه قاعدة بياناتك فتستطيع معرفته بعدّة طرق، إحدى الطرق هي استخدام وحدة التحكّم console في MySQL لاختيار قاعدة البيانات المطلوبة ومن ثمّ الحصول على حالة كل جدول فيها. ندخل في البداية إلى وحدة التحكّم console في MySQL: mysql -u root -pنقوم بإدخال كلمة سر المستخدم الجذري root في MySQL. وفي مُحث MySQL prompt نختار قاعدة البيانات التي نريد التحقّق منها، تأكد من أن تضع اسم قاعدة بياناتك هنا بدلًا من database_name: mysql> USE database_name;نطبع بعدها حالات جدولها: mysql> SHOW TABLE STATUS\G;ينبغي الإشارة للمحرك لكل صف من قاعدة البيانات: ... *************************** 11. row *************************** Name: wp_users Engine: InnoDB ...نغادر وحدة التحكّم console حالما ننتهي من هذا. mysql> exitفلنقم بتثبيت Percona XtraBackup. تثبيت Percona XtraBackupأسهل طريقة لتثبيت Percona XtraBackup هي استخدام apt-get. نضيف مفتاح مستودع Percona باستخدام هذا الأمر: sudo apt-key adv --keyserver keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2Aنضيف بعدها مستودع Percona إلى مصادر apt لدينا: sudo sh -c "echo 'deb http://repo.percona.com/apt trusty main' > /etc/apt/sources.list.d/percona.list" sudo sh -c "echo 'deb-src http://repo.percona.com/apt trusty main' >> /etc/apt/sources.list.d/percona.list"نقوم بتنفيذ الأمر التالي لتحديث مصادر apt: sudo apt-get updateنستطيع أخيرًا تنفيذ الأمر التالي لتثبيت XtraBackup: sudo apt-get install percona-xtrabackupتتألف XtraBackup بشكل أساسي من برنامج XtraBackup و script مكتوب بلغة Perl يُدعى innobackupex سنستخدمه لإنشاء نُسَخ احتياطيّة لقواعد بياناتنا. التحضيرات لأول مرةنحتاج قبل استخدام XtraBackup لأوّل مرّة إلى تحضير النظام ومستخدم MySQL الذي سيستخدمه XtraBackup، يُغطّي هذا القسم التحضيرات الأوليّة. 1- مستخدم النظامإذا لم نكن نخطّط لاستخدام المستخدم الجذري root للنظام فيجب علينا القيام ببعض التحضيرات الأساسيّة للتأكد من أنّه يُمكن تنفيذ XtraBackup بشكل صحيح، سنفترض أنّك قمت بتسجيل الدخول باستخدام المستخدم الذي سيشغّل XtraBackup وأنّه يمتلك صلاحيّات مستخدم جذر superuser. نضيف مستخدم النظام إلى المجموعة "mysql" (ضع اسم المستخدم لديك بدلًا من username): sudo gpasswd -a username mysqlنقوم بإنشاء الدليل الذي سنستخدمه لتخزين النُّسَخ الاحتياطيّة التي يقوم XtraBackup بعملها: sudo mkdir -p /data/backups sudo chown -R username: /dataيتأكّد الأمر chown من قدرة المستخدم على الكتابة إلى دليل النُّسَخ الاحتياطيّة. 2- مستخدم MySQLيحتاج XtraBackup إلى مستخدم MySQL لكي يستخدمه لإنشاء النُّسَخ الاحتياطيّة، فلنقم بإنشاء واحد الآن. ندخل إلى وحدة التحكّم console في MySQL بهذا الأمر: mysql -u root -pنقوم بإدخال كلمة سر المستخدم الجذري root في MySQL. نُنشِئ في مُحِث MySQL prompt مستخدم MySQL جديد ونعيّن كلمة سر له، يُدعى المستخدم في هذا المثال "bkpuser" وكلمة السّر هي "bkppassword"، قم بتغييرهما إلى شيء أكثر أمانًا: mysql> CREATE USER 'bkpuser'@'localhost' IDENTIFIED BY 'bkppassword'نقوم بعدها بمنح grant مستخدم MySQL الجديد صلاحيّات إعادة التحميل reload، القفل lock، والتكرار replication لكافّة قواعد البيانات: mysql> GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'bkpuser'@'localhost'; FLUSH PRIVILEGES; وهي الحد الأدنى من الصلاحيّات التي يحتاجها XtraBackup لإنشاء نُسَخ احتياطيّة كاملة لقواعد البيانات. عند الانتهاء نقوم بالخروج من لوحة تحكّم MySQL console: mysql> exitنحن الآن جاهزون لإنشاء نسخة احتياطيّة كاملة لقواعد بياناتنا. القيام بنسخة احتياطية ساخنة كاملةيُغطّي هذا القسم الخطوات الضرورية لإنشاء نسخة احتياطيّة ساخنة كاملة لقاعدة بيانات MySQL باستخدام XtraBackup، بعد التأكّد من أنّ أذونات permissions ملفّات قاعدة البيانات صحيحة سنستخدم XtraBackup لإنشاء create النسخة الاحتياطيّة وتحضيرها prepare. 1- تحديث أذونات Datadirيتم تخزين ملفّات قاعدة بيانات MySQL على Ubuntu في المسار var/lib/mysql/، وهو الذي يتم الإشارة إليه أحيانًا بـ datadir، يتم تقييد النفاذ إلى datadir افتراضيًّا فقط للمستخدم mysql، يتطلّب XtraBackup نفاذًا إلى هذا الدّليل لإنشاء نسخه الاحتياطيّة، لذا نقوم بتنفيذ بعض الأوامر للتأكّد من امتلاك مستخدم النظام الذي أعددناه سابقًا-كعضو في المجموعة mysql- للأذونات المناسبة: sudo chown -R mysql: /var/lib/mysql sudo find /var/lib/mysql -type d -exec chmod 770 "{}" \;تضمن هذه الأوامر أنّ كافّة الأدّلة في datadir قابلة للنفاذ من قبل المجموعة mysql، ويجب تنفيذها قبل كل نسخة احتياطيّة. 2- إنشاء نسخة احتياطيةنحن الآن على استعداد لإنشاء النسخة الاحتياطيّة، نستخدم الأداة innobackupex أثناء تشغيل قاعدة بيانات MySQL لفعل هذا، قم بتنفيذ هذا الأمر بعد وضع اسم مستخدمك وكلمة سرك لتتوافق مع معلومات تسجيل دخول مستخدم MySQL لديك: innobackupex --user=bkpuser --password=bkppassword --no-timestamp /data/backups/new_backupسيقوم هذا بإنشاء نسخة احتياطيّة لقاعدة البيانات في الموقع المُحدّد data/backups/new_backup/: innobackupex output innobackupex: Backup created in directory '/data/backups/new_backup' 150420 13:50:10 innobackupex: Connection to database server closed 150420 13:50:10 innobackupex: completed OK!وبشكل بديل تستطيع إزالة no-timestamp-- لكي يقوم XtraBackup بإنشاء دليل النسخة الاحتياطيّة بناءً على الختم الزمني timestamp الحالي كما يلي: innobackupex --user=bkpuser --password=bkppassword /data/backupsسيقوم هذا بإنشاء نسخة احتياطيّة لقاعدة البيانات في دليل فرعي مُولَّد تلقائيًّا كما يلي: innobackupex output — no timestamp innobackupex: Backup created in directory '/data/backups/2015-04-20_13-50-07' 150420 13:50:10 innobackupex: Connection to database server closed 150420 13:50:10 innobackupex: completed OK!ستعيد أي طريقة نستخدمها العبارة "innobackupex: completed OK" في السّطر الأخير من الخَرْج، ينتج عن النّسخة الاحتياطيّة الناجحة نسخة من قاعدة البيانات في المسار datadir والتي يجب تحضيرها قبل استخدامها. تحضير النسخة الاحتياطيةالخطوة الأخيرة في إنشاء نسخة احتياطيّة ساخنة باستخدام XtraBackup هي تحضيرها، ويتضمّن هذا إعادة "replaying" سجل المعاملات لتطبيق أي معاملة غير مرتبطة بالنسخة الاحتياطيّة، يجعل التحضير بيانات النسخة الاحتياطيّة مستقرة وقابلة للاستخدام من أجل الاستعادة. سنحضّر بحسب مثالنا النسخة الاحتياطيّة التي أنشأناها في المسار data/backups/new_backup/، ضع المسار الفعلي للنسخة الاحتياطيّة لديك: innobackupex --apply-log /data/backups/new_backupيجب أن نرى مرّة أخرى العبارة "innobackupex: completed OK" في السطر الأخير من الخَرْج. تمّ إنشاء النسخة الاحتياطيّة لقاعدة البيانات وهي جاهزة لاستعادتها إلى قاعدة بياناتنا، إن كنت تملك نظام نسخ احتياطي للملفّات مثل Bacula فيجب تضمين هذه النسخة الاحتياطيّة لقاعدة البيانات كجزء من اختيار النسخة الاحتياطيّة. يُغطّي القسم التالي كيفيّة استعادة قاعدة البيانات من النسخة الاحتياطيّة التي أنشأناها للتو. القيام باستعادة النسخة الاحتياطيةتتطلّب استعادة قاعدة البيانات باستخدام XtraBackup إيقاف قاعدة البيانات وأن يكون المسار datadir فارغًا. نوقف خدمة MySQL باستخدام هذا الأمر: sudo service mysql stopننقل أو نحذف محتويات datadir (وهو المسار var/lib/mysql/)، في حالتنا سننقله ببساطة إلى مكان مؤقّت: mkdir /tmp/mysql mv /var/lib/mysql/* /tmp/mysql/نستطيع الآن استعادة قاعدة البيانات من نسختنا الاحتياطيّة "new_backup": innobackupex --copy-back /data/backups/new_backupإن تم الأمر بنجاح فينبغي أن يكون السطر الأخير من الخَرْج هو العبارة "innobackupex: completed OK". تنتمي الملفّات التي تمّت استعادتها غالبًا إلى المستخدم الذي قام بتنفيذ عمليّة الاستعادة، نُعيد الملكيّة إلى mysql لكي تستطيع MySQL قراءة وكتابة الملفّات: sudo chown -R mysql: /var/lib/mysqlأصبحنا مستعدين لبدء MySQL: sudo service mysql startهذا هو كل شيء، يجب أن تكون قاعدة بيانات MySQL التي استعدناها قيد التشغيل الآن. الخاتمةبعد أن أصبحت الآن قادرًا على إنشاء نُسَخ احتياطيّة ساخنة لقاعدة بيانات MySQL باستخدام Percona XtraBackup فهنالك العديد من الأشياء التي يجب أن تنظر إلى إعدادها. يُنصَح أولًا بأتمتة العمليّة بحيث يتم إنشاء النُّسَخ الاحتياطيّة وفق جدول، يجب عليك ثانيًا القيام بنسخ بعيد remote للنسخ الاحتياطيّة في حال حدثت مشاكل في خادوم قاعدة البيانات باستخدام أدوات مثل rsync أو نظام نُسَخ احتياطيّة للملفّات على الشبكة مثل Bacula، سترغب بعدها في النظر في مداورة rotating النسخ الاحتياطيّة لديك (أي حذف النسخ الاحتياطيّة القديمة على أساس مُجدوَل) وإنشاء نُسَخ احتياطيّة تزايديّة (باستخدام XtraBackup) لتوفير مساحة القرص. ترجمة -وبتصرّف- لـ How To Create Hot Backups of MySQL Databases with Percona XtraBackup on Ubuntu 14.04 لصاحبه Mitchell Anicas.
  16. إنّ عامل الاستيثاق authentication factor هو جزء من المعلومات يُستخدَم لإثبات أنّه لدينا الحق لتنفيذ إجراء ما، مثل تسجيل الدخول إلى النّظام، وقناة الاستيثاق authentication channel هي الطّريقة التي يُوصِل بها نظام الاستيثاق عاملًا factor للمستخدم أو الطّريقة التي يطلب بها من المستخدم الرّد، من الأمثلة على عوامل الاستيثاق نجد كلمات السّر ورموز الأمان security tokens، ومن الأمثلة على قنوات الاستيثاق نجد الحواسيب والهواتف المحمولة. تستخدم SSH افتراضيًّا كلمات السّر من أجل الاستيثاق، وتُوصي تعليمات SSH باستخدام مفتاح SSH key بدلًا من ذلك، على أيّة حال يبقى هذا عاملًا واحدًا فقط، فإن تمّ تهديد الحاسوب لدينا من قبل شخص ما، فبإمكانه استخدام مفتاحنا لتهديد خواديمنا أيضًا. لمكافحة هذا سنقوم في هذا الدّرس بإعداد استيثاق مُتعدِّد العوامل (Multi-factor authentication (MFA، والذي يتطلّب أكثر من عامل من أجل الاستيثاق أو تسجيل الدّخول، وهذا يعني أنّه يجب على المُخترِق أن يُهدِّد عدّة أشياء، مثل حاسوبنا وهاتفنا المحمول معًا لكي يستطيع الدخول، يتم عادةً تلخيص أنواع العوامل المختلفة كما يلي: شيء نعرفه، مثل كلمة سر أو سؤال أمانشيء نملكه، مثل تطبيق استيثاق أو رمز أمان security tokenشيء نكون نحن عليه، مثل بصمة الأصابع أو الصوتمن العوامل الشائعة تطبيق OATH-TOTP مثل Google Authenticator، إنّ (OATH-TOTP (Open Authentication Time-Based One-Time Password الاستيثاق المفتوح لكلمة سر لمرّة واحد مُعتمِدة على الزمن هو عبارة عن ميثاق protocol مفتوح يقوم بتوليد كلمة سر صالحة للاستخدام لمرّة واحدة تكون عادةً عددًا من 6 أرقام يتم تجديده كل 30 ثانية. سيشرح هذا الدّرس كيفيّة تمكين استيثاق SSH باستخدام تطبيق OATH-TOTP بالإضافة لمفتاح SSH ، حيث سيتطلّب تسجيل الدخول إلى خادومنا عبر SSH عاملين اثنين عبر قناتين ممّا يجعله أكثر أمانًا من كلمة السّر أو مفتاح SSH لوحدهما. المتطلبات الأساسيةسنحتاج لمتابعة هذا الدّرس إلى: خادوم Ubuntu 14.04.مستخدم sudo غير جذري non-root مع إضافة مفتاح SSH، والذي نستطيع إعداده باتّباع درس الإعداد الابتدائي لخادوم أوبنتو 14.04.هاتف ذكي أو لوحي tablet مُثبَّت عليه تطبيق OATH-TOTP مثل Google Authenticator (روابط تنزيله من أجل Android و iOS).الخطوة الأولى – تثبيت libpam-google-authenticatorسنقوم في هذه الخطوة بتثبيت وإعداد PAM الخاصّة بـ Google. إنّ PAM، والتي ترمز إلى وحدة الاستيثاق القابلة للإضافة Pluggable Authentication Module، هي عبارة عن بنية تحتيّة للاستيثاق تُستَخدم على أنظمة لينِكس من أجل استيثاق المستخدمين، ولأنّ Google صنعت تطبيق OATH-TOTP فقد قامت أيضًا بإنشاء PAM تقوم بتوليد TOTPs ومتوافقة بشكل كامل مع أي تطبيق OATH-TOTP. نقوم في البداية بتحديث الذاكرة المؤقتة cache لمستودع Ubuntu: sudo apt-get updateنُثبِّت بعدها PAM: sudo apt-get install libpam-google-authenticatorوبعد تثبيت PAM سنستخدم تطبيق مُساعِد يتم تثبيته مع PAM لتوليد مفتاح TOTP للمستخدم الذي نرغب بإضافة عامل ثانٍ له، يتم توليد هذا المفتاح للمستخدم على أساس المستخدم وليس على أساس النّظام، ويعني هذا أنّ كل مستخدم يريد استعمال تطبيق استيثاق TOTP سيحتاج لتسجيل الدخول وتشغيل التطبيق المُساعِد للحصول على المفتاح الخاص به: google-authenticatorبعد تنفيذ الأمر سيتم سؤالنا عدّة أسئلة، يطلب السؤال الأول معرفة إذا ما كان يجب أن تكون رموز الاستيثاق authentication tokens على أساس زمني. يسمح PAM هذا برموز على أساس زمني time-based أو على أساس تتابعي sequential-based، يعني استخدام رموز على أساس تتابعي أنّ الشيفرة code تبدأ في نقطة مُعيّنة وبعدها تقوم بزيادة الشيفرة بعد كل استخدام، ويعني استخدام رموز على أساس زمني أنّ الشيفرة تتغير بشكل عشوائي بعد انقضاء وقت مُحدّد، سنختار الرموز على أساس زمني لأنّ هذا ما تتوقعه تطبيقات مثل Google Authenticator، لذا نجيبه بنعم: Do you want authentication tokens to be time-based (y/n) yبعد الإجابة على هذا السؤال سيتم تمرير الكثير من الخَرْج output، ومن ضمنه شيفرة QR كبيرة، تأكّد من تسجيلك للمفتاح السّري secret key، شيفرة التحقيق verification code، وشيفرات البداية في حالات الطوارئ emergency scratch codes في مكان آمن مثل مُدير كلمات السّر. عند هذه النقطة نستخدم تطبيق الاستيثاق authenticator الموجود على هاتفنا لمسح scan شيفرة QR أو نكتب يدويًّا المفتاح السّري، إن كانت شيفرة QR كبيرة جدًّا لمسحها نستطيع استخدام الرابط الموجود أعلاها للحصول على نسخة أصغر منها، حالما تتم إضافتها سنرى رمزًا مُكوَّنًا من 6 أرقام يتغيّر كل 30 ثانية في تطبيقنا. تقوم بقيّة الأسئلة بإعلام PAM كيف يعمل، سنمر عليها واحدًا تلو الآخر: Do you want me to update your "~/.google_authenticator" file (y/n) yيقوم هذا بشكل أساسي بكتابة المفتاح والخيارات إلى الملف google_authenticator.، إن قلنا "لا" سيخرج البرنامج ولن تتم كتابة أي شيء، والذي يعني أنّ تطبيق الاستيثاق authenticator لن يعمل. Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) yنمنع عندما نجيب على هذا السؤال بنعم هجمات الإعادة replay attack بأن نجعل كل رمز تنتهي صلاحيّته مباشرة بعد استخدامه، وهذا يمنع المُهاجِم من التقاط الرّمز الذي استخدمناه للتو وتسجيل الدخول به. By default, tokens are good for 30 seconds and in order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of 1:30min to about 4min. Do you want to do so (y/n) nتسمح إجابة نعم هنا بثمانية رموز صالحة خلال فترة 4 دقائق، وبإجابتنا "لا" نقوم بتحديدها إلى 3 رموز صالحة خلال فترة 1:30 دقيقة، إن لم تكن لديك مشكلة مع هذه الفترة فالإجابة "لا" هنا هي الخيارة الأكثر أمانًا. If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting (y/n) yيعني تحديد المُعدَّل Rate limiting أنّ المُهاجِم البعيد يستطيع فقط أن يحاول عدد مُحدَّد من التخمينات قبل أن يتم حظره، إن لم نقم مُسبقًا بإعداد تحديد المُعدَّل بشكل مباشر داخل SSH فإنّ فعل هذا هنا هو تقنية رائعة. الخطوة الثانية – إعداد OpenSSHإنّ الخطوة التالية الآن هي إعداد SSH لاستخدام مفتاح TOTP لدينا، سنحتاج أن نخبر SSH عن PAM ومن ثم نقوم بإعداد SSH لاستخدامه. نفتح أولًا ملف الإعدادات sshd لتحرير باستخدام nano أو مُحرِّر النصوص المُفضَّل لدينا: sudo nano /etc/pam.d/sshdنضيف السطر التالي إلى نهاية الملف: . . \# Standard Un*x password updating. @include common-password auth required pam_google_authenticator.so nullokتُخبِر الكلمة "nullok" الموجودة في النهاية PAM أنّ طريقة الاستيثاق هذه اختياريّة، فيسمح هذا للمستخدمين الذين لا يملكون مفتاح OATH-TOTP أن يظلّوا قادرين على تسجيل الدخول باستخدام مفتاح SSH الخاص بهم، أمّا إن كان جميع المستخدمين يملكون مفتاح OATH-TOTP فنستطيع حذف "nullok" من هذا السّطر لجعل الاستيثاق مُتعدِّد العوامل MFA إجباريًّا. نحفظ ونغلق الملف. نقوم بعدها بإعداد SSH ليدعم هذا النوع من الاستيثاق، نفتح ملف إعدادات SSH لتحريره: sudo nano /etc/ssh/sshd_configنبحث عن ChallengeResponseAuthentication ونعيّن قيمتها إلى yes: . . . \# Change to yes to enable challenge-response passwords (beware issues with \# some PAM modules and threads) ChallengeResponseAuthentication yes . . .نحفظ ونغلق الملف، ونعيد تشغيل SSH لإعادة تحميل ملفّات الإعدادات: sudo service ssh restartالخطوة الثالثة – جعل SSH على علم بالاستيثاق مُتعدد العوامل MFAسنختبر في هذه الخطوة إذا ما كان مفتاح SSH يعمل. نفتح أولًا طرفيّة terminal أخرى ونحاول الدخول عبر SSH إلى الخادوم، سنلاحظ أنّنا سجلّنا الدخول إلى هذه الجلسة الثانية باستخدام مفتاح SSH الخاص بنا بدون إدخال شيفرة التحقيق أو كلمة السّر، حدث هذا لأنّ مفتاح SSH يقوم بشكل افتراضي بتجاوز جميع خيارات الاستيثاق الأخرى، نحتاج أن نُخبِر SSH أن يستخدم شيفرة TOTP ومفتاح SSH بدلًا من كلمة السر. نفتح الآن ملف الإعدادات sshd مرّة أخرى: sudo nano /etc/ssh/sshd_configنبحث عن السطر PasswordAuthentication ونزيل التعليق عنه بحذف الحرف # في بداية السّطر ونقوم بتحديث قيمته إلى no، يُخبِر هذا SSH ألّا يقوم بالسؤال عن كلمة السّر. . . . \# Change to no to disable tunnelled clear text passwords PasswordAuthentication no . . .نضيف بعد ذلك السطر التالي إلى أسفل الملف، والذي يُخبِر SSH ما هي طرق الاستيثاق المطلوبة: . . . UsePAM yes AuthenticationMethods publickey,keyboard-interactiveنحفظ ونغلق الملف. نفتح بعدها ملف إعدادات PAM sshd: sudo nano /etc/pam.d/sshdنقوم بإيجاد السطر include common-auth@ وجعله كتعليق بإضافة الحرف # كالحرف الأول في هذا السطر، يُخبِر هذا PAM ألّا تسأل عن كلمة السر، وقد قمنا سابقًا بإخبار SSH ألّا تفعل هذا في sshd_config: . . . # Standard Un*x authentication. #@include common-auth . . .نحفظ ونغلق الملف ومن ثم نعيد تشغيل SSH: sudo service ssh restartنحاول الآن تسجيل الدخول إلى الخادوم مرّة أخرى، ينبغي أن نرى أنّنا قمنا بالاستيثاق بشكل جزئي باستخدام مفتاح SSH الخاص بنا ومن ثمّ حصلنا على مُحِث prompt من أجل شيفرة التحقيق verification code، والذي سيبدو مشابهًا لما يلي: ssh sammy@your_server_ip Authenticated with partial success. Verification code:نُدخِل شيفرة التحقيق من تطبيق OAUTH-TOTP لدينا، وسيتم تسجيل دخولنا إلى الخادوم، نمتلك الآن الاستيثاق مُتعدِّد العوامل MFA مُمكَّنًا من أجل SSH. الخاتمةوكما يحدث مع أي نظام نقوم بتمنيعه وتأمينه سنصبح مسؤولين عن إدارة هذا الأمان، ويعني هذا في هذه الحالة عدم فقدان مفتاح SSH الخاص بنا أو مفتاح أمان TOTP، ومع ذلك قد يحدث هذا في بعض الأحيان ونفقد التحكّم بالمفاتيح التي تجعلنا نُسجِّل الدخول. نجد هنا بعض الاقتراحات لاستعادة النفاذ إلى خادومنا: إن فقدنا تطبيق TOTP أو لم نعد نملك نفاذًا إليه، نستخدم شيفرات الاستعادة recovery codes كشيفرة للتحقيق، قد يحدث هذا إن اشترينا هاتفًا جديدًا ونسينا تصدير مفاتيحنا من الهاتف القديم، أو نفذت بطارية هاتفنا.إن فقدنا مفتاح الأمان secret key والنسخة الاحتياطية، نقوم بإعادة تسمية أو حذف الملف google_authenticator./~، حيث يحرص هذا ألّا تعود PAM على معرفة بإعداداتنا وألّا تطلب منّا الرمز، تأكّد من أنّ الملف etc/pam.d/sshd/ لا زال يملك "nullok" في آخره، مثل الخطوة الثانية، وإن غيّرنا هذا نقوم بإعادة تشغيل SSH.إن فقدنا مفتاح SSH الخاص بنا، نقوم بإزالة المفتاح العام القديم من ssh/authorized_hosts./~، ونستبدله بمفتاح جديد.بامتلاك عاملين (مفتاح SSH+رمز MFA token) عبر قناتين اثنتين (حاسوبنا+هاتفنا المحمول) جعلنا من المستحيل تقريبًا لأي عميل خارجي أن يشقّ طريقه بالقوة القاسية brute force إلى داخل جهازنا عبر SSH وقمنا بزيادة أمان جهازنا بشكل رائع. ترجمة -وبتصرّف- لـ How To Set Up Multi-Factor Authentication for SSH on Ubuntu 14.04 لصاحبه Michael Holley.
  17. إنّ Bacula-web هو عبارة عن تطبيق ويب مكتوب بلغة PHP يُزوِّدنا بطريقة سهلة لعرض ملخصات ومخططات بيانية لوظائف النسخ الاحتياطي backup jobs التي تم تشغيلها مسبقًا، وبالرغم من أنّه لا يسمح لنا بالتحكم بـ Bacula بأي طريقة فهو يُزوِّدنا بواجهة رسوميّة بديلة لطريقة عرض الوظائف من الـ console، إنّ Bacula-web مفيد خاصّة للمستخدمين الجديدين على Bacula، حيث تُسهِّل علينا تقاريره فهم آلية عمل Bacula. سنشرح في هذا الدّرس كيفيّة تثبيت Bacula-web على خادوم Ubuntu الذي تعمل عليه برمجيّة خادوم Bacula. المتطلبات الأساسيةيجب أن تمتلك من أجل متابعة الدّرس برمجيّة خادوم Bacula للنسخ الاحتياطي مُثبَّتة على خادوم Ubuntu لديك، تستطيع إيجاد تعليمات تثبيت Bacula هنا: كيفيّة تثبيت خادوم Bacula على Ubuntu. يفترض هذا الدّرس أنّ خادوم Bacula لديك يستخدم قاعدة بيانات MySQL، إن كنت تستخدم قاعدة بيانات أخرى مثل PostgreSQL فتأكّد من أن تقوم بالضبط المناسب من أجل هذا الدّرس، ستحتاج إلى تثبيت وحدة PHP مناسبة والقيام بضبط أمثلة معلومات اتصال قاعدة البيانات. فلنبدأ الآن. تثبيت Nginx و PHPإنّ Bacula-web هو عبارة عن تطبيق PHP لذا نحتاج لتثبيت PHP وخادوم ويب، سنستخدم Nginx، إن أردت تعلم المزيد حول إعداد هذه البرمجيّة فتحقّق من هذا الدّرس LEMP tutorial. نقوم بتحديث قوائم apt-get لدينا: sudo apt-get updateنُثبِّت بعدها Nginx، PHP-fpm، وبعض الحِزَم الأخرى باستخدام apt-get: sudo apt-get install nginx apache2-utils php5-fpm php5-mysql php5-gdنحن الآن جاهزون لإعداد PHP وNginx. إعداد PHP-FPMنفتح ملف إعدادات PHP-FPM باستخدام مُحرِّر النصوص الذي نفضّله، سنستخدم vi: sudo vi /etc/php5/fpm/php.iniنبحث عن السطر الذي يُحدِّد cgi.fix_pathinfo، نزيل التعليق عنه ونستبدل قيمته بـ 0، يجب أن يبدو كما يلي بعد أن ننتهي من ذلك: cgi.fix_pathinfo=0نبحث الآن عن الإعداد date.timezone، نزيل التعليق عنه ونستبدل قيمته بقيمة المنطقة الزمنية لدينا، سنضع New York على سبيل المثال: date.timezone = America/New_Yorkإن أردت الحصول على قائمة بكافّة المناطق الزمنية timezones فتحقّق من وثائق PHP. نحفظ الملف ونخرج منه. الآن وقد أصبح PHP-FPM مُعدًّا بشكل صحيح فلنقم بإعادة تشغيله لتطبيق التغييرات: sudo service php5-fpm restartإعداد Nginxحان الوقت الآن لإعداد Nginx ليُخدِّم تطبيقات PHP. في البداية نقوم بإنشاء ملف htpasswd لكي لا نسمح بالأشخاص غير المُصرَّح لهم بالنفاذ إلى Bacula-web، نستخدم الأمر htpasswd لإنشاء مستخدم مُدير admin، يُدعى "admin" (يجب أن تستخدم اسمًا آخر)، والذي يستطيع النفاذ إلى واجهة Bacula-web: sudo htpasswd -c /etc/nginx/htpasswd.users adminندخل كلمة السّر في المُحِث prompt، ونقوم بتحديد تذكر تسجيل الدخول هذا لأنّنا سنحتاجه للنفاذ إلى Bacula-web. نفتح الآن ملف إعدادات كتلة block الخادوم الافتراضيّة في Nginx من خلال مُحرِّر نصوص، سنستخدم vi: sudo vi /etc/nginx/sites-available/defaultنستبدل محتويات الملف بكتلة الشيفرة code التالية، احرص على تبديل القيمة server_name باسم نطاق خادومك أو عنوان IP الخاص به: server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /usr/share/nginx/html; index index.php index.html index.htm; server_name server_domain_name_or_IP; auth_basic "Restricted Access"; auth_basic_user_file /etc/nginx/htpasswd.users; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }نقوم بحفظ الملف والخروج منه، يقوم هذا بإعداد Nginx لتخديم تطبيقات PHP وليستخدم ملف htpasswd الذي أنشأناه سابقًا من أجل الاستيثاق authentication. ولتطبيق التغييرات نعيد تشغيل Nginx: sudo service nginx restartنحن الآن جاهزون لتنزيل Bacula-web. تنزيل وإعداد Bacula-webنقوم بالانتقال إلى الدليل الرئيسي home لدينا وتنزيل إصدار Bacula-web الأخير على شكل ملف أرشيف، الإصدار الأخير في وقت كتابة هذا الدّرس هو 7.0.3: cd ~ wget --content-disposition http://www.bacula-web.org/download.html?file=files/bacula-web.org/downloads/bacula-web-7.0.3.tgzنُنشِئ الآن دليلًا جديدًا اسمه bacula-web، وننتقل إليه، ثمّ نستخرج محتويات الأرشيف Bacula-web إليه: mkdir bacula-web cd bacula-web tar xvf ../bacula-web-*.tgzينبغي قبل نسخ الملفّات إلى جذر المستند document root لخادوم الويب لدينا أن نقوم بإعداده أولًا. نقوم بالانتقال إلى دليل الإعدادات كما يلي: cd application/configيُزوِّدنا Bacula-web بعيّنة sample من الإعدادات، ننسخها كما يلي: cp config.php.sample config.phpنقوم الآن بتحرير ملف الإعدادات ضمن مُحرِّر نصوص، سنستخدم vi: vi config.phpنبحث بداخله عن: MySQL bacula catalog //ونزيل التعليق عن تفاصيل الاتصال، نضع أيضًا كلمة سر قاعدة بيانات Bacula الخاصّة بنا بدلًا من القيمة password (والتي يُمكِن إيجادها في المسار etc/bacula/bacula-dir.conf/ ضمن الإعداد "dbpassword"): // MySQL bacula catalog $config[0]['label'] = 'Backup Server'; $config[0]['host'] = 'localhost'; $config[0]['login'] = 'bacula'; $config[0]['password'] = 'bacula-db-pass'; $config[0]['db_name'] = 'bacula'; $config[0]['db_type'] = 'mysql'; $config[0]['db_port'] = '3306';نحفظ الملف ونخرج منه. أصبح الآن Bacula-web مُعدًّا كما يجب، الخطوة الأخيرة هي وضع ملفّات التطبيق في المكان المناسب. نسخ تطبيق Bacula-web إلى جذر المستند Document Rootقمنا بإعداد Nginx ليستخدم usr/share/nginx/html/ كجذر المستند، ننتقل إلى هذا المسار ونحذف الملف index.html الافتراضي باستخدام الأوامر التالية: cd /usr/share/nginx/html sudo rm index.htmlننقل الآن ملفّات Bacula-web إلى الموقع الحالي، وهو جذر مستند Nginx: sudo mv ~/bacula-web/* .نقوم بتغيير ملكيّة الملفّات إلى www-data، وهو المستخدم العفريت (بالإنجليزية Daemon وهو برنامج يعمل في خلفيّة النظام) الذي يقوم بتشغيل Nginx: sudo chown -R www-data: *الآن تمّ تثبيت Bacula-web بشكل كامل. النفاذ إلى Bacula-web من خلال المتصفحأصبح الآن Bacula-web قابلًا للنفاذ على اسم نطاق خادومنا أو من خلال عنوان IP العام له. ربّما ترغب الآن أن تختبر أنّ كل شيء مُعَد بشكل صحيح، ولحسن الحظ يُزوّدنا Bacula-web بصفحة اختبار test، نستطيع الوصول إليها بفتح الرابط التالي في متصفّح الإنترنت (مع وضع عنوان خادومنا بدلًا من server_public_IP): http://server_public_IP/test.phpينبغي أن نرى الآن جدول يُظهِر الحالة لمختلف عناصر Bacula-web، ويجب أن تملك كافّة العناصر علامة صح خضراء بجانبها، ما عدا وحدات قواعد البيانات التي لا نريدها، على سبيل المثال نحن نستخدم هنا MySQL لذا لا نحتاج لوحدات قواعد البيانات الأخرى: إن سار كل شيء على ما يرام فنحن الآن جاهزون لاستخدام الصفحة الرئيسيّة dashboard، نستطيع الوصول إليها عن طريق النقر على النص "Bacula-web" الموجود في الأعلى والأيسر، أو عن طريق زيارة خادومنا من خلال متصفّح الإنترنت: http://server_public_IP/يجب أن تبدو مماثلة لما يلي: الخاتمةأصبحنا مستعدين الآن لاستخدام Bacula-web لمراقبة مُختلَف وظائف Bacula وحالاتها بسهولة. ترجمة -وبتصرّف- لـ How To Install Bacula-web on Ubuntu 14.04 لصاحبه Mitchell Anicas.
  18. NAT، أو نقل عنوان الشبكة network address translation، عبارة عن مصطلح عام لإدارة الرُّزَم packets من أجل إعادة توجيهها إلى عنوان بديل، وهو يُستخدم عادةً للسماح لحركة مرور البيانات traffic بتجاوز حدود الشبكة، يمتلك المُضيف host الذي يُطبِّق NAT نفاذًا إلى شبكتين أو أكثر بشكل نموذجي وهو مُعَد لنقل حركة مرور البيانات بينها. إعادة توجيه المنافذ Port forwarding هو عمليّة إعادة توجيه الطلبات لمنفذ مُعيَّن إلى مُضيف آخر، شبكة، أو منفذ. وبينما تقوم هذه العمليّة بتعديل وجهة الرُّزَم أثناء نقلها، فهي تُعتبَر نوع من عمليّات NAT. سنشرح في هذا الدرس كيفيّة استخدام iptables لإعادة توجيه المنافذ إلى مضيفين خلف جدار ناري باستخدام تقنيات NAT، يكون هذا مفيدًا في حال قمنا بإعداد شبكة خاصّة Private Network ولا زلنا نريد السماح لبعض حركة مرور البيانات بالمرور عبر جهاز مُحدّد كبوّابة gateway، سنستخدم مُضيفين اثنين يعملان على نظام Ubuntu لتوضيح هذا. المتطلبات الأساسية والأهداف لمتابعة هذا الدّرس تحتاج إلى مُضيفين اثنين يعملان على نظام Ubuntu في نفس مركز البيانات مع تمكين الشبكات الخاصّة private networking، نحتاج إلى إعداد حساب مُستخدِم غير جذري non-root مع صلاحيّات sudo على كل من هذين الجهازين، تستطيع معرفة كيفيّة إعداد مُستخدِم مع صلاحيّات sudo باتّباع درس الإعداد الأولي لخادوم Ubuntu. سيعمل المُضيف الأول كجدار ناري ومُوجِّه router لأجل الشبكة الخاصّة، ولأغراض توضيحيّة سيكون المُضيف الثاني مُعدًّا مع خادوم ويب قابل للوصول فقط باستخدام واجهته الخاصّة، سنقوم بإعداد جهاز الجدار الناري ليُعيد توجيه الطلبات التي يتلقّاها على واجهته العامّة إلى خادوم الويب حيث ستصل إلى واجهته الخاصّة. تفاصيل المضيف نحتاج قبل البدء أن نعرف الواجهات والعناوين التي يتم استخدامها من قِبَل كلا الخادمين لدينا. العثور على تفاصيل شبكتنا للحصول على تفاصيل أنظمتنا نبدأ بإيجاد واجهات شبكاتنا Network Interfaces، نستطيع العثور على الواجهات والعناوين المرتبطة بها على أجهزتنا بكتابة: ip -4 addr show scope global 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 198.51.100.45/18 brd 45.55.191.255 scope global eth0 valid_lft forever preferred_lft forever 3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 192.168.1.5/16 brd 10.132.255.255 scope global eth1 valid_lft forever preferred_lft forever يُظهِر الخَرْج output السّابق واجهتين (eth0 و eth1) والعناوين المُخصّصة لكل منهما (192.51.100.45 و 192.168.1.5 على الترتيب)، ولمعرفة أيّ الواجهتين هي الواجهة العامّة نكتب: ip route show | grep default default via 111.111.111.111 dev eth0 تكون الواجهة الظاهرة أمامنا (eth0 في هذا المثال) هي الواجهة المُتصلة إلى بوّابتنا الافتراضيّة، وهي بكل تأكيد واجهتنا العامّة. قم بإيجاد هذه القيم على كل جهاز لديك واستخدمها للمتابعة مع هذا الدّرس بشكل صحيح. عينة بيانات من أجل هذا الدرس لكي نجعل متابعة هذا الدّرس أسهل سنستخدم العناوين الوهميّة وتعيينات الواجهة التالية، قم بوضع القيم الخاص بك بدلًا من هذه القيم: تفاصيل شبكة خادوم الويب: عنوان IP العام Public IP Address: 203.0.113.2 عنوان IP الخاص Private IP Address: 192.0.2.2 الواجهة العامّة Public Interface: eth0 الواجهة الخاصّة Private Interface: eth1 تفاصيل شبكة الجدار الناري: عنوان IP العام Public IP Address: 203.0.113.15 عنوان IP الخاص Private IP Address: 192.0.2.15 الواجهة العامّة Public Interface: eth0 الواجهة الخاصّة Private Interface: eth1 إعداد خادوم الويب سنبدأ بإعداد مُضيف خادوم الويب، نقوم بتسجيل الدخول كمستخدم sudo للبدء. تثبيت Nginx الخطوة الأولى التي سنقوم بها هي تثبيت Nginx على مُضيف خادوم الويب لدينا وقفله بحيث يستمع فقط إلى واجهته الخاصّة، يجعلنا هذا متأكدين من أنّ خادوم الويب لن يكون متوفّرًا إلّا إذا ضبطنا إعادة توجيه المنافذ بشكل صحيح. نبدأ بتحديث الذاكرة المؤقتة للحزم المحليّة local package cache باستخدام الأمر apt لتنزيل وتثبيت Nginx: webserver $ sudo apt-get update webserver $ sudo apt-get install nginx تقييد Nginx إلى الشبكة الخاصة بعد تثبيت Nginx نقوم بفتح ملف إعدادات كتلة block الخادوم الافتراضيّة للتأكد من أنّه يستمع فقط إلى واجهته الخاصّة، نفتح الملف عن طريق الأمر التالي: webserver $ sudo nano /etc/nginx/sites-enabled/default نبحث بداخله عن الأمر التوجيهي listen، ينبغي أن نجده في سطرين متتاليين في أعلى ملف الإعدادات: etc/nginx/sites-enabled/default/ server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; . . . } نقوم عند الأمر التوجيهي listen الأول بإضافة عنوان IP الخاص لخادوم الويب لدينا مع نقطتين قبل 80 لنُخبِر Nginx أن يستمع فقط إلى واجهته الخاصّة، سنوضّح في هذا الدّرس إعادة توجيه IPv4 فقط، لذا نستطيع إزالة الأمر التوجيهي listen الثاني المُعَد من أجل IPv6. سنقوم في مثالنا بتعديل الأمر التوجيهي listen بحيث يبدو كما يلي: etc/nginx/sites-enabled/default/ server { listen 192.0.2.2:80 default_server; . . . } عند الانتهاء نحفظ الملف ونغلقه، نختبر الملف بحثًا عن أخطاء الصياغة syntax بكتابة ما يلي: webserver $ sudo nginx -t إن لم تظهر أيّة أخطاء نُعيد تشغيل خادوم Nginx لتمكين الإعدادات الجديدة: webserver $ sudo service nginx restart التحقق من تقييد الشبكة Network Restriction من المُفيد عند هذه النقطة التحقّق من مستوى النفاذ الذي نملكه لخادوم الويب لدينا. إن قمنا بمحاولة النفاذ لخادوم الويب عبر واجهته الخاصّة من خلال خادوم الجدار الناري firewall ينبغي أن ينجح هذا: firewall $ curl --connect-timeout 5 192.0.2.2 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . . أمّا إن قمنا باستخدام الواجهة العامّة سنجد أنّنا لن نستطيع الاتصال: firewall $ curl --connect-timeout 5 203.0.113.2 curl: (7) Failed to connect to 203.0.113.2 port 80: Connection refused وهو بالضبط ما نتوقّع حدوثه. إعداد الجدار الناري لإعادة توجيه المنفذ 80 نستطيع الآن العمل على تنفيذ إعادة توجيه المنافذ على جهاز الجدار الناري. تمكين إعادة التوجيه في النواة Kernel الأمر الأول الذي يجب فعله هو تمكين إعادة التوجيه على مستوى النّواة، تكون إعادة التوجيه غير مُشغَّلة في مُعظم الأنظمة. ولتشغيل إعادة توجيه المنافذ لأجل هذه الجلسة فقط نكتب: firewall $ echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward ولتشغيل إعادة توجيه المنافذ بشكل دائم ينبغي علينا تحرير الملف etc/sysctl.conf/، نفتح الملف بصلاحيّات sudo بكتابة: firewall $ sudo nano /etc/sysctl.conf نبحث بداخله عن السطر التالي ونقوم بإزالة التعليق uncomment عنه: etc/sysctl.conf/ net.ipv4.ip_forward=1 عند الانتهاء نحفظ الملف ونغلقه، نقوم بتطبيق الإعدادات في هذا الملف بكتابة ما يلي: firewall $ sudo sysctl -p firewall $ sudo sysctl --system إعداد الجدار الناري الأساسي سنستخدم الجدار الناري الموجود في هذا الدّرس كإطار عمل أساسي من أجل القواعد، قم بتنفيذ التعليمات في درس كيفية إعداد جدارٍ ناريّ باستخدام iptables، وبعد الانتهاء يجب أن تكون قد: قمت بتثبيت iptables-persistent حفظت مجموعة القواعد الافتراضيّة في etc/iptables/rules.v4/ تعلّمت كيفيّة إضافة أو ضبط القواعد عن طريق تحرير ملف القواعد أو باستخدام الأمر iptables بعد أن تقوم بإعداد الجدار الناري الأساسي أكمل الخطوات التالية لكي تستطيع ضبطه من أجل إعادة توجيه المنافذ. إضافة قواعد إعادة التوجيه نريد أن نضبط جدارنا الناري بحيث تتم إعادة توجيه حركة مرور البيانات traffic المُتدفّقة لواجهتنا العامّة (eth0) إلى واجهتنا الخاصّة (eth1). يمتلك جدارنا الناري الأساسي السلسلة FORWARD مُعدّة افتراضيًّا لكي تستبعد DROP حركة مرور البيانات، نحتاج لإضافة قواعد تسمح لنا بإعادة توجيه الاتصالات لخادوم الويب لدينا، ولأغراض أمنية سنقوم بتحديد هذا بشكل مُحكَم بحيث يتم فقط السماح للاتصالات التي نرغب بإعادة توجيهها. سنقبل في السلسلة FORWARD الاتصالات الجديدة المتجهة للمنفذ 80 والقادمة من واجهتنا العامة مُغادرةً إلى واجهتنا الخاصة، يتم تحديد الاتصالات الجديدة بواسطة اللاحقة conntrack ويتم تمثيلها بشكل خاص بواسطة رُزمة TCP SYN: firewall $ sudo iptables -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT سيسمح هذا للرزمة الأولى المعنيّة بإنشاء الاتصال بالعبور من خلال الجدار الناري، نحتاج أيضًا للسماح بأي حركة مرور بيانات لاحقة في كلا الاتجاهين والتي تنتج عن هذا الاتصال، نكتب ما يلي للسماح بحركة مرور البيانات التي تُنشئ هذا الاتصال ESTABLISHED والمتعلّقة به RLEATED بين واجهاتنا الخاصّة والعامة: firewall $ iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT firewall $ iptables -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT بإمكاننا إعادة التحقّق من أنّ سياساتنا على السلسلة FORWARD هي الاستبعاد DROP بكتابة ما يلي: firewall $ sudo iptables -P FORWARD DROP عند هذه النقطة سمحنا بحركة مرور بيانات مُحدّدة بين واجهاتنا الخاصّة والعامّة بالمرور من خلال الجدار الناري لدينا، ومع ذلك لم نقم بضبط القواعد التي تُخبِر iptables فعليًّا كيف يقوم بنقل وتوجيه حركة مرور البيانات. إضافة قواعد NAT لتوجيه الرزم بشكل صحيح سنضيف الآن القواعد التي تُخبِر iptables كيف يقوم بتوجيه حركة مرور بياناتنا، نحتاج لتنفيذ عمليتين منفصلتين من أجل أن يقوم iptables بتغيير الرُّزَم بشكل صحيح بحيث يتمكّن العملاء من التواصل مع خادوم الويب. تحدث العمليّة الأولى التي تُدعى DNAT في السلسلة PREROUTING من جدول nat، وهي عمليّة تقوم بتبديل عنوان وجهة الرُّزَم لتمكينها من التوجه بشكل صحيح عندما تمر بين الشبكات، سيتصل العملاء على الشبكة العامّة إلى خادوم الجدار الناري لدينا بدون أن يعلموا عن بُنية الشبكة الخاصّة لدينا، نحتاج لتبديل عنوان الوجهة لكل رُزمة بحيث تعلم عند إرسالها خارج شبكتنا الخاصّة كيف تصل بشكل صحيح إلى خادوم الويب. بما أنّنا نقوم فقط بإعداد إعادة توجيه المنافذ ولا نقوم بعمل NAT على كل رُزمة تصطدم بجدارنا الناري فيجب علينا أن نُطابِق المنفذ 80 في قاعدتنا، سنقوم بمطابقة الرُّزَم التي تستهدف المنفذ 80 إلى عنوان IP الخاص لخادوم الويب لدينا (192.0.2.2 في مثالنا): firewall $ sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.0.2.2 يهتم هذا بنصف الحل، فينبغي الآن أن يتم توجيه الرُّزَم بشكل صحيح إلى خادوم الويب لدينا، ومع ذلك فإنّ الرُّزَم لا تزال تملك العنوان الأصلي للعميل كعنوان مصدر، وسيحاول الخادوم إرسال الرد مباشرة إلى ذلك العنوان، ممّا يجعل من المستحيل تأسيس اتصال TCP قانوني. نحتاج من أجل ضبط التوجيه المناسب أن نقوم بتعديل عنوان المصدر للرُزَم عندما تغادر الجدار الناري في طريقها إلى خادوم الويب، يجب علينا تعديل عنوان المصدر وتغييره إلى عنوان IP الخاص لخادوم الجدار الناري لدينا (في مثالنا 192.0.2.15)، سيتم عندها إرسال الرّد إلى الجدار الناري والذي يستطيع إعادة توجيهه إلى العميل كما هو متوقّع. ولتمكين هذه الوظيفة سنضيف قاعدة إلى سلسلة POSTROUTING من جدول nat، والتي يتم تقييمها مباشرة قبل إرسال الرُّزَم على الشبكة، سنطابق الرُّزَم الموجّهة إلى خادوم الويب عن طريق عنوان IP والمنفذ: firewall $ sudo iptables -t nat -A POSTROUTING -o eth1 -p tcp --dport 80 -d 192.0.2.2 -j SNAT --to-source 192.0.2.15 حالما يتم إعداد هذه القاعدة ينبغي أن يصبح خادوم الويب لدينا قابل للنفاذ عن طريق توجيه متصفّح الويب لدينا إلى العنوان العام لجهاز الخادوم الناري: curl 203.0.113.15 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> . . . اكتمل هنا إعداد إعادة توجيه المنافذ. ضبط مجموعة القواعد الدائمة نستطيع الآن بعد أن قمنا بإعداد إعادة توجيه المنافذ أن نحفظه في مجموعة قواعد دائمة. إن لم تكن تهتم بفقدان التعليقات الموجودة في مجموعة القواعد الحالية لديك فاستخدم الخدمة iptables-persistent لحفظ قواعدك: firewall $ sudo service iptables-persistent save إن كنت ترغب بالحفاظ على التعليقات في ملفّك، فقم بفتحه وتحريره يدويًّا: firewall $ sudo nano /etc/iptables/rules.v4 سنحتاج إلى ضبط الإعدادات في الجدول filter من أجل قواعد السلسلة FORWARD التي تمّت إضافتها، يجب علينا أيضًا ضبط القسم الذي يقوم بإعداد الجدول nat كي نستطيع إضافة القواعد PREROUTING و POSTROUTING، سيبدو هذا في مثالنا مُشابِهًا لما يلي: etc/iptables/rules.v4/ *filter # Allow all outgoing, but drop incoming and forwarding packets by default :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] # Custom per-protocol chains :UDP - [0:0] :TCP - [0:0] :ICMP - [0:0] # Acceptable UDP traffic # Acceptable TCP traffic -A TCP -p tcp --dport 22 -j ACCEPT # Acceptable ICMP traffic # Boilerplate acceptance policy -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -i lo -j ACCEPT # Drop invalid packets -A INPUT -m conntrack --ctstate INVALID -j DROP # Pass traffic to protocol-specific chains ## Only allow new connections (established and related should already be handled) ## For TCP, additionally only allow new SYN packets since that is the only valid ## method for establishing a new TCP connection -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP # Reject anything that's fallen through to this point ## Try to be protocol-specific w/ rejection message -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable # Rules to forward port 80 to our web server # Web server network details: # * Public IP Address: 203.0.113.2 # * Private IP Address: 192.0.2.2 # * Public Interface: eth0 # * Private Interface: eth1 # # Firewall network details: # # * Public IP Address: 203.0.113.15 # * Private IP Address: 192.0.2.15 # * Public Interface: eth0 # * Private Interface: eth1 -A FORWARD -i eth0 -o eth1 -p tcp --syn --dport 80 -m conntrack --ctstate NEW -j ACCEPT -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A FORWARD -i eth1 -o eth0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # End of Forward filtering rules # Commit the changes COMMIT *raw :PREROUTING ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] # Rules to translate requests for port 80 of the public interface # so that we can forward correctly to the web server using the # private interface. # Web server network details: # * Public IP Address: 203.0.113.2 # * Private IP Address: 192.0.2.2 # * Public Interface: eth0 # * Private Interface: eth1 # # Firewall network details: # # * Public IP Address: 203.0.113.15 # * Private IP Address: 192.0.2.15 # * Public Interface: eth0 # * Private Interface: eth1 -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.0.2.2 -A POSTROUTING -d 192.0.2.2 -o eth1 -p tcp --dport 80 -j SNAT --to-source 192.0.2.15 # End of NAT translations for web server traffic COMMIT *security :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] COMMIT *mangle :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT قم بحفظ الملف وأغلقه بعد إضافة ما سبق وضبط القيم لكي تنطبق على بيئة شبكتك الخاصّة. نختبر صياغة ملف القواعد لدينا بكتابة: firewall $ sudo iptables-restore -t < /etc/iptables/rules.v4 إن لم يتم اكتشاف أيّة أخطاء نقوم بتحميل مجموعة القواعد: firewall $ sudo service iptables-persistent reload نختبر أنّ خادوم الويب لدينا لا يزال قابل للنفاذ من خلال عنوان IP العالم للجدار النّاري: firewall $ curl 203.0.113.15 ينبغي لهذا أن يعمل كما عمل سابقًا. الخاتمة ينبغي الآن أن نكون متآلفين مع إعادة توجيه المنافذ على خادوم لينِكس باستخدام iptables، تتضمّن العملية السماح بإعادة التوجيه على مستوى النّواة، إعداد النفاذ للسماح بإعادة التوجيه لحركة مرور البيانات لمنافذ مُحدّدة بين واجهتين على نظام الجدار النّاري، وضبط قواعد NAT بحيث يُمكِن توجيه الرُّزَم بشكل صحيح، ربّما تبدو هذه عمليّة صعبة، ولكنّها تُوضّح أيضًا مرونة إطار عمل ترشيح الرُّزَم netfilter وجدار iptables النّاري، يُمكِن استخدام هذا لتمويه بُنية الشبكة الخاصّة لدينا مع السمّاح بحركة مرور البيانات للخدمات بالمرور بشكل حر عبر بوّابة جهاز الجدار النّاري. ترجمة -وبتصرّف- لـ How To Forward Ports through a Linux Gateway with Iptables لصاحبه Justin Ellingwood.
  19. سنتعلّم في هذا الدّرس كيفيّة إعداد Bacula لإنشاء نُسَخ احتياطيّة backups لمُضيف Ubuntu عن بُعد remote وذلك عبر اتصال عن طريق الشبكة، يتضمّن هذا تثبيت وإعداد برمجيّة عميل Bacula على مُضيف عن بُعد remote host، والقيام ببعض الإضافات لإعدادات خادوم Bacula موجود حاليًّا (تمّت تغطية هذا الموضوع في فقرة المتطلبات الأساسيّة الآتي ذكرها). المتطلبات الأساسيةيفترض هذا الدّرس أنّك تمتلك خادوم تعمل عليه عناصر خادوم Bacula، كما هو موصوف في هذا الرّابط: كيف تثبت خادوم Bacula للنسخ الاحتياطي على Ubuntu 14.04. نفترض أيضًا أنّك تستخدم واجهات شبكة خاصّة للنسخ الاحتياطي للاتصالات بين الخادوم والعميل، سنقوم بالرجوع إلى FQDN الخاص للخواديم (حيث تُشير FQDNs إلى عناوين IP الخاصّة)، إن كنت تستخدم عناوين IP فضع معلومات الاتصال الخاصّة بك في الأماكن الملائمة. سنقوم في بقيّة هذا الدّرس بالإشارة إلى خادوم Bacula بـ "BaculaServer"، "Bacula Server"، أو "Backup Server"، سنشير إلى المُضيف عن بُعد والذي يتم النسخ الاحتياطي له بـ "ClientHost"، "Client Host"، أو "Client". فلنبدأ بالقيام ببعض التغييرات السريعة لإعدادات خادوم Bacula. تنظيم إعدادات مدير Bacula Director (الخادوم)نقوم على خادوم Bacula بتطبيق هذا القسم مرّة واحدة. ربما قد لاحظت عند إعداد خادوم Bacula أنّ ملفّات الإعدادات طويلة بشكل زائد، سنحاول تنظيم إعدادات مدير Bacula قليلًا بحيث يستخدم ملفّات منفصلة لإضافة الإعدادات الجديدة مثل الوظائف jobs، مجموعات الملفّات file sets، والأحواض pools. فلنقم بإنشاء دليل ليساعدنا على تنظيم ملفّات إعدادات Bacula: sudo mkdir /etc/bacula/conf.dنفتح بعدها ملف إعدادات مدير Bacula: sudo vi /etc/bacula/bacula-dir.confنضيف هذا السطر في نهاية الملف: @|"find /etc/bacula/conf.d -name '*.conf' -type f -exec echo @{} \;"نقوم بحفظ الملف والخروج منه، يُخبِر هذا السطر المدير أن يبحث في الدليل /etc/bacula/conf.d عن ملفّات إضافيّة للإعدادات ليقوم بإلحاقها، وهذا يعني أنّ أي ملف .conf تتم إضافته هنا سيتم تحميله كجزء من الإعدادات. إضافة حوض الملفات عن بعد RemoteFile Poolنريد إضافة حوض Pool إضافي لإعدادات مدير Bacula لدينا، وسنستخدمه لإعداد وظائف النسخ الاحتياطي عن بُعد. نفتح الملف conf.d/pools.conf: sudo vi /etc/bacula/conf.d/pools.confنضيف موارد الحوض Pool التالية: Pool { Name = RemoteFile Pool Type = Backup Label Format = Remote- Recycle = yes # Bacula can automatically recycle Volumes AutoPrune = yes # Prune expired volumes Volume Retention = 365 days # one year Maximum Volume Bytes = 50G # Limit Volume size to something reasonable Maximum Volumes = 100 # Limit number of Volumes in Pool }نقوم بحفظ الملف والخروج منه، يُعرِّف هذا حوض للملفّات عن بُعد "RemoteFile"، والذي سنستخدمه من قبل وظيفة النسخ الاحتياطي التي سنقوم بإنشائها لاحقًا، ولك الحريّة في تغيير أي مُعامِل بحيث يُلائم احتياجاتك. حتى الآن لا نحتاج إلى إعادة تشغيل مدير Bacula، ولكن فلنتحقّق أنّ إعداداته لا تحتوي على أيّة أخطاء فيها: sudo bacula-dir -tc /etc/bacula/bacula-dir.confإن لم تكن هنالك أيّة أخطاء فنحن جاهزون للمتابعة في إعداد عميل Bacula Client. تثبيت وإعداد عميل Baculaنقوم بتنفيذ هذا القسم على أي مُضيف عميل Client Host نريد إضافته إلى إعداد Bacula. في البداية نُحدِّث apt-get: sudo apt-get updateنثبّت بعدها الحزمة bacula-client: sudo apt-get install bacula-clientيقوم هذا بتثبيت عفريت (بالإنجليزية Daemon وهو برنامج يعمل في خلفيّة النظام) ملفّات Bacula FD أي (Bacula File Daemon)، والذي عادة تتم الإشارة إليه بعميل Bacula أي "Bacula client". إعداد العميلينبغي قبل إعداد عفريت ملفّات العميل File Daemon إيجاد المعلومات التالية، والتي سيتم استخدامها خلال هذا الدّرس: اسم مضيف العميل Client hostname: سيستخدم مثالنا "ClientHost".FQDN الخاص للعميل Client Private FQDN: سنشير له بـ "clientprivateFQDN"، وهو يبدو مُشابِهًا لـ clienthost.private.example.com.اسم مضيف خادوم Bacula أي Bacula Server hostname: سيستخدم مثالنا "BackupServer".ستختلف إعداداتك الفعلية عن هذه الأمثلة، لذا تأكّد من وضع معلوماتك في الأماكن المناسبة. نفتح إعدادات عفريت الملفّات File Daemon: sudo vi /etc/bacula/bacula-fd.confنحتاج لتغيير بعض العناصر وحفظ بعض المعلومات التي سنحتاجها لأجل إعدادات خادومنا. نبدأ بإيجاد مورد المدير Director resource المُسمّى على اسم مضيف العميل لدينا (على سبيل المثال "ClientHost-dir")، وبما أنّ مدير Bacula الذي نريد التحكّم من خلاله بالعميل متواجد على خادوم Bacula فلنقم بتغيير مُعامِل الاسم "Name" إلى اسم المضيف لخادوم النسخ الاحتياطي لدينا متبوعًا بـ "-dir"، في مثالنا وباستخدام "BackupServer" كاسم مضيف خادوم Bacula يجب أن يبدو هذا مُشابِهًا لما يلي: Director { Name = BackupServer-dir Password = "IrIK4BHRA2o5JUvw2C_YNmBX_70oqfaUi" }نحتاج أيضًا أن ننسخ المُعامِل Password ونحفظه من أجل العودة إليه لاحقًا، وهو عبارة عن كلمة السّر المُولَّدة تلقائيًّا والمستخدمة من أجل الاتصال إلى عفريت الملفّات File Daemon، سيتم استخدامها في إعدادات مدير خادوم النسخ الاحتياطي حيث سنقوم بتعيينها في خطوة قادمة من أجل الاتصال إلى عفريت الملفّات File Daemon الخاص بالعميل. نحتاج بعدها إلى ضبط معامل واحد في مورد عفريت الملفّات FileDaemon، حيث سنقوم بتغيير المُعامِل FDAddress ليُطابِق FQDN الخاص لأجهزة عملائنا، يجب أن يكون مُسبقًا قد تم إعداد المُعامِل Name بشكل صحيح مع اسم عفريت الملفّات file daemon للعميل، ينبغي أن يبدو المورد مشابهًا لما يلي (قم بوضع FQDN الفعلية أو عنوان IP لديك): FileDaemon { # this is me Name = ClientHost-fd FDport = 9102 # where we listen for the director WorkingDirectory = /var/lib/bacula Pid Directory = /var/run/bacula Maximum Concurrent Jobs = 20 FDAddress = client_private_FQDN }نحتاج أيضًا لضبط هذا العفريت daemon ليقوم بتمرير رسائل سجلّاته إلى خادوم النسخ الاحتياطي، نقوم بالبحث عن مورد الرسائل Messages وتغيير المُعامِل director ليطابق اسم مضيف خادوم النسخ الاحتياطي لدينا مع اللاحقة "-dir"، ينبغي أن يبدو مشابهًا لما يلي: Messages { Name = Standard director = BackupServer-dir = all, !skipped, !restored }نقوم بحفظ الملف والخروج منه، تم الآن إعداد عفريت الملفّات File Daemon (عميل Bacula) ليستمع للاتصالات عبر الشبكة الخاصّة. نتحقّق من أن ملف الإعدادات يمتلك الصياغة الصحيحة باستخدام الأمر التالي: sudo bacula-fd -tc /etc/bacula/bacula-fd.confإن لم يُعد الأمر أي خَرْج output فهذا يعني أنّ ملف الإعدادات يمتلك صياغة صحيحة، نعيد تشغيل عفريت الملفّات File Daemon ليستخدم الإعدادات الجديدة: sudo service bacula-fd restartفلنقم بإعداد دليل يستطيع خادوم Bacula استعادة الملفّات إليه، نقوم بإنشاء بنية الملفّات وحصر الصلاحيّات والملكيّة لأجل الأمان عن طريق الأوامر التالية: sudo mkdir -p /bacula/restore sudo chown -R bacula:bacula /bacula sudo chmod -R 700 /baculaتمّ الآن إعداد جهاز العميل بشكل صحيح، سنقوم بعدها بضبط خادوم النسخ الاحتياطي ليكون قادرًا على الاتصال إلى عميل Bacula. إضافة مجموعات الملفات FileSets (الخادوم)تُعرِّف Bacula FileSet مجموعة من الملفّات أو الأدلة التي يتم تضمينها أو استثناؤها من اختيار النسخ الاحتياطي، ويتم استخدامها من قبل وظائف النسخ الاحتياطي على خادوم Bacula. إن اتبعت الدّرس الموجود في المتطلّبات الأساسيّة والذي يقوم بإعداد عناصر خادوم Bacula فأنت تمتلك مسبقًا مجموعة ملفّات FileSet تُدعى "Full Set"، إن كنت تريد تشغيل وظائف نسخ احتياطي تتضمّن كل ملف على جهاز العميل لديك فتستطيع استخدام مجموعة الملفّات FileSet هذه في وظائفك، ومع ذلك ربّما تجد غالبًا أنّك لا تريد ولا تحتاج امتلاك نسخة احتياطية لكل شيء على الخادوم، وبهذا تكفيك مجموعة فرعيّة من البيانات. عندما تكون أكثر انتقائيّة في اختيار الملفّات التي تريد تضمينها في مجموعة الملفّات FileSet ستوفّر من مساحة القرص لديك وتوفّر من الوقت الذي يحتاجه خادوم النسخ الاحتياطي للقيام بوظيفة نسخ احتياطي، وستجعل عمليّة استعادة الملفّات أبسط حيث لن يتوجب عليك البحث في مجموعة كاملة "Full Set" لإيجاد الملفّات التي تريد استعادتها. سنشرح كيفيّة إنشاء موارد مجموعة ملفّات FileSet جديدة، بحيث تستطيع أن تكون أكثر انتقائية فيما تريد نسخه احتياطيًّا. على خادوم Bacula نفتح الملف الذي يُدعى filesets.conf الموجود في دليل إعدادات مدير Bacula الذي أنشأناه: sudo vi /etc/bacula/conf.d/filesets.confنقوم بإنشاء مورد مجموعة ملفّات FileSet لكل مجموعة محدّدة من الملفّات التي نريد استخدامها في وظائف النسخ الاحتياطي، سننشئ في هذا المثال مجموعة ملفّات FileSet تشمل فقط الدليل الرئيسي home والدليل etc: FileSet { Name = "Home and Etc" Include { Options { signature = MD5 compression = GZIP } File = /home File = /etc } Exclude { File = /home/bacula/not_important } }هنالك الكثير من الأشياء التي تحدث في هذا الملف ولكن هذه بعض التفاصيل التي يجب أن تبقى في ذهننا: يجب أن يكون اسم مجموعة الملفّات FileSet فريدًاتضمين أي ملفّات أو أقراص نريد الحصول على نسخ احتياطيّة لهااستثناء أي ملفّات لا نريد النسخ الاحتياطي لها ولكن تمّ اختيارها نتيجة وجودها بداخل ملفّات مُضمَّنةنستطيع إنشاء العديد من مجموعات الملفّات FileSets إن كنّا نرغب بذلك، نقوم بالحفظ والخروج بعد الانتهاء. نحن الآن مستعدون لإنشاء وظيفة نسخ احتياطي تستخدم مجموعة ملفّاتنا الجديدة. إضافة عميل Client ووظيفة نسخ احتياطي Backup Job إلى خادوم Baculaنحن الآن جاهزون لإضافة عميلنا إلى خادوم Bacula، ولعمل هذا يجب علينا إعداد مدير Bacula مع موارد العميل والوظيفة الجديدة. نفتح الملف conf.d/clients.conf: sudo vi /etc/bacula/conf.d/clients.conf1. إضافة مورد عميل Client Resourceيقوم مورد العميل بضبط المدير Director مع المعلومات التي يحتاجها للاتصال إلى مضيف العميل، يتضمّن هذا الاسم، العنوان، وكلمة السّر لعفريت ملفّات العميل Client File Daemon. نقوم بلصق التعريف التالي لمورد العميل إلى ذلك الملف، تأكد من أن تضع اسم مضيف العميل لديك، FQDN الخاص، وكلمة السّر (من ملف العميل bacula-fd.conf): Client { Name = ClientHost-fd Address = client_private_FQDN FDPort = 9102 Catalog = MyCatalog Password = "IrIK4BHRA2o5JUvw2C_YNmBX_70oqfaUi" # password for Remote FileDaemon File Retention = 30 days # 30 days Job Retention = 6 months # six months AutoPrune = yes # Prune expired Jobs/Files }نحتاج لعمل هذا مرّة واحدة فقط لكل عميل. 2. إنشاء وظيفة نسخ احتياطي backup jobتُعرِّف وظيفة النسخ الاحتياطي backup job تفاصيل حول العميل والبيانات التي يجب عمل نسخ احتياطي لها، ويجب أن يملك اسمًا فريدًا. نلصق وظيفة النسخ الاحتياطي التالية إلى الملف، مع وضع اسم مضيف العميل لدينا بدلًا من كلمة ClientHost: Job { Name = "BackupClientHost" JobDefs = "DefaultJob" Client = ClientHost-fd Pool = RemoteFile FileSet="Home and Etc" }يقوم هذا بإنشاء وظيفة نسخ احتياطي تُدعى "BackupClientHost" والتي تقوم بإنشاء نسخة احتياطيّة للدليلين home وetc من مضيف العميل، كما هو مُعرَّف في مجموعة الملفّات FileSet التي تُدعى "Home and Etc"، ستستخدم هذه الوظيفة الإعدادات المُحدّدة في تعريف الوظائف JobDefs الذي يُدعى "DefaultJob" وموارد الحوض Pool الذي يُدعى "RemoteFile"، وكلاهما مُعرَّف في الملف الرئيسي bacula-dir.conf، الوظائف التي تُحدِّد JobDefs = "DefaultJob" يتم تشغيلها أسبوعيًّا بشكل افتراضي. عند الانتهاء نحفظ الملف ونخرج منه. 3. التحقق من إعدادات المدير Directorفلنتحقّق من عدم وجود أخطاء صياغة في ملف إعدادات المدير لدينا: sudo bacula-dir -tc /etc/bacula/bacula-dir.confإن تمّت إعادتنا إلى مُحث الصدفة shell prompt فهذا يعني أنّه لا توجد أخطاء صياغة في ملفّات إعدادات مدير Bacula. 4. إعادة تشغيل مدير Baculaولتطبيق التغييرات التي قمنا بها نعيد تشغيل مدير Bacula: sudo service bacula-director restartيكون العميل أو المضيف عن بعد مُعدًّا الآن ليتم نسخه احتياطيًّا عن طريق خادوم Bacula. اختبار اتصال العميلينبغي أن نتحقّق من قدرة مدير Bacula على الاتصال بعميل Bacula. ندخل إلى Bacula Console على خادوم Bacula: sudo bconsole Select Client resource: ClientHost-fd The defined Client resources are: 1: BackupServer-fd 2: ClientHost-fd Select Client (File daemon) resource (1-2): 2ينبغي أن تعود إلينا حالة عفريت ملفّات العميل Client File Daemon، وإن لم يحدث ذلك ووجد خطأ بالاتصال فهنالك مشكلة ما في إعدادات خادوم Bacula أو عفريت ملفّات العميل Client File Daemon. اختبار وظيفة النسخ الاحتياطيفلنقم بتشغيل وظيفة النسخ الاحتياطي للتأكد من أنّها تعمل. نستخدم هذا الأمر على خادوم Bacula من خلال الـ Console: runسيتم حثّنا على اختيار الوظيفة التي نريد تشغيلها، نختار الوظيفة التي أنشأناها سابقًا (في مثالنا "4. BackupClientHost"): Select Job resource: BackupClientHost The defined Job resources are: 1: BackupLocalFiles 2: BackupCatalog 3: RestoreLocalFiles 4: BackupClientHost Select Job resource (1-4): 4وفي مُحث prompt التأكيد نختار "yes": Confirmation prompt: OK to run? (yes/mod/no): yesالتحقق من الرسائل والحالةسيخبرنا Bacula بعد تشغيل الوظيفة أنّنا نمتلك رسائل، وهي عبارة عن خَرْج تمّ توليده من قبل الوظائف قيد التشغيل. نتحقّق من الرسائل بكتابة: messagesينبغي أن تخبرنا الرسائل أنّه لم يتم إيجاد تسجيل لوظيفة نسخ احتياطي كامل سابقة "No prior Full backup Job record found" وأنّه بدأت وظيفة النسخ الاحتياطي لدينا، إن وُجِدَت أيّة أخطاء أخرى فهناك خطأ ما ويجب أن تعطيك هذه الأخطاء تلميحًا عن سبب عدم عمل الوظيفة. ومن الطرق الأخرى لرؤية حالة الوظيفة هي التحقّق من حالة المدير Director، ولعمل هذا نكتب الأمر التالي في bacula console: status directorإن كان كل شيء على ما يرام فينبغي أن نرى أنّ وظيفتنا قيد التشغيل أو تمّت مقاطعتها بحالة "OK". القيام باستعادة ملفات Restoreيجب أن نختبر في المرّة الأولى لإعداد عميل Bacula جديد أنّ استعادة الملفّات تعمل بشكل صحيح. إن أردنا القيام باستعادة ملفّات نستخدم الأمر restore في Bacula Console: restore allستظهر قائمة للاختيار مع العديد من الخيارات المختلفة، والتي تُستخدم لتحديد مجموعة النسخ الاحتياطي التي نريد الاستعادة منها، وبما أنّنا نملك نسخة احتياطيّة واحدة فقط سنختار الخيار 5 وهو اختيار أحدث نسخة احتياطيّة "Select the most recent backup": Select item (1-13): 5يجب بعدها أن نحدّد العميل الذي نريد الاستعادة إليه، نريد الاستعادة للمضيف عن بعد الذي قمنا بإعداده للتو، وهو في مثالنا "ClientHost-fd": Select the Client: ClientHost-fd Defined Clients: 1: BackupServer-fd 2: ClientHost-fd Select the Client (1-2): 2ستُعرَض الآن لنا شجرة ملفّات افتراضية مع كامل بنية الدليل الذي قمنا بالنسخ الاحتياطي له، تسمح هذه الواجهة المشابهة لواجهة الصدفة shell للأوامر البسيطة بتحديد وإلغاء تحديد الملفّات التي نريد استعادتها. ولأنّنا حدّدنا أنّنا نريد استعادة كافّة الملفّات "restore all"، فجميع الملفّات الموجودة في النسخة الاحتياطيّة مُحدّدة لاستعادتها، الملفّات المحدّدة مسبوقة بالحرف *. ولتحسين اختيار الملفّات، نستطيع التصفّح وسرد الملفّات باستخدام الأمرين "ls" و"cd"، تحديد الملفّات باستخدام الأمر "mark"، وإلغاء تحديد الملفّات باستخدام الأمر "unmark"، وتوجد قائمة من الأوامر متاحة بكتابة "help" في الـ console. عند الانتهاء من اختيار الملفّات التي نريد استعادتها نتابع بكتابة ما يلي: doneنقوم بتأكيد أنّنا نرغب بتنفيذ وظيفة الاستعادة: OK to run? (yes/mod/no): yesالتحقق من الرسائل والحالةيجب علينا التحقّق من الرسائل وحالة المدير بعد تشغيل وظيفة استعادة الملفّات، كما هو الحال مع وظيفة النسخ الاحتياطي. نتحقّق من الرسائل بكتابة ما يلي: messagesينبغي أن نجد رسالة تخبرنا أنّ وظيفة استعادة الملفّات قد بدأت أو تمّت مقاطعتها بحالة "Restore OK"، إن وُجِدَت أيّة أخطاء أخرى فهناك خطأ ما ويجب أن تعطيك هذه الأخطاء تلميحًا عن سبب عدم عمل الوظيفة. وكما وجدنا سابقَا فإنّ التحقّق من حالة المدير هو طريقة رائعة لنرى حالة وظيفة استعادة الملفّات: status directorعند الانتهاء من استعادة الملفّات نكتب exit لمغادرة Bacula Console: exitإن سار كل شيء على ما يرام فسنجد الملفّات التي تمّت استعادتها على مضيف العميل في الدليل /bacula/restore، إن كنت فقط تختبر عمليّة استعادة الملفّات فاحذف محتويات هذا الدليل. الخاتمةتمتلك الآن خادوم Bacula يقوم بالنسخ الاحتياطي للملفّات من عميل Bacula عن بعد، تأكّد من أن تراجع إعداداتك حتى تصبح متأكدًا من أنّك تقوم بالنسخ الاحتياطي لمجموعة الملفّات FileSets الصحيحة، وبجدول ملائم لاحتياجاتك. الخطوة القادمة التي يجب فعلها هي أن تعيد الخطوات السابقة من أجل خواديم Ubuntu الإضافية التي تريد عمل نسخ احتياطي لها. ترجمة -وبتصرّف- لـ How To Back Up an Ubuntu 14.04 Server with Bacula لصاحبه Mitchell Anicas.
  20. سنتعلّم في هذا الدّرس كيفيّة الحصول على شهادة SSL من سلطة شهادات تجاريّة (Commercial Certificate Authority (CA وكيفيّة تثبيتها، تسمح شهادات SSL لخواديم الويب بتشفير حركة مرور بياناتها traffic وتُوفِّر آليّة للتحقّق من هويّات الخواديم من أجل الزوّار، إنّ الميزة الأساسيّة لشراء شهادة SSL من سلطة شهادات تجاريّة (CA) موثوقة عن الشهادات المُوقَّعة ذاتيًّا self-signed أنّه لن يتم عرض تحذير مُخيف للزوّار حول عدم القدرة على التحقّق من هويّة موقعنا. يغطّي هذا الدرس كيفيّة الحصول على شهادة SSL من سلطات الشهادات الموثوقة التالية: GoDaddyRapidSSL via Namecheapبإمكانك أيضًا استخدام أي سلطة شهادات CA من اختيارك. سنشرح بعد أن حصلنا على شهادة SSL كيفيّة تثبيتها على خواديم ويب Nginx و Apache HTTP. سنشاهد في هذا الدّرس كيفيّة الحصول على شهادة SSL مُفردة النطاق أو wildcard من GoDaddy وRapidSSL، ولكنّ الحصول على الأنواع الأخرى من الشهادات مماثل تمامًا. توليد CSR ومفتاح خاص Private Keyبعد أن تقوم بتجهيز المتطلبات الأساسيّة وتختار نوع الشهادة التي نريد الحصول عليها، تحتاج لتوليد طلب توقيع الشهادة (certificate signing request (CSR ومفتاح خاص private key. إن كنت تخطّط لاستخدام Apache HTTP أو Nginx كخادوم ويب لديك فاستخدم openssl لتوليد CSR ومفتاحك الخاص على خادومك الويب، سنبقي في هذا الدّرس كافّة الملفات المرتبطة بهذا في الدليل الرئيسي home directory ولكن لا تتردد في تخزينها في أي موقع آمن على خادومك: cd ~نقوم بتنفيذ هذا الأمر لتوليد مفتاح خاص يُدعى example.com.key و CSR يُدعى example.com.csr (ضع اسم نطاقك بدلًا من example.com): openssl req -newkey rsa:2048 -nodes -keyout example.com.key -out example.com.csrعند هذه النقطة سيتم حثنا على إدخال عدّة أسطر من المعلومات تُضمَّن في طلب شهادتنا، إنّ الجزء الأهم منها هو حقل الاسم الشائع Common Name والذي يجب أن يُطابق الاسم الذي نرغب باستخدام الشهادة معه، على سبيل المثال example.com ،www.example.com، أو (بالنسبة لطلب شهادة wildcard) *.example.com، إن كنت تُخطّط للحصول على شهادة OV أو EV فتأكّد من أن تتوافق كافّة الحقول الأخرى بدقة مع بيانات منظمتك أو عملك. على سبيل المثال: Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:New York Locality Name (eg, city) []:New York Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:example.com Email Address []:sammy@example.comسيقوم هذا بتوليد ملفات key. و csr.، حيث يكون الملف key. هو مفتاحنا الخاص ويجب أن نبقيه في مكان آمن، والملف csr. هو الذي يجب أن نرسله إلى سلطة الشهادات لطلب شهادة SSL. نحتاج إلى نسخ ولصق CSR الخاصّة بنا عند تقديم طلب الشهادة إلى سلطة الشهادات، نستخدم هذا الأمر لطباعة محتويات ملف CSR لدينا (ضع اسم ملفّك بدلًا من التالي): cat example.com.csrنحن الآن مستعدون لشراء شهادة من سلطة الشهادات، سنعرض هنا مثالين، GoDaddy و RapidSSL عبر Namecheap، ولكن لك الحرية بالحصول على الشهادة من أي بائع آخر. مثال سلطة الشهادات الأول: RapidSSL via Namecheapتوفّر Namecheap طريقة لشراء شهادات SSL من مجموعة متنوعة من سلطات الشهادات، سنشرح عمليّة الحصول على شهادة نطاق مُفرَد من RapidSSL، ولكن إن أردت نوعًا مختلفًا من الشهادات فبإمكانك فعل ذلك. ملاحظة: إن طلبنا شهادة نطاق مُفرَد من RapidSSL من أجل النطاق الفرعي www لنطاقنا (على سبيل المثال www.example.com) فسيقومون بإصدار الشهادة لنا مع SAN لنطاقنا الأساسي، فإن كان طلب شهادتنا على سبيل المثال من أجل www.example.com فستعمل الشهادة الصادرة من أجل www.example.com و example.com. اختيار وشراء الشهادةنذهب إلى صفحة Namecheap لشهادات SSL . نستطيع هنا البدء في اختيار مستوى التحقّق، نوع الشهادة ("Domains Secured") أو ("CA Brand"). سنضغط في مثالنا على زر مقارنة المنتجات Compare Products في مربّع التحقّق من النطاق "Domain Validation"، بعدها نستطيع إيجاد "RapidSSL" والضغط على زر إضافة إلى السلّة Add to Cart. عند هذه النقطة يجب علينا التسجيل في Namecheap أو تسجيل الدخول إليه، وإنهاء عمليّة الدفع. طلب الشهادةنذهب بعد أن دفعنا من أجل الشهادة التي اخترناها إلى الرابط Manage SSL Certificates الموجود تحت القسم "Hi Username". سنشاهد هنا قائمة بكامل شهادات SSL التي اشتريناها عبر Namecheap، نضغط على رابط التفعيل الآن Activate Now من أجل الشهادة التي نريد استخدامها. نختار الآن برمجيّة خادوم الويب لدينا والتي تُحدِّد تنسيق الشهادة التي سيسلمها Namecheap لنا، الخيارات التي نختارها بشكل شائع هي "Apache + MOD SSL"، "nginx"، أو "Tomcat". نلصق CSR الخاصة بنا في المربّع ونضغط بعدها زر التالي Next. يجب أن نكون الآن في خطوة اختيار المُصادِق "Select Approver" من العمليّة، والتي سترسل بريد إلكتروني لطلب التحقّق إلى عنوان في تسجيل WHOIS لنطاقنا أو إلى عنوان من نوع مدير administrator للنطاق الذي نريد أن نحصل على شهادة له، نختار العنوان الذي نريد أن نرسل إليه البريد الإلكتروني للتحقّق. نقوم بتزويد معلومات التواصل الإداريّة "Administrative Contact Information" ونضغط على زر تقديم الطلب Submit order. التحقق من النطاقسيتم عند هذه النقطة إرسال بريد إلكتروني إلى عنوان المُصادِق "approver"، نفتح البريد الإلكتروني ونصادق على طلب الشهادة. تنزيل الشهاداتبعد المُصادَقة على الشهادة سيتم إرسالها عبر البريد الإلكتروني إلى القسم التقني Technical Contact، ستكون الشهادة الصادرة لنطاقنا وشهادة سلطة الشهادات الوسيطة CA's intermediate certificate في أسفل رسالة البريد الإلكتروني. ننسخها ونحفظها إلى خادومنا في نفس المكان الذي وضعنا فيه CSR ومفتاحنا الخاص. نقوم بتسمية الشهادة باسم النطاق مُضافًا إليه اللاحقة crt.، مثل example.com.crt، وتسمية الشهادة الوسيطة intermediate.crt. تكون الشهادة الآن جاهزة للتثبيت على خادوم الويب لدينا. مثال سلطة الشهادات الثاني: GoDaddyإنّ GoDaddy هي سلطة شهادات شائعة تملك كافّة أنواع الشهادات الأساسية، سنشرح عمليّة الحصول على شهادة نطاق مُفرَد، ولكن إن أردت نوعًا مختلفًا من الشهادات فبإمكانك فعل ذلك. اختيار وشراء الشهادةنذهب إلى صفحة GoDaddy لشهادات SSL. ننزل للأسفل ونضغط على زر البدء Get Started. نختار نوع شهادة SSL الذي نريده من القائمة المنسدلة: نطاق مُفرَد single domainنطاقات متعدّدة (multidomain (UCCwildcard نختار بعدها نوع الخطّة plan: نطاق domainمُنظَّمة organizationتحقّق مُوسَّع extended validationثم نختار المدى term (مُدّة الصلاحية). نضغط بعدها على زر إضافة إلى السلّة Add to Cart. نُراجع طلبنا الحالي ثم نضغط على المتابعة إلى الدفع Proceed to Checkout. ومن ثمّ نكمل التسجيل وعمليّة الدفع. طلب الشهادةبعد إكمال طلبنا نضغط على زر SSL Certificates* (أو نضغط على My Account > Manage SSL Certificates الموجودة في الزاوية العلوية اليمنى). نقوم بإيجاد شهادة SSL التي اشتريناها للتو ونضغط على زر الإعداد Set Up، إن لم تستخدم GoDaddy من قبل من أجل شهادات SSL فسيتم حثك على إعداد مُنتَج "SSL Certificates" وربط طلب شهادتك الأخيرة مع المُنتَج (نضغط على زر Set Up الأخضر وننتظر عدّة دقائق قبل تحديث متصفّحنا). بعد أن تتم إضافة مُنتَج "SSL Certificates" إلى حسابنا في GoDaddy ينبغي أن نرى شهادتنا الجديدة "New Certificate" وزر التنفيذ "Launch"، نضغط على الزر Launch الموجود بجانب شهادتنا الجديدة. نقوم بتقديم CSR الخاص بنا عن طريق لصقه في المربع، تُستخدَم خوارزميّة SHA-2 افتراضيًّا. نضع علامة في خانة التأشير I agree ونضغط على زر طلب الشهادة Request Certificate. التحقق من النطاقيجب الآن أن نُثبِت أنّنا نمتلك تحكّمًا بنطاقنا ونزوّد GoDaddy ببعض المستندات، تقوم GoDaddy بإرسال رسالة بريد إلكتروني للتحقّق من ملكيّة النطاق إلى العنوان الموجود في تسجيل WHOIS لنطاقنا، نتبع الخطوات الموجودة في رسائل البريد الإلكتروني التي تصلنا ونُصرِّح بإصدار الشهادة. تنزيل الشهادةبعد أن نُثبِت لـ GoDaddy أنّنا نمتلك النطاق، نتحقّق من بريدنا الإلكتروني (الذي قمنا من خلاله بالتسجيل في GoDaddy) بحثًا عن رسالة تقول أنّه تم إصدار شهادة SSL الخاصة بنا، نفتحها ونتبع رابط تنزيل الشهادة (أو نضغط على زر Launch بجانب شهادة SSL التي نريدها في لوحة تحكّم GoDaddy). نضغط الآن على زر التنزيل Download. نختار برمجيّة الخادوم التي نستخدمها من القائمة المنسدلة لنوع الخادوم Server type، إن كنّا نستخدم Apache HTTP أو Nginx نختار "Apache" ثم نضغط على زر تنزيل الملف المضغوط Download Zip File. نستخرج الملف المضغوط، الذي ينبغي أن يحتوي على ملفين crt.، أحدهما شهادة SSL الخاصّة بنا (التي ينبغي أن تملك اسمًا عشوائيًّأ) وحزمة bundle شهادة GoDaddy الوسيطة (gd_bundle-g2-1.crt)، نقوم بنسخهما إلى خادوم الويب لدينا، ونعيد تسمية الشهادة إلى اسم نطاقنا مع إضافة اللاحقة crt.، على سبيل المثال example.com.crt، ونعيد تسمية حزمة الشهادة الوسيطة إلى intermediate.crt. تكون الشهادة الآن جاهزة للتثبيت على خادوم الويب لدينا. تثبيت الشهادة على خادوم الويب لديناينبغي بعد الحصول على شهادتنا من سلطة الشهادات التي نختارها أن نقوم بتثبيتها على خادوم الويب لدينا، يتضمّن هذا إضافة بعض الأسطر المتعلّقة بـ SSL لملفّات إعدادات خادومنا. سنغطي في هذا القسم الإعدادات الأساسيّة لخادوم Nginx و Apache HTTP على Ubuntu. سنفترض الأمور التالية: يتوضّع المفتاح الخاص وشهادة SSL والشهادات الوسيطة لسلطة الشهادات-إن كان ذلك قابلًا للتطبيق- في الدليل الرئيسي على المسار home/sammy/يُدعى المفتاح الخاص باسم example.com.keyتُدعى شهادة SSL باسم example.com.crtتُوجد الشهادة أو الشهادات الوسيطة لسلطة الشهادات في ملف يُدعى intermediate.crtإن كنت تملك جدار ناري مُمكَّنًا لديك فتأكّد من أنّه يسمح بالمنفذ 443 (منفذ HTTPS)ملاحظة: يجب في البيئة الحقيقيّة تخزين هذه الملفّات في مكان يستطيع فقط المستخدم الذي يُشغِّل عملية خادوم الويب الرئيسيّة (عادة root) الوصول إليه، ينبغي الاحتفاظ بالمفتاح الخاص في مكان آمن. خادوم Nginxإن كنت ترغب باستخدام شهادتك مع خادوم Nginx على Ubuntu فاتبع هذا القسم. ينبغي في Nginx إن كانت سلطة الشهادات قد أعطتنا شهادة وسيطة أن نقوم بإنشاء ملف شهادة مُفرَد محمي بالسلاسل chained يحتوي على شهادتنا والشهادات الوسيطة لسلطة الشهادات. نذهب إلى الدليل الذي يحوي مفتاحنا الخاص، الشهادة، وشهادة سلطة البيانات الوسيطة (أي الملف intermediate.crt)، سنفترض أنّها في الدليل الرئيسي على سبيل المثال: cd ~بافتراض أنّ ملف الشهادة يُدعى example.com.crt نستخدم هذا الأمر لإنشاء ملف مُدمَج يُدعى example.com.chained.crt (نضع اسم نطاقنا بدلًا من example.com): cat example.com.crt intermediate.crt > example.com.chained.crtنذهب الآن إلى دليل إعدادات كتلة block خادوم Nginx، وبافتراض أنّه موجود في المسار etc/nginx/sites-enable/ نستخدم هذا الأمر للانتقال إليه: cd /etc/nginx/sites-enabledبافتراض أنّنا نريد إضافة SSL إلى ملف كتلة الخادوم الافتراضي default نفتح الملف من أجل تحريره: sudo vi defaultنبحث عن الأمر التوجيهي listen ونقوم بتعديله بحيث يبدو كما يلي: listen 443 ssl;نبحث بعدها عن الأمر التوجيهي server_name ونتأكد من أنّ قيمته مُطابِقة لاسم شهادتنا، نُضيف أيضًا الأوامر التوجيهيّة ssl_certificate و ssl_certificate_key لتحديد المسارات لشهادتنا وتحديد ملفّات المفاتيح الخاصّة (نضع الأسماء الموجودة لدينا بدلًا من example.com): server_name example.com; ssl_certificate /home/sammy/example.com.chained.crt; ssl_certificate_key /home/sammy/example.com.key;ولنسمح فقط بالشيفرات ciphers وميفاقات SSL protocols الأكثر أمانًا نُضيف الأسطر التالية إلى الملف: ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;إن أردنا إعادة توجيه المرور عبر HTTP إلى HTTPS نستطيع إضافة هذه الكتلة الإضافيّة للخادوم في أعلى الملف (نضع معلوماتنا بدلًا من example.com): server { listen 80; server_name example.com; rewrite ^/(.*) https://example.com/$1 permanent; }نقوم بعدها بالحفظ والخروج. نعيد تشغيل خادوم Nginx الآن لتحميل الإعدادات الجديدة وتمكين TLS/SSL عبر HTTPS: sudo service nginx restartنختبر ذلك بالوصول إلى موقعنا عبر HTTPS، على سبيل المثال https://example.com. خادوم Apacheإن كنت ترغب باستخدام شهادتك مع خادوم Apache على Ubuntu فاتبع هذا القسم. نقوم بعمل نسخة احتياطيّة لملف إعداداتنا عن طريق نسخه، وبافتراض أنّ خادومنا يعمل على ملف إعدادات المُضيف الوهمي virtual الافتراضي، etc/apache2/sites-available/000-default.conf/، نستخدم هذه الأوامر لعمل النسخة: cd /etc/apache2/sites-available cp 000-default.conf 000-default.conf.origنفتح بعدها الملف لتحريره: sudo vi 000-default.confنبحث عن المُدخَل <VirtualHost *:80> ونقوم بتعديله بحيث يستمع خادوم الويب لدينا على المنفذ 443: <VirtualHost *:443>نقوم بعدها بإضافة الأمر التوجيهي ServerName إن لم يكن موجودًا مُسبقًا (نضع اسم نطاقنا هنا): ServerName example.comنضيف بعد ذلك الأسطر التالية لتحديد شهادتنا ومسارات المفاتيح (نضع مسارنا الفعلي هنا): SSLEngine on SSLCertificateFile /home/sammy/example.com.crt SSLCertificateKeyFile /home/sammy/example.com.keyإن كُنّا نستخدم Apache 2.4.8 أو أكثر نُحدِّد حزمة الشهادة الوسيطة لسلطة الشهادات بإضافة هذا السطر (نضع المسار الفعلي لدينا): SSLCACertificateFile /home/sammy/intermediate.crtإن كُنّا نستخدم إصدار أقدم من Apache نُحدِّد حزمة الشهادة الوسيطة لسلطة الشهادات بإضافة هذا السطر (نضع المسار الفعلي لدينا): SSLCertificateChainFile /home/sammy/intermediate.crtعند هذه النقطة أصبح خادومنا مُعدًّا ليستمع إلى HTTPS فقط (المنفذ 443)، لذا لن يتم تخديم طلبات HTTP (المنفذ 80)، لإعادة توجيه طلبات HTTP إلى HTTPS نضيف ما يلي إلى أعلى الملف (نكتب اسم نطاقنا بدلًا من example.com): <VirtualHost *:80> ServerName example.com Redirect permanent / https://example.com/ </VirtualHost>نقوم بالحفظ والخروج. نقوم بتمكين وحدة Apache SSL بتنفيذ هذا الأمر: sudo a2enmod sslنعيد تشغيل خادوم Apache الآن لتحميل الإعدادات الجديدة وتمكين TLS/SSL عبر HTTPS: sudo service apache2 restartنختبر ذلك بالوصول إلى موقعنا عبر HTTPS، على سبيل المثال https://example.com، نريد أيضًا اختبار الاتصال عبر HTTP، مثل http://example.com لنضمن أنّ إعادة التوجيه تعمل بشكل صحيح. الخاتمةنمتلك الآن فكرة جيّدة عن كيفيّة إضافة شهادة SSL موثوقة لتأمين خادوم الويب لدينا، احرص على أن تتسوّق من سلطة شهادات تجعلك مسرورًا معها. ترجمة -وبتصرّف- لـ How To Install an SSL Certificate from a Commercial Certificate Authority لصاحبه Mitchell Anicas.
  21. سنتعلّم في هذا الدّرس المفاهيم الأساسيّة التي نحتاجها قبل الحصول على شهادة SSL من سلطة شهادات تجاريّة Commercial Certificate Authority CA، تسمح شهادات SSL لخواديم الويب بتشفير حركة مرور بياناتها traffic وتُوفِّر آليّة للتحقّق من هويّات الخواديم من أجل الزوّار، إنّ الميزة الأساسيّة لشراء شهادة SSL من سلطة شهادات تجاريّة (CA) موثوقة عن الشهادات المُوقَّعة ذاتيًّا self-signed أنّه لن يتم عرض تحذير مُخيف للزوّار حول عدم القدرة على التحقّق من هويّة موقعنا. يغطّي هذا الدرس المتطلبات الأساسيّة التي يجب التأكد منها قبل الحصول على شهادة SSL، ويشرح الأنواع المختلفة للشهادات. المتطلبات الأساسيةهنالك العديد من المتطلبات التي يجب التأكد منها قبل محاولة الحصول على شهادة SSL من سلطة شهادات تجاريّة، سيغطي هذا القسم الأمور التي نحتاجها ليتم إصدار شهادة SSL لنا من معظم سلطات الشهادات التجارية. الماليجب علينا شراء شهادات SSL الصادرة عن سلطات الشهادات التجاريّة، تتضمّن البدائل المجانيّة لها الشهادات المُوقَّعة ذاتيًّا self-signed أو شهادات StartSSL، ومع ذلك فإنّ الشهادات المُوقَّعة ذاتيًّا غير موثوقة من قبل أيّة برمجيات، ولا يُمكِن استخدام شهادات StartSSL لأغراض تجاريّة. اسم نطاق Domain مسجلينبغي قبل الحصول على شهادة SSL أن نملك اسم نطاق مُسجَّل والذي نرغب باستخدام الشهادة معه، إن كُنّا لا نمتلك اسم نطاق مُسجَّل فبإمكاننا تسجيله باستخدام أحد مُسجِّلات اسم النطاق المتوفِّرة (مثل Namecheap، GoDaddy، إلخ..). حقوق التحقق من النطاقيجب من أجل العمليّة الأساسيّة للتحقّق من النطاق أن نملك نفاذًا إلى أحد عناوين البريد الإلكتروني على تسجيل WHOIS لنطاقنا أو إلى عنوان بريد إلكتروني من نمط مُدير admin على النطاق نفسه، تقوم سلطات الشهادات التي تُصدِر شهادات SSL نموذجيًّا بالتحقّق من التحكم بالنطاق عن طريق إرسال بريد إلكتروني للتحقّق إلى أحد عناوين البريد الإلكتروني على تسجيل WHOIS لنطاقنا، أو إلى عنوان بريد إلكتروني من نمط مدير عام على النطاق ذاته، توفّر بعض سلطات الشهادات طرق بديلة للتحقّق من النطاق، مثل DNS أو التحقّق المعتمد على HTTP والتي هي مواضيع خارج نطاق درسنا. إن كنت ترغب في إصدار شهادة SSL مع تحقّق من المنظّمة (Organization Validation (OV أو تحقّق مُوسَّع (Extended Validation (EV فيجب عليك تزويد سلطات الشهادات بأوراقك لتأسيس هوية قانونيّة لمالك الموقع من بين الأشياء الأخرى. خادوم الويبسنحتاج بالإضافة للنقاط المذكورة سابقًا إلى خادوم ويب لتثبيت شهادة SSL عليه، وهو الخادوم القابل للوصول إليه عبر اسم النطاق الذي سنصدر شهادة SSL له، سيكون نموذجيًّا خادوم Apache HTTP، Nginx، HAProxy، أو Varnish، إن كنت تحتاج المساعدة في إعداد خادوم ويب قابل للوصول من خلال اسم النطاق المُسجَّل لديك فقم باتباع الخطوات التالية: إعداد خادوم ويب من اختيارك، على سبيل المثال خادوم (LEMP (Nginx أو (LAMP (Apache.إعداد النطاق ليستخدم أسماء الخواديم nameservers الملائمة.إضافة تسجيلات DNS records لخادوم الويب إلى أسماء الخواديم لديك.اختيار سلطة الشهاداتإن لم تكن متأكّدًا من سلطة الشهادات التي تريد استخدامها فهنالك القليل من العوامل المهمّة التي يجب أن تأخذها بعين الاعتبار، وكنظرة عامّة فإنّ الشيء الأكثر أهمية أن تكون سلطة الشهادات التي تختارها تعطيك الميزات التي تريدها بالسعر الذي يناسبك، يُركّز هذا القسم بشكل أكبر على الميزات التي يجب أن يعلم بها مشترو شهادات SSL أكثر من الأسعار. عضويات برنامج الشهادات الجذرية Rootإنّ النقطة الأهم هي أن تكون سلطة الشهادات التي نختارها عضوًا في برامج الشهادات الجذريّة لأنظمة التشغيل ومتصفحات الويب الأكثر استخدامًا، أي بمعنى أن تكون سلطة شهادات موثوقة وشهادتها الجذريّة موثوقة من قبل معظم المتصفّحات والبرمجيات الأخرى، فإن كانت شهادة SSL لموقعنا مُوقَّعة من قبل سلطة شهادات موثوقة فستعتبر هويتها صالحة من قبل البرمجيّات التي تثق بسلطة الشهادات، وهي على النقيض تمامًا من شهادات SSL المُوقَّعة ذاتيًّا والتي تُزوّدنا أيضًا بقدرات التشفير ولكنّها مصحوبة بتحذيرات التحقّق من الهوية التي لا تسر معظم زوّار موقعنا. إنّ أغلب سلطات الشهادات التي سنصادفها هي عضو من برامج الشهادات الجذريّة الشائعة، وستكون متوافقة مع 99% من المتصفحات، ولكن لن يضرّنا أن نتحقّق من ذلك قبل شراء الشهادة، تزوّدنا شركة Apple على سبيل المثال بلائحة من شهادات SSL الجذريّة الموثوقة لأجل IOS8 هنا. أنواع الشهاداتيجب أن نتأكّد من اختيار سلطة شهادات تزوّدنا بنوع الشهادة الذي نريده، تُقدّم العديد من سلطات الشهادات أشكال مختلفة من أنواع الشهادات في إطار مجموعة من الأسماء والأسعار والتي كثيرًا ما تكون مربكة، وهذا وصف مختصر لكل نوع: نطاق مُفرَد Single Domain: يُستخدَم من أجل النطاق المُفرَد، مثل example.com، نلاحظ أنّه لا يتم تضمين النطاقات الفرعيّة subdomains مثل www.example.comWildcard: تُستخدَم من أجل النطاق وأي نطاقات فرعيّة له، على سبيل المثال يُمكِن استخدام شهادة wildcard لِـ *.example.com أيضًا من أجل www.example.com وstore.example.comالنطاقات المُتعدّدة Multiple Domain: وهي معروفة باسم شهادة SAN أو UC، ويمكن استخدامها مع النطاقات المُتعدّدة والنطاقات الفرعيّة التي تتم إضافتها إلى حقل الاسم البديل للموضوع Subject Alternative Name، فعلى سبيل المثال يُمكِن استخدام شهادة نطاقات متعدّدة مُفرَدة مع example.com، www.example.com، و example.netوبالإضافة لأنواع الشهادات المذكورة آنفًا تُوجَد مستويات مختلفة من التحقّق التي توفّرها سلطات الشهادات، وسنتحدّث عنها هنا: التحقّق من النطاق (Domain Validation (DV: يتم إصدار شهادات DV بعد أن تتحقّق سلطة الشهادات أنّ طالب الشهادة يملك أو يتحكّم بالنطاق المطلوب.التحقّق من المُنظّمة (Organization Validation (OV: يُمكِن إصدار شهادات OV فقط بعد أن تتحقّق سلطة الشهادات من الهوية القانونية لطالب الشهادة.التحقّق المُوسَّع (Extended Validation (EV: يُمكِن إصدار شهادات EV فقط بعد أن تتحقّق سلطة الشهادات من الهوية القانونيّة لطالب الشهادة مع عدّة أشياء أخرى وفق مجموعة صارمة من الإرشادات، إنّ الغرض من هذا النوع من الشهادات هو توفير ضمان إضافي عن قانونيّة هوية مُنظّمتك بالنسبة لزوّار موقعك، يُمكِن أن تكون شهادات EV مُفردة أو متعدّدة النطاقات ولكن لا يمكن أن تكون wildcard.ميزات إضافيةتوفّر العديد من سلطات الشهادات مجموعة كبيرة ومتنوعة من الميزات الإضافيّة لتمييز نفسها عن بقيّة بائعي شهادات SSL، بعض هذه الميزات قد توفّر عليك المال، لذا من المهم أن تعرف احتياجاتك مقابل العروض قبل أن تقوم بالشراء، على سبيل المثال تشمل الميزات التي يجب البحث عنها إعادة إصدار شهادة مجانيّة أو شهادة بسعر شهادة نطاق مُفرَد وتعمل من أجل www. والاسم الأساسي للنطاق، مثل www.example.com مع شهادة SAN من example.com الخاتمةتعلّمنا في هذا الدّرس المفاهيم الأساسيّة للحصول على شهادات SSL من سلطة شهادات تجاريّة، والمتطلّبات الأساسيّة التي نحتاجها قبل شرائها، وتحدّثنا عن العوامل التي يجب أن نأخذها بعين الاعتبار عند اختيار سلطة شهادات تجاريّة. ترجمة -وبتصرّف- لـ How To Install an SSL Certificate from a Commercial Certificate Authority لصاحبه Mitchell Anicas.
  22. إنّ التخزين المؤقّت Caching للمحتوى بشكل ذكي هو واحد من أكثر الطرق فعاليّة لتحسين التجربة لزوّار موقعنا، إنّ التخزين المؤقّت Caching، أو تخزين المحتوى بشكل مؤقّت من الطلبات السّابقة، هو جزء من لُب استراتيجيّة توصيل المحتوى المُنفَّذة ضمن ميفاق HTTP protocol، تستطيع المُكوِّنات عبر مسار توصيل المحتوى أن تقوم بالتخزين المؤقّت للعناصر لتسريع الطلبات اللاحقة، والتي تكون خاضعة لسياسات التخزين المؤقّت المُصرَّح عنها بالنسبة للمحتوى. سنناقش في هذا الدّرس كيفيّة اختيار سياسات التخزين المؤقّت لنضمن أن يتمكّن التخزين المؤقّت في جميع أنحاء شبكة الإنترنت من معالجة محتوانا بشكل صحيح، وسنتحدّث عن استخدام ترويسات التخزين المؤقّت، وتوظيف الاستراتيجيات المختلفة للحصول على أفضل مزيج من الأداء والمرونة. ترويسات التخزين المؤقت Caching Headersتعتمد سياسة التخزين المؤقّت على عاملين مختلفين، كيان التخزين المؤقّت والذي يُقرِّر بنفسه أن يقوم بالتخزين المؤقّت للمحتوى المقبول أم لا، فيستطيع أن يُقرِّر أن يُخزِّن بشكل مؤقّت أقل مما هو مسموح له ولا أكثر من ذلك. يتم تحديد مُعظم سلوك التخزين المؤقّت عن طريق سياسة التخزين المؤقّت، والتي تُوضَع من قبل مالك المحتوى. تتمحور هذه السياسات بشكل أساسي حول استخدام ترويسات HTTP مُحدّدة. ومع تحديثات ميفاق HTTP protocol ظهرت بعض الترويسات المختلفة التي تُركِّز على التخزين المؤقّت مع مستويات مختلفة من التعقيد، ولكنّ الترويسات التالية هي التي لا نزال بحاجة إلى الانتباه لها: Expires: إنّ الترويسة Expires واضحة جدًّا، على الرغم من أنّها محدودة المجال، فتقوم بشكل أساسي بتعيين وقت في المستقبل تنتهي فيه صلاحيّة المحتوى، وعند هذه النقطة يجب على أي طلب لهذا المحتوى أن يعود إلى الخادوم الأصل، تُستخدَم هذه الترويسة أفضل ما يُمكن كاحتياط فقط.Cache-Control: وهي البديل الأكثر حداثة للترويسة Expires ومدعومة بشكل جيّد وتقوم بتطبيق تصميم أكثر مرونة، وهي مُفضّلة تقريبًا في كل الحالات على Expires، ولكن لن يضرّنا تعيين قيمة لهما معًا، سنناقش تفاصيل الخيارات التي بإمكاننا تعيينها مع Cache-Control لاحقًا.Etag: تُستخدَم الترويسة Etag في التحقّق من التخزين المؤقّت، حيث يُزوّدنا الخادوم الأصل بترويسة Etag فريدة لأجل العناصر حينما يقوم بتخديم المحتوى في البداية، فعندما يُريد التخزين المؤقّت التحقق من المحتوى الذي يملكه عند انتهاء الصلاحيّة يستطيع إرسال الترويسة Etag التي يملكها من أجل المحتوى إلى الخادوم الأصل والذي إمّا أن يُخبر التخزين المؤقّت بأنّه يملك نفس المحتوى أو يقوم بإرسال المحتوى الجديد (مع ترويسة Etag جديدة).Last-Modified: تُحدِّد هذه الترويسة المرّة الأخيرة التي تمّ فيها تعديل العنصر، ويُمكن استخدامها كجزء من استراتيجيّة التحقّق لضمان محتوى حديث.Content-Length: بالرغم من أنّها لا تُشارِك تحديدًا في التخزين المؤقّت فإنّه من الهام تعيين قيمة لهذه الترويسة عند تعريف سياسات التخزين المؤقّت، حيث ترفض بعض البرمجيّات التخزين المؤقّت للمحتوى إن لم تكن تعلم مُسبقًا حجم هذا المحتوى الذي تحتاج لحجز مساحة له.Vary: يستخدم التخزين المؤقّت بشكل نموذجي المُضيف host المطلوب والمسار إلى الموارد كمفتاح يُخزَّن بواسطته العنصر المطلوب، يُمكِن استخدام الترويسة Vary لنخبر التخزين المؤقّت أن ينتبه إلى ترويسة إضافيّة عندما يُقرّر إذا ما كان الطلب لنفس هذا العنصر، وهي أكثر ما تستخدم لإخبار التخزين الاحتياطي أن تستخدم الترويسة Accept-Encoding كمفتاح أيضًا، بحيث يعلم التخزين المؤقّت كيف يُفرِّق بين المحتوى المضغوط compressed وغير المضغوط.نظرة جانبية على الترويسة Varyتزوّدنا الترويسة Vary بالقدرة على تخزين إصدارات مختلفة من نفس المحتوى على حساب تمييع diluting المُدخلات في التخزين المؤقّت. ففي حالة Accept-Encoding يسمح لنا إعداد الترويسة Vary بالتمييز بشكل قاطع بين المحتوى المضغوط وغير المضغوط، حيث نحتاج لهذا لتخديم هذه العناصر بشكل صحيح للمتصفّحات التي لا تستطيع التعامل مع المحتوى المضغوط، وهو ضروري من أجل توفير سهولة الاستخدام الأساسيّة، ومن إحدى السمات التي تُخبرنا بأنّ الترويسة Accept-Encoding قد تكون مُرشّحًا جيّدًا من أجل الترويسة Vary هي أنّها تمتلك فقط قيمتان أو ثلاث قيم ممكنة. يبدو عنصر مثل User-Agent للوهلة الأولى طريقة جيّدة للتمييز بين متصفّحات الحواسيب ومتصفّحات الهواتف النقّالة لتخديم إصدارات مختلفة لموقعنا، ومع ذلك وبما أنّ السلاسل النصيّة لـ User-Agent ليست معياريّة فستكون النتيجة غالبًا عدّة إصدارات من نفس المحتوى في التخزينات المؤقّتة الوسيطة مع نسبة استخدام تخزين مؤقّت Cache hit ratio ضئيلة، ينبغي استخدام الترويسة Vary باعتدال، خاصّة إن لم نكن نملك القدرة على تقليل تكرار الطلبات في التخزينات المؤقّتة الوسيطة التي نتحكّم بها (والذي قد يكون ممكنًا إن استفدنا من شبكة توصيل محتوى content delivery network على سبيل المثال). كيف تؤثر أعلام الترويسة Cache-Control على التخزين المؤقتأشرنا سابقًا إلى كيفيّة استخدام الترويسة Cache-Control من أجل مواصفات سياسة التخزين المؤقّت الحديثة، يُمكن تعيين عدد من التعليمات المختلفة لهذه السياسة باستخدام هذه الترويسة، مع فصل التعليمات المتعدّدة بواسطة الفواصل. ومن بعض خيارات Cache-Control التي نستطيع استخدامها للنص على سياسة التخزين المؤقّت للمحتوى لدينا نجد: no-cache: تُحدِّد هذه التعليمة أنّه يجب التحقّق من أي محتوى مُخزَّن مؤقّتًا عند كل طلب قبل تخديمه إلى العميل، وتقوم فعليًّا بتحديد المحتوى بأنّه قديم stale فورًا، ولكن تتيح له استخدام تقنيات إعادة التحقّق لتجنّب إعادة تنزيل كامل العنصر مرّة أخرى.no-store: تشير هذه التعليمة إلى أنّه لا يُمكن التخزين المؤقّت للمحتوى بأي طريقة، وهي ملائمة لتعيينها إن كانت الاستجابة تمثّل بيانات حسّاسة.public: تقوم بتحديد المحتوى بأنّه عام ممّا يعني أنّه يمكن التخزين المؤقّت له من قبل المتصفّح أو من قبل أي تخزينات مؤقّتة وسيطة، يتم تحديد الاستجابات بالنسبة للطلبات التي تستخدم استيثاق HTTP بأنّها خاصّة private افتراضيًّا، وتستطيع هذه الترويسة تجاوز ذلك الإعداد.private: تقوم بتحديد المحتوى بأنّه خاص private، والذي يُمكن تخزينه من قبل متصفّح المستخدم ويُمنَع تخزينه بشكل مؤقّت من قبل أي أطراف وسيطة، تستخدم هذه التعليمة غالبًا للبيانات الخاصّة بالمستخدم.max-age: يضبط هذا الإعداد الفترة العظمى التي يُمكن خلالها تخزين المحتوى بشكل مؤقّت قبل أن تجب إعادة التحقّق منه أو إعادة تحميله من الخادوم الأصل، وهو يستبدل الترويسة Expires من أجل المتصفّحات الحديثة وهو الأساس لتحديد حداثة جزء من المحتوى، تُحدَّد قيمة هذا الخيار بالثواني ووقت الحداثة الأعظمي المقبول هو سنة واحدة (31536000 ثانية).s-maxage: وهو مشابه كثيرًا للإعداد max-age بأنّه يشير للفترة الزمنيّة التي يُمكِن خلالها التخزين المؤقّت للمحتوى، ويكمن الفرق في أنّ هذا الخيار يُطبَّق فقط على التخزينات المؤقّتة الوسيطة، يسمح جمعه مع الخيار السابق ببناء سياسة أكثر مرونة.must-revalidate: يُشير هذا الخيار إلى أنّه يجب إطاعة معلومات الحداثة المنصوص عليها من خلال max-age، s-maxage، أو الترويسة Expires بشكل صارم، فلا يُمكِن تخديم المحتوى القديم تحت أي ظروف، ويمنع هذا استخدام المحتوى المُخزَّن مؤقّتًا في حالة انقطاعات الشبكة والسيناريوهات المشابهة لها.proxy-revalidate: يقوم هذا الإعداد بنفس ما يقوم به الإعداد السابق ولكن ينطبق فقط على وسطاء التخزين المؤقّت البيني intermediary proxies، ويبقى متصفّح المستخدم في هذه الحالة قادرًا على تخديم المحتوى القديم في حالة انقطاعات الشبكة، ولكن لا يُمكن استخدام التخزينات المؤقّتة الوسيطة لهذا الغرض.no-transform: يمنع هذا الخيار التخزينات المؤقّتة من تعديل المحتوى الذي تلقّته لأسباب تتعلّق بالأداء تحت أي ظروف، يعني هذا على سبيل المثال أنّ التخزين المؤقّت غير قادر على إرسال إصدارات مضغوطة من محتوى لم يتلقّاه بشكل مضغوط وغير مسموح له بهذا أصلًا.نستطيع الجمع بين كل ما سبق بطرق مختلفة للحصول على سلوك متعدّد للتخزين المؤقّت، بعض القيم التبادليّة هي: no-cache ،no-store، وسلوك التخزين المؤقّت الطبيعي الذي نشير إليه بغياب أحدهماpublic و privateيحل الخيار no-store محل no-cache إن كان كلاهما موجودًا، ومن أجل الاستجابة على الطلبات التي لا تتعلق بالاستيثاق يتم تطبيق الخيار public، ومن أجل الاستجابة على الطلبات التي تحتوي استيثاق يتم تطبيق الخيار private، ويُمكِن تجاوزها بتضمين الخيار المعاكس في الترويسة Cache-Control. تطوير سياسة تخزين مؤقتيُمكِن في العالم المثالي التخزين المؤقّت لكل شيء بقوّة والتواصل مع الخواديم فقط للتحقّق من المحتوى بين حين وآخر، ولكن على الرغم من ذلك لا يحدث هذا في الممارسة العمليّة، لذا ينبغي أن نحاول تعيين سياسات تخزين مؤقّت عاقلة تطمح إلى الموازنة بين تنفيذ تخزين مؤقّت طويل المدى والاستجابة لاحتياجات الموقع المتغيّر. مشاكل شائعةهنالك العديد من الحالات التي لا يُمكِن أو لا ينبغي فيها تنفيذ التخزين المؤقّت نظرًا لكيفيّة إنتاج هذا المحتوى (توليده بشكل مُتغيّر بحسب المستخدم) أو طبيعة هذا المحتوى (معلومات بنكيّة حساسة على سبيل المثال)، ومن المشاكل الأخرى التي تُواجِه العديد من مديري النّظم عند إعداد التخزين المؤقّت هي الحالة التي تكون فيها إصدارات أقدم ومنتشرة من محتوانا ليست قديمة بعد على الرغم من نشر إصدارات أجدد منها. تتم مصادفة هاتين المشكلتين بشكل متكرّر وتمتلكان أثرًا هامًّا على أداء التخزين المؤقّت ودقّة المحتوى الذي نقوم بتخديمه، ومع ذلك نستطيع الحد من هذه المشاكل عن طريق تطوير سياسات تخزين مؤقّت تتوقّع هذه المشاكل. توصيات عامةعلى الرغم من أنّ الحالة هي التي تُملي علينا استراتيجيّة التخزين المؤقّت المُلائِمة، تستطيع التوصيات التالية إرشادنا نحو بعض القرارات المنطقيّة. هناك بعض الخطوات التي نستطيع اتخاذها لزيادة نسبة استخدام التخزين المؤقّت Cache hit ratio قبل الانتقال لاستخدام ترويسات محدّدة، ومن بعض الأفكار نجد: إنشاء أدلّة directories مُخصّصة للصور، ملفات css، والمحتوى المُشترَك: يسمح وضع المحتوى في أدلّة مُخصّصة بالرجوع بسهولة إليها من أي صفحة على موقعنا.استخدام نفس الرابط URL للإشارة إلى نفس العناصر: بما أنّ التخزينات المؤقّتة تستخدم مفتاح مُكوَّن من المُضيف والمسار للمحتوى المطلوب فيجب أن نتأكّد من أن نشير إلى محتوانا بنفس الطريقة على كافّة صفحات موقعنا، وتجعل النصيحة السابقة من هذا أسهل.استخدام الأشكال الشبحية sprites لصور CSS حيثما أمكن ذلك: تُقلِّل الأشكال الشبحية لصور CSS من أجل عناصر مثل الأيقونات والتصفّح navigation من عدد الجولات المطلوبة لتصيير render موقعنا وتسمح لنا بالتخزين المؤقّت لذلك الشكل الشبحي لوقت طويل.استضافة الـ scripts والموارد الخارجيّة بشكل محلّي بقدر الإمكان: إن كُنّا نستخدم scripts خاصة بلغة javascript وموارد خارجيّة أخرى فيجب أن نأخذ بعين الاعتبار استضافة هذه الموارد على خواديمنا الخاصّة، نلاحظ أنّه يجب علينا الانتباه لأي تحديثات جديدة لهذه الموارد لكي نقوم بتحديث نسختنا المحليّة منها.وضع بصمة خاصّة لعناصر التخزين المؤقّت: من المناسب أن نقوم بوضع بصمة خاصّة بالنسبة للمحتوى الثابت مثل ملفّات CSS وJavascript، ويعني هذا إضافة مُعرِّف فريد unique identifier إلى اسم الملف (عادةً تلبيد hash للملف) بحيث إن تمّ تعديل المورد يُمكِن طلب الاسم الجديد للمورد مما يجعل الطلبات تجتاز التخزين المؤقّت بشكل صحيح، توجد العديد من الأدوات التي تساعد في إنشاء بصمات وتعديل المراجع إليها في ملفّات HTML.ومن ناحية اختيار الترويسات الصحيحة للعناصر المختلفة، فيمكن اعتبار ما يلي كمرجع عام: السماح لكافّة التخزينات المؤقتة بتخزين الممتلكات العامّة general assets: ينبغي أن يتم التخزين المؤقّت للمحتوى الثابت وغير المتعلّق بالمستخدم في كافّة النقاط على سلسلة التوصيل، ممّا يسمح للتخزينات المؤقّتة الوسيطة بالاستجابة بالمحتوى للعديد من المستخدمين.السماح للمتصفّحات بالتخزين المؤقّت للممتلكات الخاصّة بالمستخدم: من المقبول والمفيد بالنسبة للمحتوى الخاص بالمستخدم أن نسمح بالتخزين المؤقّت داخل متصفّح المستخدم، وبينما يكون من غير الملائم فعل هذا على التخزينات المؤقّتة الوسيطة يسمح التخزين المؤقّت في المتصفّح بالاستعادة الآنيّة للمحتوى من أجل المستخدمين خلال الزيارات اللاحقة.عمل استثناءات للمحتوى الأساسي الحساس بالنسبة للوقت: إن كنّا نملك محتوى حساس بالنسبة للوقت نقوم بعمل استثناء للقواعد السابقة بحيث لا يتم تخديم المحتوى القديم في الحالات الحرجة، على سبيل المثال إن كان موقعنا يمتلك عربة تسوّق shopping cart فينبغي أن تعكس العناصر الموجودة فيها فورًا، واعتمادًا على طبيعة المحتوى يُمكِن تعيين الخيار no-cache أو no-store في الترويسة Cache-Control لتحقيق هذا.توفير خيارات للتحقّق دومًا: تسمح لنا خيارات التحقّق بتحديث المحتوى القديم بدون أن يتوجّب علينا تنزيل كامل الموارد مرّة أخرى، يسمح تعيين الترويسات Etag وLast-Modified للتخزينات المؤقّتة بأن تتحقّق من محتواها وتعيد تخديمه إن لم يتم تعديله على الخادوم الأصل، مما يؤدي إلى إنقاص الحمل load.تعيين أوقات حداثة freshness times طويلة للمحتوى الداعم: من أجل الاستفادة من التخزين المؤقّت بشكل فعّال فإنّ العناصر المطلوبة كمحتوى داعم لملء الطلب ينبغي عادة أن تملك وقت حداثة طويل، وهو مناسب بشكل عام من أجل لعناصر مثل الصور وملفّات CSS والتي يتم سحبها لتصيير صفحة HTML المطلوبة من قبل المستخدم، يسمح تعيين وقت حداثة طويل مع جمعه بوضع بصمة بأن تقوم التخزينات المؤقّتة بتخزين هذه الموارد لفترات طويلة، فإن تمّ تغيير الممتلكات فستقوم البصمة المُعدّلة بإبطال العنصر المُخزَّن مؤقّتًا وستقوم بتحفيز تنزيل المحتوى الجديد، وحتى ذلك الحين يُمكِن أن يتم تخزين العناصر الداعمة بشكل مؤقّت لوقت طويل في المستقبل.تعيين أوقات حداثة freshness times قصيرة للمحتوى الأب: يجب أن يملك عنصر الاحتواء وقت حداثة قصير نسبيًّا أو حتى لا يتم تخزينه بشكل مؤقّت نهائيًّا وذلك من أجل تطبيق المخطّط السّابق، وهو بشكل نموذجي صفحة HTML التي تستدعي العناصر المساعدة الأخرى، فيتم تنزيل ملفّات HTML بشكل متكرّر ممّا يسمح لها بالاستجابة للتغيرات بسرعة، ومن ثمّ بعدها يُمكِن التخزين المؤقّت للمحتوى الداعم بشدّة.المفتاح الأساسي لتحقيق هذا هو خلق موازنة تُفضِّل التخزين المؤقّت بشدّة حيثما أمكن مع ترك فُرَص لإبطال المُدخلات مُستقبلًا عندما يتم حدوث تغييرات، من المرجّح أن يملك موقعنا تركيبة من: عناصر مُخزَّنة مؤقّتًا بشدّةعناصر مُخزّنة مؤقّتًا مع وقت حداثة قصير والقدرة على إعادة التحقّقعناصر لا ينبغي تخزينها بشكل مؤقّت إطلاقًاوالهدف هو نقل المحتوى إلى الفئة الأولى إن أمكن مع الحفاظ على مستوى مقبول من الدقة. الخاتمةإنّ أخذ الوقت للتأكّد من أنّ موقعنا يملك سياسات تخزين مؤقّت مناسبة في مكانها له تأثير هام عليه، حيث يسمح التخزين المؤقّت بالتقليل من نفقات عرض النطاق bandwidth المترافقة مع تخديم نفس المحتوى بشكل متكرّر، سيكون خادومنا أيضًا قادر على التعامل مع كميّة كبيرة من حركة مرور البيانات traffic باستخدام نفس العتاد، وربّما الأهم من كل ذلك أنّ العملاء سيملكون تجربة أسرع على موقعنا ممّا يقود بهم إلى العودة إليه بشكل متكرّر، وفي حين أنّ التخزين المؤقّت بشكل فعّال ليس حلًّا سحريًّا فإنّ إعداد سياسات تخزين مؤقّت مناسبة يعطينا مكاسب ملموسة بجهد قليل. ترجمة -وبتصرّف- لـ Web Caching Basics: Terminology, HTTP Headers, and Caching Strategies لصاحبه Justin Ellingwood.
  23. إنّ التخزين المؤقّت Caching للمحتوى بشكل ذكي هو واحد من أكثر الطرق فعاليّة لتحسين التجربة لزوّار أي موقع. إنّ التخزين المؤقّت Caching، أو تخزين المحتوى بشكل مؤقّت من الطلبات السّابقة، هو جزء من لُب استراتيجيّة توصيل المحتوى المُنفَّذة ضمن ميفاق HTTP protocol، تستطيع المُكوِّنات عبر مسار توصيل المحتوى أن تقوم بالتخزين المؤقّت للعناصر لتسريع الطلبات اللاحقة، والتي تكون خاضعة لسياسات التخزين المؤقّت المُصرَّح عنها بالنسبة للمحتوى. سنناقش في هذا الدّرس بعض المفاهيم الأساسيّة للتخزين المؤقّت لمحتوى الويب، وسنتحدّث عن الفوائد التي يتيح لنا التخزين المؤقّت الحصول عليها والأماكن التي يتم فيها هذا التخزين. ما هو التخزين المؤقت Caching؟التخزين المؤقّت Caching هو مصطلح يُعبِّر عن تخزين الاستجابات القابلة لإعادة استخدامها لجعل الطلبات اللاحقة تتم بشكل أسرع، تُوجد العديد من الأنواع المختلفة المُتاحة للتخزين المؤقّت، وكل منها له خصائصه الفريدة، فالتخزين المؤقّت للتطبيقات والتخزين المؤقّت للذاكرة شائعان لقدرتهما على تسريع بعض الاستجابات. إنّ التخزين المؤقّت للويب Web Caching -وهو محور درسنا هذا- هو نوع مختلف من التخزين المؤقّت، وهو ميزة التصميم الأساسيّة في ميفاق HTTP protocol والتي تهدف لتصغير حركة مرور البيانات عبر الشبكة network traffic مع تحسين الاستجابة التي يتلقّاها النظام ككل، تُوجد التخزينات المؤقّتة Caches في كل مستوى من مستويات رحلتنا مع المحتوى، ابتداءً من الخادوم الأصلي وحتى المتصفّح. يعمل التخزين المؤقّت للويب عن طريق التخزين المؤقّت لاستجابات HTTP للطلبات وفق قواعد معيّنة، ويتم بعدها تلبية الطلبات اللاحقة للمحتوى المُخزّن بشكل مؤقّت من التخزين المؤقّت القريب من المستخدم بدلًا من إعادة إرسال الطلبات إلى خادوم الويب. الفوائديُساعد التخزين المؤقّت الفعّال مستهلكي المحتوى ومزوّدي المحتوى، ومن الفوائد التي يقدّمها لتوصيل المحتوى نجد: تقليل تكاليف الشبكة: يُمكن التخزين المؤقّت للمحتوى في عدّة نقاط على مسار الشبكة بين مُستهلِك المحتوى ومصدر المحتوى، وعندما يتم تخزين المحتوى بشكل مؤقّت في مكان أقرب للمستهلك فلن تُحدِث الطلبات نشاطًا إضافيًّا للشبكة ما وراء نقطة التخزين المؤقّت.تحسين الاستجابة: يُمكِّننا التخزين المؤقّت من استرجاع المحتوى بشكل أسرع لأنّه ليس من الضروري القيام بدورة كاملة عبر الشبكة من أجل استرجاعه، يستطيع التخزين المؤقّت القريب من المستخدم، مثل التخزين المؤقّت للمتصفّح browser cache، أن يجعل هذا الاسترجاع للمحتوى لحظيًّا.تحسين الأداء على نفس العتاد: بالنسبة للخادوم الذي هو منشأ المحتوى فبإمكاننا الحصول على المزيد من الأداء من نفس العتاد عن طريق السماح بالتخزين المؤقّت العنيف aggressive caching، فيتمكّن مالك المحتوى من الاستفادة من الخواديم القويّة على مسار التوصيل لتتحمّل شدّة بعض تحميلات المحتوى.توافر المحتوى أثناء انقطاعات الشبكة: يُمكِن استخدام التخزين المؤقّت ضمن سياسات مُحدّدة لتخديم المحتوى للمستخدمين النهائيين عندما لا يكون هذا المحتوى متوفّرًا لفترة قصيرة من الوقت من الخواديم الأصل.مصطلحاتقد نصادف عند التعامل مع التخزين المؤقّت بعض المصطلحات غير المألوفة، ومن أشيعها ما يلي: الخادوم الأصل Origin server: إنّ الخادوم الأصل هو المكان الأصلي للمحتوى، فإن كنت تلعب دور مُدير خادوم الويب فهو الجهاز الذي تتحكّم به، وهو مسؤول عن تخديم أي محتوى لم نتمكّن من استرجاعه من التخزين المؤقّت على طول مسار الطلب، وإعداد سياسة التخزين المؤقّت لكافّة المحتويات.نسبة استخدام التخزين المؤقّت Cache hit ratio: تُقاس فعاليّة التخزين المؤقّت وفق نسبة استخدام التخزين المؤقّت cache hit ratio أو معدل الاستخدام hit rate، وهي نسبة الطلبات التي يُمكن استرجاعها من التخزين المؤقّت على العدد الكلّي للطلبات، وعندما تكون مرتفعة تدل على أنّنا استطعنا استرجاع نسبة عالية من الطلبات من التخزين المؤقّت، وهو عادةً النتيجة المرجوّة لمعظم مُديري النُظُم.الحداثة Freshness: وهو مصطلح يُستخدم ليصف إذا ما كان العنصر في التخزين المؤقّت لا يزال يُعد مُرشَّحًا لتخديمه إلى العميل، يُستخدَم المحتوى الموجود في التخزين المؤقّت كاستجابة فقط إذا كان ضمن الإطار الزمني للحداثة freshness المُحدَّد من قبل سياسة التخزين المؤقّت.المحتوى القديم Stale content: تنتهي صلاحيّة العناصر الموجودة في التخزين المؤقّت وفق إعدادات freshness المُحدَّدة من قبل سياسته الخاصة، يُوصف المحتوى مُنتهي الصلاحيّة بأنّه قديم "stale"، وبشكل عام لا يُمكن استخدام هذا المحتوى للإجابة على طلبات العملاء، ويجب هنا إعادة الاتصال مع الخادوم الأصل لاسترجاع المحتوى الجديد أو للتحقّق على الأقل من أنّ المحتوى المُخزَّن مؤقّتًا لا يزال دقيقًا.التحقّق Validation: يُمكِن التحقّق من العناصر الموجودة في التخزين المؤقّت من أجل تحديث مُدّة صلاحيتها، ويتضمّن هذا التواصل مع الخادوم الأصل لنعرف إذا ما كان المحتوى المُخزَّن مؤقّتًا لا يزال يُمثِّل أحدث إصدار من هذه العناصر.الإبطال Invalidation: الإبطال هو عمليّة إزالة المحتوى من التخزين المؤقّت قبل الوقت المُحدّد لانتهاء صلاحيّته، وهو ضروري إن تمّ تغيير المحتوى على الخادوم الأصل، فامتلاك محتوى قديم في التخزين المؤقّت سيسبب مشاكل هامّة للعميل.يُوجد المزيد من مصطلحات التخزين المؤقّت، ولكن ينبغي أن تُساعدك المصطلحات السّابقة في البدء. ما هو المحتوى الذي يمكن تخزينه بشكل مؤقت؟يجعل بعض المحتوى من نفسه أكثر سهولة للتخزين المؤقّت من محتوى آخر، فمن المحتوى القابل بشدّة للتخزين المؤقّت لمعظم المواقع نجد: صور الشعارات والعلامات التجاريّةالصور غير المتناوبة Non-rotating images (مثل أيقونات التصفّح navigation)ملفّات التنسيق Style sheetsملفّات Javascript العامّةالمحتوى القابل للتنزيلملفّات الوسائط Media Filesتميل هذه المحتويات إلى عدم تغيّرها بشكل متكرّر، لذا نستفيد من تخزينها بشكل مؤقّت لفترات طويلة. ومن بعض العناصر التي يجب أن نحذر عند تخزينها بشكل مؤقّت نجد: صفحات HTMLالصور المتناوبة Rotating imagesملفّات CSS و Javascript المُعدَّلة بشكل متكرّرالمحتوى الذي يتم طلبه من خلال كعكات الاستيثاق authentication cookiesومن العناصر التي لا ينبغي إطلاقًا تخزينها بشكل مؤقّت تقريبًا: البيانات الحسّاسة (معلومات البنك، إلخ ..)المحتوى المرتبط بالمستخدم والمتغيّر بشكل متكرّروبالإضافة للقواعد العامّة السّابقة من الممكن تحديد سياسات تسمح لنا بالتخزين المؤقّت لأنواع مختلفة من المحتوى بشكل مناسب، على سبيل المثال إن كانت تظهر نفس شاشة العرض من موقعنا للمستخدمين الذين قاموا بالاستيثاق فمن الممكن التخزين المؤقّت لها في أي مكان، وإن كانت تظهر شاشة تعرض معلومات حسّاسة عن المستخدم في موقعنا فمن الممكن أن تكون صالحة للتخزين المؤقّت لبعض الوقت، وربّما نخبر متصفّح المستخدم أن يقوم بالتخزين المؤقّت ولكن من دون إخبار أي أماكن وسيطة أخرى للتخزين المؤقّت أن تقوم بتخزين شاشة العرض هذه. أماكن التخزين المؤقت لمحتوى الويبيُمكِن التخزين المؤقّت للمحتوى في العديد من النقاط المختلفة على طول سلسلة التوصيل: التخزين المؤقّت للمتصفّح Browser cache: تحتفظ متصفّحات الإنترنت لنفسها بمكان صغير للتخزين المؤقّت، يقوم المتصفّح نموذجيًّا بتعيين سياسة تنص على أهم العناصر التي يجب تخزينها مؤقّتًا، والتي قد تكون محتوى خاص بالمستخدم أو محتوى يُعتبَر من المُكلِف تنزيله ومن المرجّح أن يُطلَب مرّة أخرى.وسطاء التخزين المؤقّت البيني Intermediary caching proxies: يستطيع أي خادوم بين العميل وبنيتنا التحتيّة أن يقوم بالتخزين المؤقّت كما يرغب، يتم الحفاظ على هذه التخزينات المؤقّتة من قبل مزوّدات خدمة الإنترنت ISPs أو أطراف مستقلّة أخرى.التخزين المؤقّت العكسي Reverse Cache: بإمكان البنية التحتيّة لخادومنا تنفيذ التخزين المؤقّت الخاص بها لخدمات المنتهى الخلفي backend services، وبهذه الطريقة يُمكِن تخديم المحتوى من نقطة الاتصال بدلًا من الوصول لخواديم المنتهى الخلفي backend عند كل طلب.تقوم هذه المواقع عادةً بعمل تخزين مؤقّت للعناصر وفق سياسات التخزين المؤقّت لديها والسياسات المُحدَّدة على الخادوم الأصل. الخاتمةتحدّثنا في هذا الدّرس عن مفهوم التخزين المؤقّت وشرحنا بعض المصطلحات الأساسيّة فيه، وشاهدنا الفوائد التي نحصل عليها من استخدامه، والأماكن التي يتم فيها هذا التخزين. تكلمنا أيضًا عن أنواع المحتوى التي يُمكِن تخزينها بشكل مؤقّت والأنواع التي لا يجب إطلاقًا تخزينها. ترجمة -وبتصرّف- لـ Web Caching Basics: Terminology, HTTP Headers, and Caching Strategies لصاحبه Justin Ellingwood. حقوق الصورة البارزة: Designed by Freepik.
  24. iptables عبارة عن جدار ناري firewall يلعب دورًا أساسيًّا في أمان الشبكات لمعظم أنظمة لينِكس، وبينما تقوم العديد من دروس iptables بتعليمنا كيفيّة إنشاء قواعد الجدار النّاري لتأمين خادومنا، يُركِّز هذا الدرس على ناحية مختلفة من إدارة الجدار النّاري: سرد listing وحذف القواعد rules. سنشرح في هذا الدّرس كيفيّة القيام بمهام iptables التالية: سرد القواعد list rules مسح عدادات Packet وByte حذف القواعد إفراغ السلاسل Flush chains (حذف جميع القواعد في السلسلة) إفراغ السلاسل والجداول، حذف السلاسل، وقبول أي حركة مرور البيانات traffic ملاحظة: احذر عند التعامل مع الجدار النّاري من حظر نفسك عن خادومك عن طريق حظر حركة مرور بيانات SSH (المنفذ 22 افتراضيًّا)، وإن فقدت النفاذ إليه بسبب إعدادات الجدار النّاري فربّما تحتاج للاتصال إليه عن طريق الـ console لإصلاح نفاذنا إليه، حيث تستطيع بعدها تغيير إعدادات الجدار النّاري للسماح بنفاذ SSH (أو أي حركة مرور بيانات traffic)، وإن كانت قواعد الجدار النّاري المحفوظة لديك تسمح بنفاذ SSH فمن الطرق الأخرى هي إعادة تشغيل خادومك. المتطلبات الأساسية ينبغي قبل أن تبدأ باتّباع هذا الدّرس أن تمتلك على خادومك حساب superuser غير جذري non-root مُنفصِل (مُستخدِم مع صلاحيّات sudo)، إن أردت إعداده اتبع الدّرس التّالي: الإعداد الابتدائي لخادوم أوبنتو 14.04. فلنقم بإلقاء نظرة على كيفيّة سرد list القواعد أولًا. توجد طريقتان مختلفتان لعرض قواعد iptables النشيطة active: إمّا في جدول أو على شكل قائمة من مواصفات القواعد، تُزوِّدنا هاتان الطريقتان بنفس المعلومات تقريبًا في صيغ مختلفة. سرد القواعد بحسب المواصفات Specification لسرد جميع قواعد iptables النشيطة بحسب المواصفات نقوم بتنفيذ الأمر iptables مع الخيار S-: sudo iptables -S -P INPUT DROP -P FORWARD DROP -P OUTPUT ACCEPT -N ICMP -N TCP -N UDP -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -p udp -m conntrack --ctstate NEW -j UDP -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j TCP -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable -A INPUT -p tcp -j REJECT --reject-with tcp-reset -A INPUT -j REJECT --reject-with icmp-proto-unreachable -A TCP -p tcp -m tcp --dport 22 -j ACCEPT يبدو الخرْج Output كما نرى مُشابِهًا للأوامر التي اعتدنا على إنشائها ولكن بدون أن يسبقها الأمر iptables، يبدو هذا أيضًا مُشابِهًا لملفّات إعدادات قواعد iptables إن قمت سابقًا باستخدام iptables-persistent أو iptables save. سرد سلسلة محددة إن أردنا تحديد الخَرْج إلى سلسلة مُحدّدة (مثل INPUT، OUTPUT، TCP، إلخ..) فبإمكاننا تحديد اسم السلسلة مباشرة بعد الخيار S-، على سبيل المثال لإظهار كافّة مواصفات القواعد في سلسلة TCP نقوم بتنفيذ الأمر التالي: sudo iptables -S TCP -N TCP -A TCP -p tcp -m tcp --dport 22 -j ACCEPT فلنقم بإلقاء نظرة على الطريقة البديلة لعرض قواعد iptables النشيطة كجدول من القواعد. سرد القواعد كجداول يُمكِن أن يكون عرض قواعد iptables في طريقة عرض الجدول مفيدًا لمقارنة القواعد المختلفة مع بعضها. لإخراج كافّة قواعد iptables النشيطة في جدول نقوم بتنفيذ الأمر iptables مع الخيار L-: sudo iptables -L سيقوم هذا بإخراج جميع القواعد الحاليّة مُرتّبة بحسب السلسلة. إن أردنا تحديد الخَرْج إلى سلسلة مُحدّدة (مثل INPUT، OUTPUT، TCP، إلخ..) فبإمكاننا تحديد اسم السلسلة مباشرة بعد الخيار L-. دعونا نلقي نظرة على مثال عن سلسلة الدّخل INPUT: sudo iptables -L INPUT Chain INPUT (policy DROP) target prot opt source destination ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED ACCEPT all -- anywhere anywhere DROP all -- anywhere anywhere ctstate INVALID UDP udp -- anywhere anywhere ctstate NEW TCP tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN ctstate NEW ICMP icmp -- anywhere anywhere ctstate NEW REJECT udp -- anywhere anywhere reject-with icmp-port-unreachable REJECT tcp -- anywhere anywhere reject-with tcp-reset REJECT all -- anywhere anywhere reject-with icmp-proto-unreachable يُشير السّطر الأول من الخَرْج إلى اسم السلسلة (في هذه الحالة INPUT) متبوعًا بسياسته policy الافتراضيّة (DROP). يتكوّن السّطر التالي من ترويسة كل عمود في الجدول متبوعة بقواعد السلسلة، فلنقم بالمرور على دلالة كل ترويسة: target: إن كانت الرزمة packet تُطابِق القاعدة يُحدِّد الهدف target ما ينبغي فعله معها، يُمكن على سبيل المثال أن يتم قبول، إسقاط drop، تسجيل، أو إرسال الرزمة إلى سلسلة أخرى لتتم مقارنتها مع قواعد أخرى prot: الميفاق protocol، مثل tcp، udp، icmp، أو all opt: يُشير هذا العمود إلى خيارات عنوان IP ونادرًا ما يتم استخدامه source: عنوان IP المصدر أو الشبكة الفرعية subnet لحركة مرور البيانات traffic، أو anywhere destination: عنوان IP الوجهة destination أو الشبكة الفرعية subnet لحركة مرور البيانات traffic، أو anywhere يُشير العمود الأخير الذي لا يملك عنوان إلى خيارات options القاعدة، والتي هي أي جزء من القاعدة لم يتم الإشارة إليه في الأعمدة السابقة، يُمكن لها أن تكون أي شيء من منافذ ports المصدر والوجهة، وحتى حالة اتصال الرزمة. إظهار تعداد الرزم Packet Counts والحجم الكلي Aggregate Size من الممكن أيضًا عند سرد قواعد iptables أن نظهر عدد الرُّزَم packets والحجم الكلّي لها بالبايت، والذي يُقابل كل قاعدة مُحدّدة، يكون هذا مُفيدًا عادةً عندما نحاول أخذ فكرة تقريبيّة عن القواعد التي تُطابِق الرُّزَم، ولفعل هذا نستخدم ببساطة الخيارين L- وv- معًا. فلنلقِ نظرة على سبيل المثال على سلسلة الدّخل INPUT مرّة أخرى مع الخيار v-: sudo iptables -L INPUT -v Chain INPUT (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 284K 42M ACCEPT all -- any any anywhere anywhere ctstate RELATED,ESTABLISHED 0 0 ACCEPT all -- lo any anywhere anywhere 0 0 DROP all -- any any anywhere anywhere ctstate INVALID 396 63275 UDP udp -- any any anywhere anywhere ctstate NEW 17067 1005K TCP tcp -- any any anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN ctstate NEW 2410 154K ICMP icmp -- any any anywhere anywhere ctstate NEW 396 63275 REJECT udp -- any any anywhere anywhere reject-with icmp-port-unreachable 2916 179K REJECT all -- any any anywhere anywhere reject-with icmp-proto-unreachable 0 0 ACCEPT tcp -- any any anywhere anywhere tcp dpt:ssh ctstate NEW,ESTABLISHED نلاحظ أنّ القائمة تحتوي الآن على عمودين إضافيين وهما pkts وbytes. الآن وقد عرفنا كيفيّة سرد قواعد الجدار النّاري النشيطة بطرق متعدّدة، فلنلقِ نظرة على كيفيّة تصفير reset عدادات الرُّزم والبايتات. تصفير تعداد الرزم Packet Counts والحجم الكلي Aggregate Size إن أردنا مسح أو تصفير عدادات الرُّزَم والبايتات لقواعدنا نستخدم الخيار Z-، يتم أيضًا تصفيرها عند حدوث إعادة تشغيل، وهذا مفيد لمعرفة إن كان خادومنا يتلقّى حركة مرور بيانات جديدة تتوافق مع قواعدنا الحاليّة. لمسح العدادات لجميع السلاسل والقواعد نستخدم الخيار Z-: sudo iptables -Z ولمسح العدادات لجميع القواعد في سلسلة مُحدّدة نستخدم الخيار Z- مع تحديد السلسلة المطلوبة، على سبيل المثال لمسح عدادات سلسلة الدّخل INPUT نكتب هذا الأمر: sudo iptables -Z INPUT إن أردنا مسح العدادات من أجل قاعدة مُحدّدة نُحدِّد اسم السلسلة ورقم القاعدة، على سبيل المثال لتصفير العدادات للقاعدة الأولى في سلسلة الدّخل INPUT نقوم بتنفيذ الأمر التالي: sudo iptables -Z INPUT 1 الآن وقد عرفنا كيفيّة تصفير عدادات الرُّزَم والبايتات في iptables فلنلقِ نظرة على طريقتي حذفهما. حذف القاعدة بحسب المواصفات Specification إنّ إحدى طرق حذف قواعد iptables هي عن طريق مواصفات القاعدة، ولفعل هذا نستطيع تنفيذ الأمر iptables مع الخيار D- متبوعًا بمواصفات القاعدة، إن أردنا استخدام هذه الطريقة لحذف القواعد فبإمكاننا استخدام خَرْج سرد القواعد (iptables –S) من أجل المساعدة. إن أردنا على سبيل المثال حذف القاعدة التي تقوم بإسقاط (drop) الرُّزَم الخاطئة القادمة فبإمكاننا تنفيذ هذا الأمر: sudo iptables -D INPUT -m conntrack --ctstate INVALID -j DROP نلاحظ أنّه يجب علينا استبعاد الخيار A- والذي يُستخدَم للإشارة إلى موقع القاعدة في وقت إنشائها. حذف القاعدة بحسب السلسلة والرقم الطريقة الأخرى لحذف قواعد iptables هي عن طريق سلسلتها chain ورقم سطرها line number، ولتحديد هذا الرقم نقوم بسرد القواعد في صيغة جدول مع إضافة الخيار line-numbers--: sudo iptables -L --line-numbers Chain INPUT (policy DROP) num target prot opt source destination 1 ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED 2 ACCEPT all -- anywhere anywhere 3 DROP all -- anywhere anywhere ctstate INVALID 4 UDP udp -- anywhere anywhere ctstate NEW 5 TCP tcp -- anywhere anywhere tcp flags:FIN,SYN,RST,ACK/SYN ctstate NEW 6 ICMP icmp -- anywhere anywhere ctstate NEW 7 REJECT udp -- anywhere anywhere reject-with icmp-port-unreachable 8 REJECT tcp -- anywhere anywhere reject-with tcp-reset 9 REJECT all -- anywhere anywhere reject-with icmp-proto-unreachable 10 ACCEPT tcp -- anywhere anywhere tcp dpt:ssh ctstate NEW,ESTABLISHED ... يُضيف هذا الخيار رقم السطر لكل قاعدة مع الإشارة إليه بالترويسة num. بعد أن نعرف ما هي القاعدة التي نريد حذفها نتأكد من سلسلة ورقم سطر هذه القاعدة ثم نقوم بتنفيذ الأمر iptables –D متبوعًا بسلسلة ورقم القاعدة. على سبيل المثال إن أردنا حذف قاعدة input التي تُسقِط الرُّزَم الخاطئة نستطيع أن نرى أنّها القاعدة 3 من السلسلة INPUT لذا نقوم بتنفيذ الأمر التالي: sudo iptables -D INPUT 3 الآن وقد عرفنا كيفيّة حذف قواعد الجدار النّاري المفردة فلننتقل إلى كيفيّة إفراغ flush سلاسل القواعد. إفراغ السلاسل تُزوّدنا iptables بطريقة لحذف كافّة القواعد في سلسلة، أي إفراغ flush السلسلة، يُغطّي هذا القسم الطرق المتعدّدة لفعل هذا. ملاحظة: انتبه، فقد تحظر نفسك عن خادومك عبر SSH عن طريق إفراغ سلسلة تمتلك سياسة افتراضيّة drop أو deny، إن فعلت ذلك فربّما تحتاج للاتصال بخادومك عبر الـ console لإصلاح النفاذ إليه. 1- إفراغ سلسلة مفردة لإفراغ سلسلة مُحدّدة، والذي يقوم بحذف كافّة القواعد في هذه السلسلة، فبإمكاننا استخدام الخيار F- (أو الخيار flush-- المُكافِئ له) مع اسم السلسلة التي نريد إفراغها. على سبيل المثال لحذف جميع القواعد في سلسلة الدّخل INPUT نقوم بتنفيذ هذا الأمر: sudo iptables -F INPUT 2- إفراغ كافة السلاسل لإفراغ كافّة السلاسل، والذي يقوم بحذف كامل قواعد الجدار النّاري لدينا، فبإمكاننا استخدام الخيار F- (أو الخيار flush-- المُكافِئ له): sudo iptables -F إفراغ جميع القواعد، حذف كامل السلاسل، وقبول أي حركة مرور بيانات traffic سنشاهد في هذا القسم كيفيّة إفراغ كامل قواعد الجدار النّاري لدينا، الجداول، والسلاسل، والسماح بأي حركة مرور بيانات traffic على الشبكة. ملاحظة: سيقوم هذا بتعطيل الجدار النّاري لديك بشكل كامل، ينبغي فقط أن تتبع هذا القسم إن أردت البدء من جديد في إعداد الجدار النّاري لديك. نُعيّن في البداية السياسات الافتراضيّة لكل سلسلة مُضمَّنة إلى ACCEPT، السبب الأساسي لفعل هذا هو التأكد من عدم حظر أنفسنا عن خادومنا عبر SSH: sudo iptables -P INPUT ACCEPT sudo iptables -P FORWARD ACCEPT sudo iptables -P OUTPUT ACCEPT نقوم بعدها بإفراغ الجداول nat وmangle، إفراغ كامل السلاسل (F-)، وحذف كافّة السلاسل غير الافتراضيّة (X-): sudo iptables -t nat -F sudo iptables -t mangle -F sudo iptables -F sudo iptables -X سيسمح الآن جدارنا النّاري بكافة حركة مرور البيانات traffic على الشبكة، وإن قمنا بسرد قواعدنا الآن سنشاهد أنّه لا توجد أي قاعدة، وأنّه فقط بقيت لنا السلاسل الثلاث الافتراضية (INPUT، FORWARD، وOUTPUT). الخاتمة ينبغي بعد قراءة هذا هذا الدّرس أن تتكوّن لديك صورة واضحة حول كيفيّة سرد وحذف قواعد جدار iptables النّاري لديك. تذكّر أنّ أي تغيير لـ iptables عبر الأمر iptables هو تغيير عابر، ويجب حفظه ليبقى بشكل دائم بعد إعادة تشغيل الخادوم، وقد تم شرح هذا في قسم حفظ القواعد من درس قواعد وأوامر شائعة للجدار النّاري. ترجمة -وبتصرّف- لـ How To List and Delete Iptables Firewall Rules لصاحبه Mitchell Anicas.
  25. MemSQL عبارة عن قاعدة بيانات تعمل مُباشرة من الذاكرة in-memory تستطيع أن تُخدِّم القراءة والكتابة بشكل أسرع من قواعد البيانات التقليديّة، وبالرغم من أنّها تقنية حديثة إلّا أنّها تتعامل بميفاق protocol قاعدة بيانات MySQL لذلك يكون التعامل معها مألوفًا. تضم MemSQL أحدث قدرات MySQL مع ميّزات حديثة مثل دعم JSON والقدرة على عمل upsert للبيانات (تعني كلمة upsert إدراج صف جديد إن لم يكن موجودًا أي insert، أو تحديث هذا الصف إن كان موجودًا أي update). إنّ أحد أهم نقاط تفوّق MemSQL على MySQL هي قدرتها على فصل الاستعلام query عبر عدّة عقد nodes، والمعروفة أيضًا باسم المعالجة المتوازية على نطاق واسع massively parallel processing، ممّا يؤدي إلى سرعة أكبر في قراءة الاستعلامات. سنقوم في هذا الدّرس بتثبيت MemSQL على خادوم Ubuntu، تنفيذ تجارب قياس الأداء benchmarks، والتعامل مع إدراج بيانات JSON عبر عميل سطر الأوامر في MySQL. المتطلبات الأساسيةسنحتاج لمتابعة هذا الدّرس إلى: Ubuntu 14.04 x64 Droplet مع ذاكرة RAM 8 غيغابايت على الأقل (أو خادوم محلّي بنفس المواصفات)مستخدم غير جذري non-root مع صلاحيّات sudo، والذي يُمكِن إعداده عن طريق درس الإعداد الأولي للخادوم مع Ubuntu.الخطوة الأولى – تثبيت MemSQLسنقوم في هذا القسم بتحضير بيئة العمل من أجل تثبيت MemSQL. يتم عرض آخر إصدار من MemSQL على صفحة تحميله، سنقوم بتحميل وتثبيت MemSQL Ops، والذي هو برنامج يدير تحميل وتحضير خادومنا لتشغيل MemSQL بشكل صحيح، الإصدار الأحدث من MemSQL Ops لدى كتابة هذا الدّرس هو 4.0.35. نقوم في البداية بتنزيل ملف حزمة تثبيت MemSQL من موقعها على الإنترنت: wget http://download.memsql.com/memsql-ops-4.0.35/memsql-ops-4.0.35.tar.gzنستخرج extract بعدها الحزمة: tar -xzf memsql-ops-4.0.35.tar.gzأنشأ استخراج الحزمة مجلّدًا يُدعى memsql-ops-4.0.35، نلاحظ أنّ اسم المجلّد يحتوي على رقم الإصدار، لذلك إن قمت بتنزيل إصدار أحدث من الإصدار المحدّد في هذا الدّرس فستملك مجلّدًا مع رقم الإصدار الذي نزّلته. نغير الدليل إلى هذا المجلّد: cd memsql-ops-4.0.35ثم نقوم بتنفيذ script التثبيت والذي هو جزء من حزمة التثبيت التي استخرجناها للتو: sudo ./install.shسنرى بعض الخَرْج output من الـ script، وسيسألنا بعد لحظات إذا ما كنّا نرغب بتثبيت MemSQL على هذا المُضيف host فقط، سنتعلّم تثبيت MemSQL على عدّة أجهزة في درس لاحق، لذا من أجل غرض هذا الدّرس فلنقل نعم yes عن طريق إدخال الحرف y: Installation script prompt and output . . . Do you want to install MemSQL on this host only? [y/N] y 2015-09-04 14:30:38: Jd0af3b [INFO] Deploying MemSQL to 45.55.146.81:3306 2015-09-04 14:30:38: J4e047f [INFO] Deploying MemSQL to 45.55.146.81:3307 2015-09-04 14:30:48: J4e047f [INFO] Downloading MemSQL: 100.00% 2015-09-04 14:30:48: J4e047f [INFO] Installing MemSQL 2015-09-04 14:30:49: Jd0af3b [INFO] Downloading MemSQL: 100.00% 2015-09-04 14:30:49: Jd0af3b [INFO] Installing MemSQL 2015-09-04 14:31:01: J4e047f [INFO] Finishing MemSQL Install 2015-09-04 14:31:03: Jd0af3b [INFO] Finishing MemSQL Install Waiting for MemSQL to start...نمتلك الآن مجموعة MemSQL مُثبَّتة على خادوم أوبونتو لدينا، ولكن نلاحظ من السجلّات السّابقة أنّه تم تثبيت MemSQL مرتين. تستطيع MemSQL أن تعمل بدورين مختلفين: عقدة مُجمِّع aggregator node وعقدة ورقة leaf node، إنّ سبب تثبيت MemSQL مرتين هو أنّها تحتاج على الأقل إلى عقدة مُجمِّع واحدة وعقدة ورقة واحدة لكي يعمل العنقود cluster. إنّ عقدة المُجمِّع aggregator node هي واجهتنا إلى MemSQL، وهي تبدو بالنسبة للعالم الخارجي مشابهة كثيرًا لـ MySQL، فهي تستمع إلى نفس المنفذ port، وبإمكاننا أن نربط إليها أدوات تتوقّع أن تتعامل مع MySQL ومكتبات MySQL المعياريّة، وظيفة المُجمِّع هي أن يعرف عن كافّة عُقَد الورقة leaf nodes لـ MemSQL، يتعامل مع عُملاء MySQL، ويترجم استعلاماتهم إلى MemSQL. تُخزِّن عقدة الورقة leaf node البيانات فعليًّا، فعندما تستقبل عقدة الورقة طلبًا من عقدة المُجمِّع لقراءة أو كتابة البيانات تقوم بتنفيذ هذا الاستعلام وتُعيد النتائج إلى عقدة المُجمِّع، تسمح MemSQL لنا بمشاركة بياناتنا عبر عدّة مضيفين، وتمتلك كل عقدة ورقة قسمًا من تلك البيانات (حتى مع وجود عقدة ورقة واحدة تكون البيانات تكون البيانات مُقسَّمة ضمن تلك العقدة). عندما نملك عدة عقد ورقة يكون المُجمِّع مسؤولًا عن ترجمة استعلامات MySQL لجميع عقد الورقة التي ينبغي أن تشارك في هذا الاستعلام، ومن ثمّ يتلقى الردود من جميع عقد الورقة ويُجمِّع النتيجة في استعلام واحد يعود إلى عميل MySQL لدينا، وهكذا تتم إدارة الاستعلامات المتوازية. يمتلك إعداد المضيف الوحيد لدينا عقدة مُجمِّع وورقة تعملان على نفس الجهاز، ولكن نستطيع إضافة المزيد من عقد الورقة عبر العديد من الأجهزة الأخرى. الخطوة الثانية – تنفيذ تجربة قياس أداءفلنرى مدى السّرعة التي تستطيع أن تعمل بها MemSQL باستخدام الأداة MemSQL Ops والتي تم تثبيتها كجزء من script تثبيت MemSQL. نذهب إلى http://you_server_ip:9000 في متصفحنا: تعطينا الأداة MemSQL Ops لمحة عامّة عن العنقود cluster لدينا، نمتلك عقدتي MemSQL: المُجمِّع الرئيسي وعقدة الورقة. فلنقم بإجراء اختبار السّرعة Speed Test على عقدة MemSQL في جهازنا المفرد، نضغط على Speed Test من القائمة الموجودة على اليسار، وبعدها نضغط على START TEST، وهذا مثال عن النتائج التي قد نراها: لن نشرح في هذا الدّرس كيفيّة تثبيت MemSQL على خواديم متعددة، ولكن من أجل المقارنة أدرجنا هنا قياس أداء من عنقود MemSQL على نظام Ubuntu يملك 8 جيجابايت من الذّاكرة Ram وعدّة عقد (عقدة مُجمِّع وعقدتا leaf): نكون قادرين بزيادة عدد عقد leaf أن نُضاعِف مُعدَّل الإدراج insert، وبالنظر إلى أقسام قراءة الصفوف Rows Read نستطيع أن نرى أنّ عنقود العقد الثلاثة لدينا قادر على قراءة الصفوف بشكل متزامن أكثر بمقدار 12 مليون صف من عنقود العقدة الواحدة وفي نفس المدة الزمنية. الخطوة الثالثة – التعامل مع MemSQL من خلال mysql-clientتبدو MemSQL بالنسبة للعملاء مثل MySQL، فكلاهما تتعامل بنفس الميفاق protocol، ولبدء التخاطب مع عنقود MemSQL لدينا نقوم بتثبيت mysql-client. في البداية نقوم بتحديث apt لكي نُثبِّت الإصدار الأخير من العميل client في الخطوة التالية: sudo apt-get updateنُثبِّت الآن عميل MySQL والذي سيُمكّننا من تنفيذ الأمر mysql: sudo apt-get install mysql-client-core-5.6نحن الآن على استعداد للاتصال بـ MemSQL باستخدام عميل MySQL، سنتصل باستخدام المستخدم الجذري root إلى المضيف 127.0.0.1 (والذي هو عنوان IP للمضيف المحلّي localhost لدينا) على المنفذ 3306، سنقوم بتخصيص رسالة المُحث prompt لتكون <memsql: mysql -u root -h 127.0.0.1 -P 3306 --prompt="memsql> "سنشاهد بعض أسطر الخَرْج متبوعة بالمُحث <memsql. فلنقم بسرد list قواعد البيانات: memsql> show databases; سنشاهد هذا الخَرْج: +--------------------+ | Database | +--------------------+ | information_schema | | memsql | | sharding | +--------------------+ 3 rows in set (0.01 sec)نُنشِئ قاعدة بيانات جديدة تُدعى tutorial: memsql> create database tutorial;ثم نتحوّل لاستخدام قاعدة البيانات الجديدة باستخدام الأمر use: memsql> use tutorial;نقوم بعدها بإنشاء جدول users والذي يملك الحقلين id و email، يجب علينا تحديد نوع لكلا هذين الحقلين، فلنجعل id من نوع bigint و email من نوع varchar بطول 255، سنخبر أيضًا قاعدة البيانات أنّ الحقل id هو مفتاح أساسي primary key والحقل email لا يُمكن أن يكون عَدم Null. memsql> create table users (id bigint auto_increment primary key, email varchar(255) not null);ربّما تلاحظ زمن تنفيذ بطيء للأمر الأخير (15-20 ثانية)، هناك سبب رئيسي يجعل من MemSQL بطيئة في إنشاء هذا الجدول الجديد وهو: توليد الشيفرة code generation. تستخدم MemSQL توليد الشيفرة لتنفيذ الاستعلامات، وهذا يعني أنّه في كل مرة تتم فيها مصادفة نوع جديد من الاستعلامات تحتاج MemSQL توليد وتصريف compile الشيفرة التي تُمثِّل الاستعلام، يتم بعدها نقل الشيفرة إلى العنقود لتنفيذها، وهذا يُسرِّع عمليّة معالجة البيانات الفعليّة ولكن هناك تكلفة من أجل التحضير، تبذل MemSQL جهدها لإعادة استخدام الاستعلامات المُولَّدة مُسبقًا pre-generated queries، ولكن تبقى الاستعلامات الجديدة ذات البُنية التي لم تشاهدها MemSQL من قبل بطيئة. وبالعودة إلى جدول users نقوم بإلقاء نظرة على تعريفه: memsql> describe users;+-------+--------------+------+------+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+------+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | email | varchar(255) | NO | | NULL | | +-------+--------------+------+------+---------+----------------+ 2 rows in set (0.00 sec)فلنقم الآن بإدراج بعض أمثلة عناوين البريد الإلكتروني في الجدول users، وهي نفس الصياغة syntax التي نستخدمها لقاعدة بيانات MySQL: memsql> insert into users (email) values ('one@example.com'), ('two@example.com'), ('three@example.com');Inserting emails output Query OK, 3 rows affected (1.57 sec) Records: 3 Duplicates: 0 Warnings: 0نستعلم الآن عن الجدول users: memsql> select * from users;بإمكاننا رؤية البيانات التي أدخلناها للتو: +----+-------------------+ | id | email | +----+-------------------+ | 2 | two@example.com | | 1 | one@example.com | | 3 | three@example.com | +----+-------------------+ 3 rows in set (0.07 sec) الخطوة الرابعة – إدراج واستعلام JSONتوفِّر MemSQL نوع JSON، لذا سنقوم في هذه الخطوة بإنشاء جدول أحداث events لاستخدام الأحداث الواردة، يمتلك هذا الجدول حقل id (كما فعلنا مع جدول users) وحقل event والذي سيكون من النوع JSON: memsql> create table events (id bigint auto_increment primary key, event json not null);فلنقم بإدراج حدثين، سنقوم في JSON بإرجاع حقل email والذي بدوره يقوم بإعادة الإرجاع إلى مُعرِّفات IDs المستخدمين الذين أدخلناهم في الخطوة الثالثة: memsql> insert into events (event) values ('{"name": "sent email", "email": "one@example.com"}'), ('{"name": "received email", "email": "two@example.com"}');نقوم الآن بإلقاء نظرة على الأحداث events التي أدرجناها للتو: memsql> select * from events;+----+-----------------------------------------------------+ | id | event | +----+-----------------------------------------------------+ | 2 | {"email":"two@example.com","name":"received email"} | | 1 | {"email":"one@example.com","name":"sent email"} | +----+-----------------------------------------------------+ 2 rows in set (3.46 sec)نستطيع بعدها الاستعلام عن كل الأحداث events التي تكون خاصّية JSON لها التي تُدعى name هي النّص “received email”: memsql> select * from events where event::$name = 'received email';+----+-----------------------------------------------------+ | id | event | +----+-----------------------------------------------------+ | 2 | {"email":"two@example.com","name":"received email"} | +----+-----------------------------------------------------+ 1 row in set (5.84 sec)نحاول تغيير هذا الاستعلام لإيجاد تلك الأحداث التي خاصيّة name لها هي النّص “sent email”: memsql> select * from events where event::$name = 'sent email';+----+-------------------------------------------------+ | id | event | +----+-------------------------------------------------+ | 1 | {"email":"one@example.com","name":"sent email"} | +----+-------------------------------------------------+ 1 row in set (0.00 sec)تم تنفيذ هذا الاستعلام الأخير بشكل أسرع من الاستعلام الذي سبقه لأنّنا غيّرنا فقط مُعامِل في الاستعلام، لذا كانت MemSQL قادرة على تخطّي توليد الشيفرة. فلنقم بعمل شيء أكثر تقدّمًا بالنسبة لقاعدة بيانات SQL مُوزَّعة، وهو ضم جدولين على أساس مفاتيح غير أساسيّة non-primary حيث يتم تداخل قيمة ما من الانضمام join بداخل قيمة JSON ولكن يكون الترشيح filter على أساس قيمة JSON مختلفة. نسأل في البداية عن كافّة حقول جدول المستخدمين users مع ضم جدول الأحداث events بمطابقة حقل البريد الإلكتروني email حيث يكون اسم الحدث هو “received email”. memsql> select * from users left join events on users.email = events.event::$email where events.event::$name = 'received email';+----+-----------------+------+-----------------------------------------------------+ | id | email | id | event | +----+-----------------+------+-----------------------------------------------------+ | 2 | two@example.com | 2 | {"email":"two@example.com","name":"received email"} | +----+-----------------+------+-----------------------------------------------------+ 1 row in set (14.19 sec)نجرب بعد ذلك نفس الاستعلام ولكن مع ترشيح الأحداث “sent email” فقط: memsql> select * from users left join events on users.email = events.event::$email where events.event::$name = 'sent email'; +----+-----------------+------+-------------------------------------------------+ | id | email | id | event | +----+-----------------+------+-------------------------------------------------+ | 1 | one@example.com | 1 | {"email":"one@example.com","name":"sent email"} | +----+-----------------+------+-------------------------------------------------+ 1 row in set (0.01 sec)وكما وجدنا سابقًا فإنّ الاستعلام الثاني أسرع بكثير من الأول، تظهر فائدة توليد الشيفرة عند تنفيذ أكثر من مليون صف، كما رأينا في قياس الأداء، إنّ مرونة استخدام قواعد بيانات SQL تفهم JSON وكيفيّة الانضمام بين الجداول هي ميزة قوية للمستخدمين. الخاتمةلقد قمنا بتثبيت MemSQL، تنفيذ تجربة قياس أداء العقد لدينا، التعامل مع العقدة من خلال عميل MySQL المعياري، وتعاملنا مع بعض الميّزات المتقدمة غير الموجودة في MySQL، ينبغي أن يعطينا هذا فكرة واضحة عمّا يمكن أن تفعله قاعدة بيانات SQL داخل الذاكرة لنا. لا يزال هناك الكثير لتعلّمه حول كيفيّة توزيع MemSQL لبياناتنا فعليًّا، كيفية بناء الجداول من أجل أفضل أداء، كيفيّة توسيع MemSQL عبر عدّة عقد، كيفيّة تكرار بياناتنا من أجل توافريّة عالية للبيانات، وكيفيّة تأمين MemSQL. ترجمة -وبتصرّف- لـ How to Install MemSQL on Ubuntu 14.04 لصاحبه Ian Hansen.
×
×
  • أضف...