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

kinan mawed

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

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

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

1 متابع

آخر الزوار

لوحة آخر الزوار معطلة ولن تظهر للأعضاء

إنجازات kinan mawed

عضو مساهم

عضو مساهم (2/3)

14

السمعة بالموقع

  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.
×
×
  • أضف...