<?xml version="1.0"?>
<rss version="2.0"><channel><title>DevOps: Ansible</title><link>https://academy.hsoub.com/devops/deployment/ansible/?d=4</link><description>DevOps: Ansible</description><language>ar</language><item><title>&#x643;&#x62A;&#x627;&#x628;&#x629; &#x62F;&#x644;&#x64A;&#x644; &#x62A;&#x634;&#x63A;&#x64A;&#x644; &#x627;&#x644;&#x623;&#x62F;&#x627;&#x629; Ansible &#x639;&#x646;&#x62F; &#x625;&#x62F;&#x627;&#x631;&#x629; &#x636;&#x628;&#x637; &#x627;&#x644;&#x62E;&#x648;&#x627;&#x62F;&#x645;</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%AF%D9%84%D9%8A%D9%84-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A9-ansible-%D8%B9%D9%86%D8%AF-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%AF%D9%85-r690/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_03/----Configuration-Management-----Ansible.png.5e25c3cf465a42346afa6159d9b0ee37.png" /></p>
<p>
	تُعَد إدارة ضبط الخادم (يُشار إليها أيضًا باسم أتمتة تقانة المعلومات IT Automation) حلًا لتحويل إدارة بنيتك التحتية إلى الشيفرة البرمجية الأساسية، ولوصف جميع العمليات اللازمة لنشر خادم في مجموعة من سكربتات الإعداد المسبق Provisioning Scripts التي يمكن إصدارها وإعادة استخدامها بسهولة، ويمكنها تحسين التكامل لأيّ بنية خادم تحتية بصورة كبيرة بمرور الوقت.
</p>

<p>
	تحدثنا في المقال السابق <a href="https://academy.hsoub.com/devops/deployment/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%AF%D9%85-configuration-management-r689/" rel="">مدخل إلى إدارة ضبط الخوادم Configuration Management</a> عن الفوائد الرئيسية لتنفيذ إستراتيجية إدارة الضبط لبنية الخادم التحتية، وكيفية عمل أدوات إدارة الضبط والعناصر المشتركة بين هذه الأدوات، وسنوضح في هذا المقال عملية أتمتة إعداد الخادم المسبق باستخدام الأداة <a href="https://academy.hsoub.com/devops/deployment/ansible/" rel="">Ansible</a>، وهي أداة لإدارة الضبط توفر إطار عمل أتمتة كامل وقدرات تنسيق مع الحفاظ على هدف السهولة والبساطة المطلقة، وسنركز على مصطلحات اللغة والصياغة والميزات اللازمة لإنشاء مثال مبسّط للأتمتة الكاملة لنشر خادم ويب أوبنتو 18.04 باستخدام أباتشي Apache.
</p>

<p>
	تحتوي القائمة التالية على جميع الخطوات التي نحتاجها للأتمتة حتى الوصول إلى هدفنا:
</p>

<ul>
	<li>
		قائمة الحزم.
	</li>
	<li>
		ثبّت أباتشي Apache.
	</li>
	<li>
		أنشئ مجلد المستند الجذر المُخصَّص.
	</li>
	<li>
		ضع ملف <code>index.html</code> في المستند الجذر المخصص.
	</li>
	<li>
		طبّق قالبًا لإعداد المضيف الوهمي المخصص.
	</li>
	<li>
		أعِد تشغيل أباتشي.
	</li>
</ul>

<p>
	سنبدأ بإلقاء نظرة على المصطلحات التي تستخدمها أداة Ansible، ثم سنتعرّف على ميزات اللغة الرئيسية التي يمكن استخدامها لكتابة أدلة التشغيل Playbooks، ثم ستجد محتويات مثال الإعداد المسبق الكامل لأتمتة الخطوات الموضحة لإعداد أباتشي على Ubuntu 18.04.
</p>

<p>
	<strong>ملاحظة</strong>: يهدف هذا المقال إلى تعريفك بلغة Ansible وكيفية كتابة أدلة التشغيل لأتمتة إعداد خادمك المسبق. اطّلع على <a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-ansible-%D8%B9%D9%84%D9%89-ubuntu-1804-r394/" rel="">كيفيّة تثبيت وضبط Ansible على Ubuntu 18.04</a> لمعرفة الخطوات اللازمة لتثبيت أداة Ansible والبدء باستخدامها، بالإضافة إلى كيفية تشغيل أوامر Ansible وأدلة تشغيلها.
</p>

<p>
	هذا المقال جزء من سلسلة حول إدارة ضبط الخوادم، وإليك روابط فصول السلسلة:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%AF%D9%85-configuration-management-r689/" rel="">مدخل إلى إدارة ضبط الخوادم Configuration Management</a>
	</li>
	<li>
		<span ipsnoautolink="true">مبادئ إدارة ضبط الخوادم Configuration Management: كتابة دليل تشغيل الأداة Ansible</span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/puppet/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%AF%D9%85-configuration-management-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86-manifests-%D9%84%D9%84%D8%A3%D8%AF%D8%A7%D8%A9-puppet-r691/" rel="">مبادئ إدارة ضبط الخوادم Configuration Management: كتابة ملفات البيان Manifests للأداة Puppet</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/chef/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%AF%D9%85-configuration-management-%D9%83%D8%AA%D8%A7%D8%A8%D8%A9-%D8%A7%D9%84%D9%88%D8%B5%D9%81%D8%A7%D8%AA-recipes-%D9%81%D9%8A-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A9-chef-r692/" rel="">مبادئ إدارة ضبط الخوادم Configuration Management: كتابة الوصفات Recipes في الأداة Chef</a>
	</li>
</ul>

<h2>
	البدء باستخدام أداة Ansible
</h2>

<p>
	يجب أن نتعرف أولًا على المصطلحات والمفاهيم المهمة التي قدمتها أداة Ansible قبل البدء بالعمل.
</p>

<h3>
	المصطلحات
</h3>

<p>
	تحتوي القائمة التالية على نظرة عامة سريعة على المصطلحات الأهم التي تستخدمها أداة Ansible:
</p>

<ul>
	<li>
		عقدة التحكم Control Node: الجهاز المُثبّت عليه أداة Ansible، وهو المسؤول عن تشغيل الإعداد المسبق على الخوادم التي تديرها.
	</li>
	<li>
		المخزن Inventory: ملف <code>INI</code> يحتوي على معلومات حول الخوادم التي تديرها.
	</li>
	<li>
		دليل التشغيل Playbook: ملف <code>YAML</code> يحتوي على سلسلة من الإجراءات التي يجب أن تكون مؤتمتة.
	</li>
	<li>
		المهمة Task: كتلة تحدد إجراءً واحدًا لتنفيذه مثل تثبيت حزمة.
	</li>
	<li>
		الوحدة Module: تجرّد الوحدة مهمة النظام مثل التعامل مع الحزم أو إنشاء وتغيير الملفات. تحتوي أداة Ansible على العديد من الوحدات المبنية مسبقًا، ولكن يمكنك إنشاء وحداتك المُخصَّصة.
	</li>
	<li>
		الدور Role: مجموعة من أدلة التشغيل والقوالب والملفات الأخرى ذات الصلة، وهي منظمة بطريقة مُعرَّفة مسبقًا لتسهيل إعادة الاستخدام والمشاركة.
	</li>
	<li>
		التشغيل Play: هو الإعداد المسبق المنفَّذ من البداية إلى النهاية.
	</li>
	<li>
		الحقائق Facts: المتغيرات العامة التي تحتوي على معلومات حول النظام مثل واجهات الشبكة أو <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">نظام التشغيل</a>.
	</li>
	<li>
		المعالجات Handlers: تُستخدَم لبدء تغييرات حالة الخدمة مثل إعادة تشغيل الخدمة أو إعادة تحميلها.
	</li>
</ul>

<h3>
	تنسيق المهمة
</h3>

<p>
	تحدّد المهمة خطوة مؤتمتة واحدة يجب أن تنفّذها الأداة Ansible، وتتضمن عادةً استخدام وحدة Module أو تنفيذ أمر خام Raw Command، حيث تبدو المهمة كما يلي:
</p>

<pre class="ipsCode">- name: This is a task
  apt: name=vim state=latest
</pre>

<p>
	يُعَد الجزء <code>name</code> اختياريًا ولكن يُوصَى به، حيث يظهر في مخرجات الإعداد المسبق عند تنفيذ المهمة، والجزء <code>apt</code> هو وحدة Ansible مبنية مسبقًا تجرّد إدارة الحزم في التوزيعات القائمة على نظام دبيان Debian. تخبر المهمة في المثال السابق أداة Ansible أن الحزمة <code>vim</code> يجب أن تتغير حالتها إلى الأحدث <code>latest</code>، مما يؤدي إلى أن يثبّت مدير الحزم هذه الحزمة في حالة عدم تثبيتها بعد.
</p>

<h3>
	تنسيق دليل التشغيل
</h3>

<p>
	أدلة التشغيل هي ملفات <code>YAML</code> تحتوي على سلسلة من الموجّهات Directives لأتمتة إعداد <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a> المسبق. يوضّح المثال التالي دليل تشغيل بسيط يؤدي مهمتين هما: تحديث ذاكرة <code>apt</code> المخبئية ثم تثبيت حزمة <code>vim</code>:
</p>

<pre class="ipsCode">---
- hosts: all
  become: true
  tasks:
     - name: Update apt-cache 
       apt: update_cache=yes

     - name: Install Vim
       apt: name=vim state=latest
</pre>

<p>
	تعتمد لغة <code>YAML</code> على المسافة البادئة لسَلسلة بنى البيانات، لذا يجب أن تكون حريصًا للحفاظ على المسافة البادئة الصحيحة عند كتابة أدلة التشغيل وخاصة عند نسخ الأمثلة.
</p>

<p>
	سنرى في نهاية المقال مثالًا واقعيًا لأدلة التشغيل بالتفصيل، ولكن سيعطيك القسم التالي نظرة عامة على أهم العناصر والميزات التي يمكن استخدامها لكتابة دليل تشغيل Ansible.
</p>

<h2>
	كتابة أدلة التشغيل
</h2>

<p>
	أصبحت الآن على دراية بالمصطلحات الأساسية والتنسيق العام لأدلة التشغيل والمهام في Ansible، لذا سنتعرف على بعض ميزات دليل التشغيل التي يمكن أن تساعدنا في إنشاء عمليات أتمتة أكثر تنوعًا.
</p>

<h3>
	التعامل مع المتغيرات
</h3>

<p>
	هناك طرق مختلفة يمكنك من خلالها تعريف المتغيرات في أداة Ansible، ولكن أبسط طريقة هي استخدام القسم <code>vars</code> في دليل التشغيل. يعرّف المثال التالي المتغير <code>package</code> الذي سنستخدمه لاحقًا ضمن مهمة:
</p>

<pre class="ipsCode">---
- hosts: all
  become: true
  vars:
     package: vim
  tasks:
     - name: Install Package
       apt: name={{ package }} state=latest
</pre>

<p>
	للمتغير <code>package</code> نطاق عام، مما يعني أنه يمكن الوصول إليه من أي نقطة في الإعداد المسبق حتى من الملفات والقوالب المُضمَّنة.
</p>

<h3>
	استخدام الحلقات
</h3>

<p>
	تُستخدَم الحلقات عادةً لتكرار مهمة باستخدام قيم دخل مختلفة، فمثلًا يمكنك إنشاء مهمة واحدة واستخدام حلقة لتكرار المهمة مع جميع الحزم المختلفة التي تريد تثبيتها بدلًا من إنشاء 10 مهام لتثبيت 10 حزم مختلفة.
</p>

<p>
	يمكنك إنشاء حلقة ضمن مهمة من خلال تضمين الخيار <code>with_items</code> مع مصفوفة من القيم، ويمكن الوصول إلى المحتوى باستخدام متغير الحلقة <code>item</code> كما هو موضح في المثال التالي:
</p>

<pre class="ipsCode">- name: Install Packages
  apt: name={{ item }} state=latest
  with_items:
     - vim
     - git
     - curl 
</pre>

<p>
	ويمكنك استخدام متغير مصفوفة لتعريف عناصرك:
</p>

<pre class="ipsCode">---
- hosts: all
  become: true
  vars:
     packages: [ 'vim', 'git', 'curl' ]
  tasks:
     - name: Install Package
       apt: name={{ item }} state=latest
       with_items: "{{ packages }}"
</pre>

<h3>
	استخدام التعليمات الشرطية
</h3>

<p>
	يمكنك استخدام التعليمات الشرطية لتقرير ما إذا كان يجب تنفيذ مهمة ما أم لا ديناميكيًا بناءً على متغير أو خرج أمرٍ ما مثلًا، حيث سيوقف المثال التالي الأنظمة القائمة على دبيان فقط:
</p>

<pre class="ipsCode">- name: Shutdown Debian Based Systems
  command: /sbin/shutdown -t now
  when: ansible_os_family == "Debian"
</pre>

<p>
	تأخذ التعليمة الشرطية <code>when</code> تعبيرًا يجب تقييمه بوصفه وسيطًا، إذ لا تُنفَّذ المهمة إلا في حالة تقييم التعبير على أنه <code>true</code>، حيث اختبرنا في مثالنا حقيقةً Fact للتحقق مما إذا كان نظام التشغيل من عائلة دبيان.
</p>

<p>
	حالة الاستخدام الشائعة للتعليمات الشرطية في أتمتة تقانة المعلومات هي عندما يعتمد تنفيذ مهمة على خرج أمرٍ ما، والطريقة التي نطبّق بها ذلك باستخدام أداة Ansible هي من خلال تسجيل متغير ليحتفظ بنتائج تنفيذ الأمر، ثم اختبار هذا المتغير في مهمة لاحقة. يمكننا اختبار حالة خروج الأمر (إذا فشل أو نجح)، ويمكننا التحقق من وجود محتويات معينة في الخرج بالرغم من أن ذلك يمكن أن يتطلب استخدام <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/" rel="">تعابير نمطية RegEx</a> وأوامر تحليل السلاسل النصية.
</p>

<p>
	يوضح المثال الآتي مهمتين شرطيتين بناءً على خرج الأمر <code>php -v</code>، حيث سنختبر حالة الخروج من الأمر، لأننا نعلم أنه سيفشل في التنفيذ في حالة عدم تثبيت <a href="https://academy.hsoub.com/programming/php/%D8%AA%D9%85%D9%87%D9%8A%D8%AF-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-php-r235/" rel="">PHP</a> على الخادم، ويُعَد الجزء <code>ignore_errors</code> من المهمة مهمًا للتأكد من استمرار الإعداد المسبق حتى عندما يفشل تنفيذ الأمر.
</p>

<pre class="ipsCode">- name: Check if PHP is installed
  register: php_installed
  command: php -v
  ignore_errors: true

- name: This task is only executed if PHP is installed
  debug: var=php_install
  when: php_installed|success

- name: This task is only executed if PHP is NOT installed
  debug: msg='PHP is NOT installed'
  when: php_installed|failed
</pre>

<p>
	الوحدة <code>debug</code> المُستخدَمة في مثالنا هي وحدة مفيدة لعرض محتويات المتغيرات أو رسائل تنقيح الأخطاء، إذ يمكنها إما طباعة سلسلة نصية (عند استخدام الوسيط <code>msg</code>) أو طباعة محتويات متغير (عند استخدام الوسيط <code>var</code>).
</p>

<h3>
	التعامل مع القوالب
</h3>

<p>
	تُستخدَم القوالب عادةً لإعداد ملفات الضبط، مما يسمح باستخدام المتغيرات والميزات الأخرى التي تهدف إلى جعل هذه الملفات أكثر تنوعًا وقابلية لإعادة الاستخدام، حيث تستخدم أداة Ansible <a href="https://academy.hsoub.com/programming/python/flask/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D9%84%D8%A8-jinja-%D8%A7%D9%84%D8%AF%D9%88%D8%A7%D9%84-%D9%88%D8%A7%D9%84%D9%85%D8%B1%D8%B4%D8%AD%D8%A7%D8%AA-r440/" rel="">محرك القوالب Jinja2</a>.
</p>

<p>
	يوضَح المثال التالي قالبًا لإعداد مضيف أباتشي الوهمي باستخدام متغيرٍ لإعداد المستند الجذر لهذا المضيف:
</p>

<pre class="ipsCode">&lt;VirtualHost *:80&gt;
    ServerAdmin webmaster@localhost
    DocumentRoot {{ doc_root }}

    &lt;Directory {{ doc_root }}&gt;
        AllowOverride All
        Require all granted
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>

<p>
	تُستخدَم الوحدة <code>template</code> المبنية مسبقًا لتطبيق القالب من مهمةٍ ما، فإذا سمّيتَ ملف القالب السابق بالاسم <code>vhost.tpl</code>، ووضعته في في مجلد دليل تشغيلك نفسه، فالطريقة التالية هي الطريقة التي ستطبِّق بها القالب لاستبدال مضيف أباتشي الوهمي الافتراضي:
</p>

<pre class="ipsCode">- name: Change default Apache virtual host
  template:
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf
</pre>

<h3>
	تعريف المعالجات Handlers وتشغيلها
</h3>

<p>
	تُستخدَم المعالجات لبدء تغيير الحالة في خدمة ما مثل إعادة التشغيل أو الإيقاف، حيث لا تنفَّذ المعالجات إلّا عندما يبدؤها الموجّه <code>notify</code> مسبقًا في مهمةٍ ما بالرغم من أنها تبدو متشابهة إلى حدٍ ما مع المهام العادية. تُعرَّف المعالجات عادةً بوصفها مصفوفة في القسم <code>handlers</code> من دليل التشغيل، ولكن يمكن أن تكون موجودةً في ملفات منفصلة أيضًا.
</p>

<p>
	لنأخذ مثالنا السابق لاستخدام القالب حيث ضبطنا مضيف أباتشي الوهمي. إذا أردت التأكد من إعادة تشغيل أباتشي بعد تغيير المضيف الوهمي، فيجب أولًا إنشاء معالج لخدمة أباتشي، حيث تمثل الطريقة التالي طريقةَ تعريف المعالجات ضمن دليل التشغيل:
</p>

<pre class="ipsCode">handlers:
    - name: restart apache
      service: name=apache2 state=restarted

    - name: other handler
      service: name=other state=restarted
</pre>

<p>
	يُعَد الموجّه <code>name</code> مهمًا لأنه سيكون المعرّف الفريد لهذا المعالج، ويمكنك بدء هذا المعالج من مهمة من خلال استخدام الخيار <code>notify</code> كما يلي:
</p>

<pre class="ipsCode">- name: Change default Apache virtual host
  template:
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf
  notify: restart apache
</pre>

<p>
	رأينا بعضًا من أهم الميزات التي يمكنك استخدامها لبدء كتابة أدلة تشغيل Ansible، وسنتعمق في القسم التالي في مثال أكثر واقعية عن دليل التشغيل الذي سيؤتمِت تثبيت أباتشي وضبطه على أوبنتو 18.04.
</p>

<h2>
	تطبيق عملي عن دليل التشغيل
</h2>

<p>
	لنلقِ الآن نظرة على دليل التشغيل الذي سيؤتمِت تثبيت خادم ويب أباتشي على نظام أوبنتو 18.04. يمكن العثور على المثال الكامل بما في ذلك ملف القالب لإعداد أباتشي وملف <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> ليخدّمه خادم الويب على <a href="https://github.com/erikaheidi/cfmgmt/tree/master/ansible" rel="external nofollow">GitHub</a>، ويحتوي المجلد أيضًا على الملف Vagrantfile الذي يتيح لك اختبار دليل التشغيل في إعداد مبسط باستخدام آلة افتراضية تديرها أداة Vagrant.
</p>

<h3>
	محتويات دليل التشغيل
</h3>

<p>
	إليك المحتويات الكاملة لدليل التشغيل:
</p>

<pre class="ipsCode">---
- hosts: all
  become: true
  vars:
    doc_root: /var/www/example
  tasks:
    - name: Update apt
    apt: update_cache=yes

    - name: Install Apache
    apt: name=apache2 state=latest

    - name: Create custom document root
    file: path={{ doc_root }} state=directory owner=www-data group=www-data

    - name: Set up HTML file
    copy: src=index.html dest={{ doc_root }}/index.html owner=www-data group=www-data mode=0644

    - name: Set up Apache virtual host file
    template: src=vhost.tpl dest=/etc/apache2/sites-available/000-default.conf
    notify: restart apache
  handlers:
    - name: restart apache
    service: name=apache2 state=restarted
</pre>

<p>
	لنتعرّف على كل جزء من دليل التشغيل بمزيد من التفصيل:
</p>

<ul>
	<li>
		<code>hosts: all</code>: يبدأ دليل التشغيل بالإشارة إلى وجوب تطبيقه على جميع <code>all</code> المضيفين في مخزونك (<code>hosts: all</code>). يمكن تقييد تنفيذ دليل التشغيل على مضيف معين أو مجموعة من المضيفين، ويمكن تعديل هذا الخيار في وقت التنفيذ.
	</li>
	<li>
		<code>become: true</code>: يخبر هذا الجزء الأداة Ansible باستخدام ارتقاء الصلاحيات sudo لتنفيذ جميع المهام في دليل التشغيل، ويمكن تعديل هذا الخيار لتنفيذ مهمة تلوَ الأخرى.
	</li>
	<li>
		vars: يعرّف هذا الجزء متغيرًا هو <code>doc_root</code> الذي يُستخدَم لاحقًا في مهمة، ويمكن أن يحتوي على متغيرات متعددة.
	</li>
	<li>
		tasks : تُعرَّف المهام الفعلية في هذا القسم، حيث تحدِّث المهمة الأولى ذاكرة <code>apt</code> المخبئية، وتثبّت المهمة الثانية الحزمة <code>apache2</code>. تستخدم المهمة الثالثة ملف الوحدة المبنية مسبقًا لإنشاء مجلد ليكون بمثابة المستند الجذر، ويمكن استخدام هذه الوحدة لإدارة الملفات والمجلدات، وتستخدم المهمة الرابعة نسخة الوحدة لنسخ ملف محلي إلى الخادم البعيد، حيث سننسخ ملف HTML بسيط لتقديمه بوصفه موقع ويب يستضيفه أباتشي.
	</li>
	<li>
		handlers: يُصرَّح عن الخدمات في القسم <code>handlers</code>. عرّفنا المعالج <code>restart apache</code> الذي يُعلَم من المهمة الرابعة في مكان تطبيق قالب أباتشي.
	</li>
</ul>

<h3>
	بدء تنفيذ دليل التشغيل
</h3>

<p>
	يمكنك استخدام دليل التشغيل <code>ansible-playbook</code> لتنفيذه على عقدة واحدة أو أكثر من مخزونك بعد تنزيل محتويات دليل التشغيل إلى عقدة تحكم Ansible، حيث ينفّذ الأمر التالي دليل التشغيل على جميع المضيفين من ملف مخزونك الافتراضي باستخدام استيثاق زوج مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr> للاتصال كمستخدم النظام الحالي:
</p>

<pre class="ipsCode">ansible-playbook playbook.yml
</pre>

<p>
	يمكنك استخدام <code>‎-l</code> لقصر التنفيذ على مضيف واحد أو مجموعة مضيفين من مخزونك كما يلي:
</p>

<pre class="ipsCode">ansible-playbook -l host_or_group playbook.yml
</pre>

<p>
	إذا أردتَ تحديد مستخدم <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr> مختلف للاتصال بالخادم البعيد، فيمكنك تضمين الوسيط <code>‎-u user</code> في هذا الأمر كما يلي:
</p>

<pre class="ipsCode">ansible-playbook -l host_or_group playbook.yml -u remote-user
</pre>

<p>
	يرجى الاطلاع على <a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-ansible-%D8%B9%D9%84%D9%89-ubuntu-1804-r394/" rel="">كيفية تثبيت وضبط Ansible على Ubuntu 18.04</a> لمزيد من المعلومات حول كيفية تشغيل أوامر وأدلة تشغيل Ansible.
</p>

<h2>
	الخلاصة
</h2>

<p>
	تُعَد Ansible أداة أتمتة بسيطة لتقانة المعلومات لديها مسار تعليمي بسيط، وتستخدم لغة YAML لسكربتات الإعداد المسبق، وتحتوي على عدد كبير من الوحدات المبنية مسبقًا التي يمكن استخدامها لتجريد المهام مثل تثبيت الحزم والعمل مع القوالب. يمكن أن تكون متطلبات البنية التحتية المبسطة واللغة البسيطة مناسبة جدًا للأشخاص المبتدئين في مجال إدارة الضبط، ولكنها يمكن أن تفتقر إلى بعض الميزات المتقدمة التي يمكنك العثور عليها باستخدام أدوات أكثر تعقيدًا مثل Puppet و Chef.
</p>

<p>
	سنتعرّف في المقال التالي على الأداة Puppet، وهي أداة إدارة ضبط شائعة تستخدم لغة DSL مخصصة قوية وتعتمد على لغة روبي Ruby لكتابة سكربتات الإعداد المسبق.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/configuration-management-101-writing-ansible-playbooks" rel="external nofollow">Configuration Management 101: Writing Ansible Playbooks</a> لصاحبته Erika Heidi.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/linux/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%A7%D8%B9%D8%AF-ansible-%D8%B9%D9%84%D9%89-%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%B3%D9%8A%D8%B7%D8%A9-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%AD%D9%88%D8%A7%D8%B3%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D9%86%D8%B2%D9%84-r635/" rel="">كيف تساعد Ansible على أتمتة مهام بسيطة لإدارة حواسيب المنزل</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-ansible-r637/" rel="">مدخل إلى وحدات Ansible</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">690</guid><pubDate>Tue, 28 Mar 2023 13:09:00 +0000</pubDate></item><item><title>&#x623;&#x62A;&#x645;&#x62A;&#x629; &#x625;&#x639;&#x62F;&#x627;&#x62F; &#x62E;&#x627;&#x62F;&#x645; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x623;&#x62F;&#x627;&#x629; Ansible</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%AF%D8%A7%D8%A9-ansible-r688/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_03/-----Ansible.png.74d1a71c830b4a9a116a97a107229dd0.png" /></p>
<p>
	تلعب عملية أتمتة الخادم server automation الآن دورًا أساسيًا في إدارة الأنظمة نظرًا لطبيعة بيئات التطبيقات الحديثة التي تُستخدَم لمرة واحدة ثم يمكنك التخلص منها، إذ تُستخدَم أدوات <a href="https://academy.hsoub.com/devops/deployment/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%AF%D9%85-configuration-management-r689/" rel="">إدارة الضبط Configuration management</a> مثل أداة <span ipsnoautolink="true">Ansible</span> لتبسيط عملية إعداد الخادم من خلال إنشاء إجراءات معيارية للخوادم الجديدة، مما يقلل من الأخطاء البشرية المرتبطة بالإعدادات اليدوية. لذا تقدّم أداة Ansible معمارية مبسَّطة لا تتطلب تثبيت برامج خاصة على العُقد، وتوفر مجموعة من الميزات والوحدات المبنية مسبقًا والتي تسهل كتابة سكربتات الأتمتة.
</p>

<p>
	سيوضح هذا المقال كيفية إعداد ملف المخزون Inventory File وتنفيذ مجموعة من سكربتات الإعداد المسبَق Provisioning لأتمتة عملية إعداد خادم حزمة LEMP أو (Linux و ‎(E)nginx و MariaDB و PHP-FPM) على أوبنتو ونشر تطبيق <a href="https://academy.hsoub.com/programming/php/laravel/" rel="">لارافيل Laravel</a> التجريبي على هذا النظام.
</p>

<p>
	<strong>ملاحظة</strong>: يهدف هذا المقال إلى توضيح كيفية استخدام أدلة التشغيل Playbooks لأتمتة إعداد الخادم باستخدام <a href="https://academy.hsoub.com/devops/deployment/ansible/" rel="">أداة Ansible</a>، ونشجعك على تعديل وتكييف الإعداد المضمَّن ليناسب احتياجاتك الخاصة بالرغم من أننا سنستخدم تطبيق لارافيل الذي يعمل على خادم LEMP.
</p>

<h2>
	المتطلبات الأساسية
</h2>

<p>
	ستحتاج ما يلي لمتابعة هذا المقال:
</p>

<ul>
	<li>
		عقدة تحكم Ansible واحدة: وهي جهاز يعمل بنظام أوبنتو 22.04 مع تثبيت أداة Ansible عليه وضبطه للاتصال بمضيفات Ansible باستخدام <a href="https://academy.hsoub.com/devops/security/ssh/%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%85%D8%B9-%D8%AE%D9%88%D8%A7%D8%AF%D9%8A%D9%85-ssh-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D8%A7%D8%A1-%D9%88%D8%A7%D9%84%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD-r55/" rel="">مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr></a>. تأكّد من أن عقدة التحكم لديها مستخدم عادي يمتلك أذونات مستخدم sudo (أذونات المستخدم الجذر) مع تفعيل جدار حماية، وتعلّم <a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-ansible-%D8%B9%D9%84%D9%89-ubuntu-1804-r394/" rel="">كيفية تثبيت وضبط Ansible على أوبنتو</a> لإعداد الأداة Ansible.
	</li>
	<li>
		مضيف Ansible واحد أو أكثر: هو خادم أوبنتو واحد أو أكثر، إذ يجب أن يكون لكل مضيفٍ المفتاح العام لعقدة التحكم الذي يُضاف إلى ملف <code>authorized_keys</code>. إن أردتَ استخدام <a href="https://www.digitalocean.com/products/droplets" rel="external nofollow">أجهزة DigitalOcean Droplets الافتراضية</a> بوصفها عقدًا، فيمكنك استخدام <a href="https://docs.digitalocean.com/products/droplets/how-to/add-ssh-keys/" rel="external nofollow">لوحة التحكم</a> لإضافة مفتاحك العام إلى مضيفات Ansible.
	</li>
</ul>

<h2>
	الخطوة الأولى: نسخ المستودع التجريبي
</h2>

<p>
	يجب أولًا نسخ المستودع الذي يحتوي على سكربتات Ansible للإعداد المسبَق وتطبيق لارافيل التجريبي الذي سننشره على الخوادم البعيدة، حيث يمكن العثور على جميع الملفات الضرورية في مستودع جيت هَب <a href="https://github.com/do-community/ansible-laravel-demo" rel="external nofollow">do-community/ansible-laravel-demo</a>.
</p>

<p>
	انسخ المستودع بعد تسجيل الدخول إلى عقدة تحكم Ansible كمستخدم جذر sudo، وانتقل إلى المجلد الذي ينشئه الأمر <code>git</code> كما يلي:
</p>

<pre class="ipsCode">git clone https://github.com/do-community/ansible-laravel-demo.git
cd ansible-laravel-demo
</pre>

<p>
	يمكنك الآن تشغيل الأمر <code>ls</code> لفحص محتويات المستودع المنسوخ كما يلي:
</p>

<pre class="ipsCode">ls -l --group-directories-first
</pre>

<p>
	وسترى خرجًا يشبه التالي:
</p>

<pre class="ipsCode">drwxrwxr-x 3 sammy sammy 4096 Mar 24 15:24 application
drwxrwxr-x 2 sammy sammy 4096 Mar 24 15:24 group_vars
drwxrwxr-x 7 sammy sammy 4096 Mar 24 15:24 roles
-rw-rw-r-- 1 sammy sammy  102 Mar 24 15:24 inventory-example
-rw-rw-r-- 1 sammy sammy 1987 Mar 24 15:24 laravel-deploy.yml
-rw-rw-r-- 1 sammy sammy  794 Mar 24 15:24 laravel-env.j2
-rw-rw-r-- 1 sammy sammy  920 Mar 24 15:24 readme.md
-rw-rw-r-- 1 sammy sammy  318 Mar 24 15:24 server-setup.yml
</pre>

<p>
	إليك نظرة عامة على المجلدات والملفات السابقة:
</p>

<ul>
	<li>
		<code>application/‎</code>: يحتوي هذا المجلد على تطبيق لارافيل التجريبي الذي سننشره على الخادم البعيد في النهاية.
	</li>
	<li>
		<code>group_vars/‎</code>: يحتوي هذا المجلد على ملفات المتغيرات التي تحتوي على خيارات مُخصَّصة لإعداد التطبيق مثل ثبوتيات Credentials <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قاعدة البيانات</a> ومكان تخزين ملفات التطبيق على <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">الخادم</a> البعيد.
	</li>
	<li>
		<code>roles/‎</code>: يحتوي هذا المجلد على أدوار Ansible المختلفة التي تعالج الإعداد المسبَق لخادم Ubuntu LEMP.
	</li>
	<li>
		<code>inventory-example</code>: يمكن استخدام هذا الملف بوصفه قاعدةً لإنشاء مخزون مُخصَّص لبنيتك التحتية.
	</li>
	<li>
		<code>laravel-deploy.yml</code>: دليل التشغيل الذي سينشر تطبيق لارافيل التجريبي على الخادم البعيد.
	</li>
	<li>
		<code>laravel-env.j2</code>: يستخدم دليلُ التشغيل <code>laravel-deploy.yml</code> هذا القالب لإعداد ملف بيئة التطبيق.
	</li>
	<li>
		<code>readme.md</code>: يحتوي هذا الملف على معلومات عامة حول الإعداد المسبَق المتضمن في هذا المستودع.
	</li>
	<li>
		<code>server-setup.yml</code>: سيُعِدّ دليل التشغيل هذا مسبقًا خادم LEMP باستخدام الأدوار المُحدَّدة في المجلد <code>roles/‎</code>.
	</li>
</ul>

<h2>
	الخطوة الثانية: إعداد ملف المخزون واختبار الاتصال بالعقد
</h2>

<p>
	سننشئ الآن ملف مخزون لسرد المضيفين الذين نريد إدارتهم باستخدام أداة Ansible. انسخ أولًا الملف <code>inventory-example</code> إلى ملف جديد يسمى <code>hosts</code>:
</p>

<pre class="ipsCode">cp inventory-example hosts
</pre>

<p>
	استخدم محرر النصوص الذي تريده لفتح ملف المخزون الجديد وحدّثه باستخدام خوادمك الخاصة، إذ سنستخدم في مثالنا محرر النصوص <code>nano</code>:
</p>

<pre class="ipsCode">nano hosts
</pre>

<p>
	يحتوي المخزون في مثالنا على مجموعتين هما: التطوير <code>dev</code> والإنتاج <code>production</code> اللتان توضحان كيفية استخدام متغيرات المجموعة لتخصيص النشر في بيئات متعددة. إذا أردتَ اختبار هذا الإعداد باستخدام عقدة واحدة، فيمكنك استخدام إما مجموعة التطوير <code>dev</code> أو مجموعة الإنتاج <code>production</code> وإزالة المجموعة الأخرى من ملف المخزون.
</p>

<pre class="ipsCode">[dev]
203.0.113.0.101

[prod]
203.0.113.0.102

[all:vars]
ansible_python_interpreter=/usr/bin/python3
</pre>

<p>
	<strong>ملاحظة</strong>: يحدّد المتغير <code>ansible_python_interpreter</code> المسار إلى ملف بايثون التنفيذي على المضيف البعيد، ونطلب هناك من أداة Ansible أن تضبط هذا المتغير لجميع المضيفات في ملف المخزون.
</p>

<p>
	احفظ وأغلق الملف عند الانتهاء، فإذا أردتَ استخدام محرر النصوص <code>nano</code>، فيمكنك ذلك عن طريق الضغط على الاختصار "CTRL+X" ثم نضغط "Y" وزر الادخال "ENTER" للتأكيد.
</p>

<p>
	يمكنك بعد الانتهاء من ضبط ملف المخزون تنفيذ وحدة <code>ping</code> الخاصة بالأداة Ansible لاختبار ما إذا كانت عقدة التحكم قادرة على الاتصال بالمضيفين كما يلي:
</p>

<pre class="ipsCode">ansible all -i hosts -m ping -u root
</pre>

<p>
	لنتعرّف على الأمر السابق بالتفصيل:
</p>

<ul>
	<li>
		<code>all</code>: يخبر هذا الخيار أداة Ansible بتشغيل الأمر الذي يليه على جميع المضيفات من ملف المخزون المحدَّد.
	</li>
	<li>
		<code>‎-i hosts</code>: يحدد المخزون الذي يجب استخدامه، وإن لم يتوفّر هذا الخيار، فستحاول أداة Ansible استخدام المخزون الافتراضي الذي يوجد عادةً في المجلد <code>‎/etc/ansible/hosts</code>.
	</li>
	<li>
		<code>‎-m ping</code>: سيؤدي هذا الأمر إلى تنفيذ وحدة <code>ping</code> الخاصة بأداة Ansible، والتي ستختبر الاتصال بالعقد وما إذا كان يمكن العثور على ملف بايثون التنفيذي على الأنظمة البعيدة أم لا.
	</li>
	<li>
		<code>‎-u root</code>: يحدّد هذا الخيار المستخدم البعيد الذي يجب استخدامه للاتصال بالعقد، إذ نستخدم حساب الجذر في مثالنا لأنه الحساب الوحيد المتاح على خوادم جديدة. يمكن أن تكون خيارات الاتصال الأخرى ضرورية بناءً على مزود البنية التحتية وضبط <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr>.
	</li>
</ul>

<p>
	إذا ضُبِط اتصال <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr> بالعقد بصورة صحيحة، فستحصل على الخرج التالي:
</p>

<pre class="ipsCode">203.0.113.0.101 | SUCCESS =&gt; {
    "changed": false, 
    "ping": "pong"
}
203.0.113.0.102 | SUCCESS =&gt; {
    "changed": false, 
    "ping": "pong"
}
</pre>

<p>
	تعني الاستجابة <code>pong</code> أن عقدة التحكم الخاصة بك قادرة على الاتصال بالعقد المُدارة، وأن أداة Ansible قادرة على تنفيذ <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">أوامر بايثون</a> على المضيفين البعيدين.
</p>

<h2>
	الخطوة الثالثة: إعداد ملفات المتغيرات
</h2>

<p>
	يجب أولًا قبل تشغيل أدلة التشغيل المُضمَّنة في مثالنا تعديلُ ملف المتغيرات الذي يحتوي على إعدادات مثل اسم المستخدم البعيد الذي سيُنشَأ وثبوتيات قاعدة البيانات لإعدادها باستخدام قاعدة بيانات MariaDB.
</p>

<p>
	افتح الملف <code>group_vars/all</code> باستخدام محرر النصوص الذي تريده كما يلي:
</p>

<pre class="ipsCode">nano group_vars/all.yml
</pre>

<p>
	يحتوي هذا الملف على المحتويات التالية:
</p>

<pre class="ipsCode">---
# Initial Server Setup
remote_user: sammy

# MySQL Setup
mysql_root_password: MYSQL_ROOT_PASSWORD
mysql_app_db: travellist
mysql_app_user: travellist_user
mysql_app_pass: DB_PASSWORD

# Web Server Setup
http_host: "{{ ansible_facts.eth0.ipv4.address }}"
remote_www_root: /var/www
app_root_dir: travellist-demo
document_root: "{{ remote_www_root }}/{{ app_root_dir }}/public"

# Laravel Env Variables
app_name: Travellist
app_env: dev
app_debug: true
app_url: "http://{{ http_host }}"
db_host: localhost
db_port: 3306
db_database: "{{ mysql_app_db }}"
db_user: "{{ mysql_app_user }}"
db_pass: "{{ mysql_app_pass }}"
</pre>

<p>
	المتغيرات التي يجب معرفتها هي:
</p>

<ul>
	<li>
		<code>remote_user</code>: سيُنشَأ المستخدم المُحدَّد على الخادم البعيد وسيُمنَح صلاحيات المستخدم الجذر <code>sudo</code>.
	</li>
	<li>
		<code>mysql_root_password</code>: يحدّد هذا المتغير كلمة مرور قاعدة البيانات الجذر لخادم MariaDB، ولاحظ أنه يجب أن تكون كلمة مرور آمنة من اختيارك.
	</li>
	<li>
		<code>mysql_app_db</code>: اسم قاعدة البيانات المُراد إنشاؤها لتطبيق لارافيل. لست بحاجة إلى تغيير هذه القيمة، ولكن لك الحرية في تغييرها إذا أردتَ ذلك، حيث ستُستخدَم هذه القيمة لإعداد ملف ضبط لارافيل <code>‎.env</code>.
	</li>
	<li>
		<code>mysql_app_user</code>: اسم مستخدم قاعدة البيانات لتطبيق لارافيل. لست بحاجة إلى تغيير هذه القيمة، ولكن لك الحرية في تغييرها إذا أردتَ ذلك.
	</li>
	<li>
		<code>mysql_app_pass</code>: كلمة مرور قاعدة البيانات لتطبيق لارافيل، إذ يجب أن تكون كلمة مرور آمنة من اختيارك.
	</li>
	<li>
		<code>http_host</code>: اسم النطاق أو عنوان IP للمضيف البعيد. نستخدم في مثالنا حقيقة Fact خاصة بأداة Ansible التي تحتوي على عنوان IPv4 لواجهة الشبكة <code>eth0</code>. إذا كان هناك أسماء نطاقات تؤشّر إلى مضيفاتك البعيدة، فيمكن أن ترغب في إنشاء ملفات متغيرات منفصلة لكل منها، وتعديل هذه القيمة ليحتوي ضبطُ خادم Nginx على اسم المضيف الصحيح لكل خادم.
	</li>
</ul>

<p>
	احفظ الملف وأغلقه عندما تنتهي من تعديل هذه القيم.
</p>

<h3>
	إنشاء ملفات متغيرات إضافية لبيئات متعددة
</h3>

<p>
	إذا أعددتَ ملف المخزون مع عقد متعددة، فيمكن أن ترغب في إنشاء ملفات متغيرات إضافية لإعداد كل عقدة وفقًا لذلك، حيث أنشأنا في مثالنا مجموعتين متميزتين للمخزون هما: التطوير <code>dev</code> والإنتاج <code>production</code>، إذ يجب إنشاء ملف متغيرات منفصل للاحتفاظ بقيم الإنتاج لتجنب وجود ثبوتيات قاعدة البيانات والإعدادات الأخرى نفسها في كلتا البيئتين.
</p>

<p>
	يمكن أن ترغب في نسخ ملف المتغيرات الافتراضي واستخدامه بوصفه قاعدةً لقيم الإنتاج الخاصة بك كما يلي:
</p>

<pre class="ipsCode">cp group_vars/all.yml group_vars/production.yml
nano group_vars/production.yml
</pre>

<p>
	يحتوي ملف <code>all.yml</code> على القيم الافتراضية التي يجب أن تكون صالحة لجميع البيئات، لذا يمكنك إزالة جميع المتغيرات التي لن تحتاج إلى تغييرها من ملف <code>production.yml</code> الجديد. المتغيرات التي يجب تحديثها لكل بيئة هي:
</p>

<ul>
	<li>
		<code>prod_user</code>
	</li>
	<li>
		<code>MYSQL_PROD_ROOT_PASSWORD</code>
	</li>
	<li>
		<code>MYSQL_PROD_APP_PASSWORD</code>
	</li>
	<li>
		<code>prod</code>
	</li>
	<li>
		<code>false</code>
	</li>
</ul>

<p>
	وذلك في الشيفرة التالية:
</p>

<pre class="ipsCode" id="ips_uid_5333_11">---
# Initial Server Setup
remote_user: prod_user

# MySQL Setup
mysql_root_password: MYSQL_PROD_ROOT_PASSWORD
mysql_app_pass: MYSQL_PROD_APP_PASSWORD

# Laravel Env Variables
app_env: prod
app_debug: false</pre>

<p>
	لاحظ أننا غيّرنا قيمة <code>app_env</code> إلى <code>prod</code> وضبطنا قيمة <code>app_debug</code> على <code>false</code>، وهذه هي إعدادات لارافيل الموصَى بها لبيئات الإنتاج.
</p>

<p>
	احفظ الملف وأغلقه بعد الانتهاء من تخصيص متغيرات الإنتاج.
</p>

<h3>
	تشفير ملفات المتغيرات باستخدام ميزة Vault الخاصة بأداة Ansible
</h3>

<p>
	إذا أردت مشاركة إعداد أداة Ansible الخاص بك مع مستخدمين آخرين، فيجب الحفاظ على أمان ثبوتيات <a href="https://academy.hsoub.com/devops/servers/databases/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-database/" rel="">قاعدة البيانات</a> والبيانات الحساسة الأخرى في ملفات المتغيرات، ويمكن تحقيق ذلك باستخدام ميزة Vault الخاصة بأداة Ansible، وهي ميزة مُضمَّنة فيها افتراضيًا، إذ تسمح هذه الميزة بتشفير ملفات المتغيرات بحيث يتمكن فقط المستخدمون الذين لديهم إذن الوصول إلى كلمة مرور Vault من عرض هذه الملفات أو تعديلها أو إلغاء تشفيرها. تُعَد كلمة مرور Vault ضرورية لتشغيل دليل التشغيل أو الأمر الذي يستخدم الملفات المُشفَّرة.
</p>

<p>
	شغّل الأمر التالي لتشفير ملف متغيرات الإنتاج:
</p>

<pre class="ipsCode">ansible-vault encrypt group_vars/production.yml
</pre>

<p>
	سيُطلَب منك تقديم كلمة مرور Vault وتأكيدها، ثم سترى أن البيانات مُشفَّرة إذا فحصتَ محتويات هذا الملف. إذا أردتَ عرض ملف المتغيرات دون تغيير محتوياته، فيمكنك استخدام أمر <code>view</code> التالي:
</p>

<pre class="ipsCode">ansible-vault view group_vars/production.yml
</pre>

<p>
	سيُطلَب منك تقديم كلمة المرور نفسها التي حددتها عند تشفير هذا الملف باستخدام <code>ansible-vault</code>، ثم ستظهر محتويات الملف في طرفيتك Terminal بعد تقديم كلمة المرور، ويمكنك الخروج من عرض الملف من خلال الضغط على <code>q</code>.
</p>

<p>
	استخدم الأمر <code>edit</code> التالي لتعديل ملف مُشفَّر مسبقًا باستخدام Ansible Vault:
</p>

<pre class="ipsCode">ansible-vault edit group_vars/production.yml
</pre>

<p>
	سيطلب منك هذا الأمر تقديم كلمة مرور Vault لهذا الملف، ثم سيُستخدَم محرّر طرفيتك الافتراضي لفتح الملف لتعديله. احفظ الملف وأغلقه بعد إجراء التغييرات المطلوبة، وسيُشفَّر تلقائيًا مرة أخرى باستخدام Ansible Vault.
</p>

<p>
	انتهيت الآن من إعداد ملفات المتغيرات، وسنشغّل في الخطوة التالية دليل التشغيل لإعداد Nginx و PHP-FPM و MariaDB (والتي تشكل مع نظام التشغيل المستند إلى لينكس مثل أوبنتو حزمة LEMP) على الخادم أو الخوادم البعيدة.
</p>

<h2>
	الخطوة الرابعة: تنفيذ دليل تشغيل حزمة LEMP
</h2>

<p>
	يجب إعداد بيئة LEMP التي تخدّم التطبيق قبل نشر تطبيق لارافيل التجريبي على الخادم أو الخوادم البعيدة، إذ يتضمن دليل التشغيل <code>server-setup.yml</code> أدوار Ansible الضرورية لإعدادها. يمكنك فحص محتويات دليل التشغيل <code>server-setup.yml</code> من خلال تشغيل الأمر التالي:
</p>

<pre class="ipsCode">cat server-setup.yml
</pre>

<p>
	وسيظهر الخرج التالي:
</p>

<pre class="ipsCode">---
- hosts: all
  become: true
  roles:
    - { role: setup, tags: ['setup'] }

    - { role: mariadb, tags: ['mysql', 'mariadb', 'db', 'lemp'] }

    - { role: php, tags: ['php', 'web', 'php-fpm', 'lemp'] }

    - { role: nginx, tags: ['nginx', 'web', 'http', 'lemp'] }

    - { role: composer, tags: ['composer'] }
</pre>

<p>
	إليك نظرة عامة على جميع الأدوار المضمنة في دليل التشغيل السابق:
</p>

<ul>
	<li>
		<code>setup</code>: يحتوي على المهام اللازمة لإنشاء مستخدم جديد للنظام ومنحه صلاحيات المستخدم الجذر <code>sudo</code> بالإضافة إلى تفعيل جدار الحماية <code>ufw</code>.
	</li>
	<li>
		<code>mariadb</code>: يثبّت خادم قاعدة بيانات MariaDB وينشئ قاعدة بيانات ومستخدم التطبيق.
	</li>
	<li>
		<code>php</code>: يثبّت وحدات <code>php-fpm</code> و <a href="https://academy.hsoub.com/programming/php/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-php-r609/" rel="">PHP</a> الضرورية لتشغيل تطبيق لارافيل.
	</li>
	<li>
		<code>nginx</code>: يثبّت <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-%D8%AE%D8%A7%D8%AF%D9%85-nginx-r401/" rel="">خادم الويب Nginx</a> ويتيح الوصول إلى المنفذ 80.
	</li>
	<li>
		<code>composer</code>: تثبيت مدير الحزم Composer على المستوى العام.
	</li>
</ul>

<p>
	لاحظ أننا ضبطنا بعض الوسوم ضمن كل دور لتسهيل إعادة تشغيل أجزاء فقط من دليل التشغيل إن لزم الأمر. إذا أجريت تغييرات على ملف قالب Nginx مثلًا، فيمكن أن ترغب في تشغيل الدور Nginx فقط.
</p>

<p>
	سينفّذ الأمر التالي دليل التشغيل على جميع الخوادم من ملف مخزونك، حيث يُعَد <code>‎--ask-vault-pass</code> ضروريًا فقط في حالة استخدام <code>ansible-vault</code> لتشفير ملفات المتغيرات في الخطوة السابقة:
</p>

<pre class="ipsCode">ansible-playbook -i hosts server-setup.yml -u root --ask-vault-pass
</pre>

<p>
	وستحصل على خرج يشبه ما يلي:
</p>

<pre class="ipsCode">PLAY [all] **********************************************************************************************

TASK [Gathering Facts] **********************************************************************************
ok: [203.0.113.0.101]
ok: [203.0.113.0.102]

TASK [setup : Install Prerequisites] ********************************************************************
changed: [203.0.113.0.101]
changed: [203.0.113.0.102]

...

RUNNING HANDLER [nginx : Reload Nginx] ******************************************************************
changed: [203.0.113.0.101]
changed: [203.0.113.0.102]

PLAY RECAP **********************************************************************************************
203.0.113.0.101             : ok=31   changed=27   unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   
203.0.113.0.102            : ok=31   changed=27   unreachable=0    failed=0    skipped=0    rescued=0    ignored=1  
</pre>

<p>
	أصبحت عقدتك (أو مجموعة عقدك) جاهزةً الآن لتخديم تطبيقات PHP باستخدام Nginx و PHP-FPM مع خادم قاعدة بيانات MariaDB، وسننشر في الخطوة التالية تطبيق لارافيل التجريبي المُضمَّن باستخدام دليل تشغيل Ansible الذي هو <code>laravel-deploy.yml</code>.
</p>

<h2>
	الخطوة الخامسة: نشر تطبيق لارافيل
</h2>

<p>
	أصبح لديك الآن بيئة LEMP تعمل على الخادم أو الخوادم البعيدة، فيمكنك تنفيذ دليل التشغيل <code>laravel-deploy.yml</code> الذي سينفّذ المهام التالية:
</p>

<ol>
	<li>
		إنشاء المستند الجذر للتطبيق على الخادم البعيد، إن لم يُنشَأ فعليًا.
	</li>
	<li>
		مزامنة مجلد التطبيق المحلي مع الخادم البعيد باستخدام الوحدة <code>sync</code>.
	</li>
	<li>
		استخدام الوحدة <code>acl</code> لضبط أذونات مستخدم www-data في مجلد التخزين.
	</li>
	<li>
		إعداد ملف التطبيق <code>‎.env</code> بناءً على القالب <code>laravel-env.j2</code>.
	</li>
	<li>
		تثبيت اعتماديات التطبيق باستخدام مدير الحزم Composer.
	</li>
	<li>
		توليد مفتاح أمان التطبيق.
	</li>
	<li>
		إعداد رابط عام للمجلد <code>storage</code>.
	</li>
	<li>
		تشغيل <a href="https://academy.hsoub.com/programming/php/laravel/%D8%AA%D8%AC%D8%B1%D9%8A%D8%AF-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%A7%D8%B1%D8%A7%D9%81%D9%8A%D9%84-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%87%D8%AC%D9%8A%D8%B1-migration-%D9%88%D8%A7%D9%84%D8%A8%D8%B0%D8%B1-seeder-r1725/" rel="">عمليات تهجير Migration قاعدة البيانات والبذر Seeder</a>.
	</li>
</ol>

<p>
	يجب أن ينفِّذ مستخدمٌ غير جذر لديه أذونات sudo دليلَ التشغيل، ويجب أن يكون هذا المستخدم مُنشَأً عند تنفيذ دليل التشغيل <code>server-setup.yml</code> في الخطوة السابقة باستخدام الاسم الذي يحدّده المتغير <code>remote_user</code>.
</p>

<p>
	شغّل دليل التشغيل <code>laravel-deploy.yml</code> باستخدام الأمر التالي:
</p>

<pre class="ipsCode">ansible-playbook -i hosts laravel-deploy.yml -u sammy --ask-vault-pass
</pre>

<p>
	يُعَد <code>‎--ask-vault-pass</code> ضروريًا فقط في حالة استخدام <code>ansible-vault</code> لتشفير ملفات المتغيرات في الخطوة السابقة.
</p>

<p>
	وستحصل على خرج يشبه ما يلي:
</p>

<pre class="ipsCode">PLAY [all] **********************************************************************************************

TASK [Gathering Facts] **********************************************************************************
ok: [203.0.113.0.101]
ok: [203.0.113.0.102]

TASK [Make sure the remote app root exists and has the right permissions] *******************************
ok: [203.0.113.0.101]
ok: [203.0.113.0.102]

TASK [Rsync application files to the remote server] *****************************************************
ok: [203.0.113.0.101]
ok: [203.0.113.0.102]

...

TASK [Run Migrations + Seeders] *************************************************************************
ok: [203.0.113.0.101]
ok: [203.0.113.0.102]

PLAY RECAP **********************************************************************************************
203.0.113.0.101             : ok=10   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
203.0.113.0.102             : ok=10   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
</pre>

<p>
	يمكنك عند انتهاء التنفيذ الوصول إلى التطبيق التجريبي من خلال توجيه متصفحك إلى اسم نطاق أو عنوان IP الخاص بعقدتك:
</p>

<pre class="ipsCode">http://node_domain_or_IP
</pre>

<p>
	وسترى صفحة تشبه ما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="120703" href="https://academy.hsoub.com/uploads/monthly_2023_03/01_travellist_version1-0.png.3b7b2ff59e563616cc777e15e08ccc99.png" rel=""><img alt="01_travellist_version1-0.png" class="ipsImage ipsImage_thumbnailed" data-fileid="120703" data-unique="gr5ht263z" src="https://academy.hsoub.com/uploads/monthly_2023_03/01_travellist_version1-0.thumb.png.5b6da53c5d6e65394f97ecc0ea079727.png"> </a>
</p>

<h2>
	الخلاصة
</h2>

<p>
	أوضح هذا المقال كيفية إعداد ملف مخزون الأداة Ansible والاتصال بالعقد البعيدة، وكيفية تشغيل أدلة تشغيل Ansible لإعداد خادم LEMP ونشر تطبيق لارافيل التجريبي عليه. اطّلع على <a href="https://github.com/do-community/ansible-laravel-demo" rel="external nofollow">مستودع جيت هَب</a> التجريبي الذي يحتوي على جميع الملفات الضرورية لمتابعة العمل.
</p>

<p>
	ترجمة -وبتصرُّف- للمقال <a href="https://www.digitalocean.com/community/meetup-kits/automating-server-setup-with-ansible-a-digitalocean-workshop-kit" rel="external nofollow">Automating Server Setup with Ansible: A DigitalOcean Workshop Kit</a> لصاحبته Erika Heidi.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/%D9%85%D8%A7-%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D9%88%D8%A7%D9%84%D8%A3%D8%AA%D9%85%D8%AA%D8%A9%D8%9F-r562/" rel="">ما الفرق بين التنسيق والأتمتة؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/linux/%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D9%84%D9%8A-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-%D8%A8%D8%A5%D8%B5%D8%AF%D8%A7%D8%B1-1804-r443/" rel="">أتمتة إعداد خادم أولي أوبونتو</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-ansible-%D9%84%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-%D9%88%D9%86%D8%B4%D8%B1-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-ubuntu-r158/" rel="">كيفية تثبيت وإعداد Ansible لأتمتة إدارة الإعدادات ونشر التطبيقات على خادوم Ubuntu</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">688</guid><pubDate>Tue, 14 Mar 2023 13:07:02 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x648;&#x62D;&#x62F;&#x627;&#x62A; Ansible</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-ansible-r637/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_07/62dfb9e975649_----Ansible.png.421da5af2c9766214b17a64f3fe3a0eb.png" /></p>

<p>
	يعد <a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-ansible-%D9%84%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-%D9%88%D9%86%D8%B4%D8%B1-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-ubuntu-r158/" rel="">Ansible</a> أداة لأتمتة المهام التقنية البسيطة ويتميز ببنية دفع push على عكس الأدوات المشابهة له والتي تعتمد على نموذج السحب pull الشائع.
</p>

<p>
	يتكون Ansible من أدلة التشغيل playbooks والوحدات modules، يحتوي دليل التشغيل على تسلسل من الوحدات لتنفيذها، أما الوحدات فهي من يقوم بالعمل المطلوب.
</p>

<h2>
	الوحدات modules
</h2>

<p>
	هي عبارة عن برامج صغيرة تُرسل إلى العقد بعد الاتصال بها ليتم تنفيذها عن بُعد وعند انتهاء مهمتها يتم إزالتها، تحتوي هذه البرامج على إعدادات الضبط ويتم دفعها إلى خوادم بلا وكلاء. تتخصص كل وحدة بتنفيذ مهمة معينة، فمثلًا تقوم وحدة بإنشاء ملف جديد وتقوم أخرى بتثبيت برمجية ما كما تقوم أخرى بتشغيل برنامج ما وهكذا لذا يوجد عدد كبير من الوحدات والتي تُضمَّن بواسطة نموذج وحدات Ansible الشامل.
</p>

<p>
	تمكننا الوحدات من إدارة كل ما يمتلك واجهة برمجة تطبيقات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> أو واجهة سطر الأوامر CLI أو ملف ضبط إعدادات قابل للتعديل يمكن التفاعل معه، ويشمل ذلك أجهزة الشبكة مثل موازِن الحمل والمبدل وجدار الحماية و<a href="https://academy.hsoub.com/devops/deployment/%D9%85%D8%A7-%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%AA%D9%86%D8%B3%D9%8A%D9%82-%D9%88%D8%A7%D9%84%D8%A3%D8%AA%D9%85%D8%AA%D8%A9%D8%9F-r562/" rel="">منسق الحاويات</a> والحاوية نفسها وحتى نُسَخ الآلات الوهمية في مراقب Hypervisor أو في سحابة عامة cloud مثل AWS و GCE و Azure أو السحابة الخاصة مثل <a href="https://academy.hsoub.com/devops/cloud-computing/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86-%D8%B3%D8%AA%D8%A7%D9%83-openstack-r601/" rel="">OpenStack</a> و CloudStack، بالإضافة إلى أجهزة التخزين والأمان وضبط النظام.
</p>

<h2>
	طريقة بناء الوحدات
</h2>

<p>
	تُكتب إعدادات الضبط بشكل سكربتات صغيرة في ملفات YAML وتُرسل عبر الشبكة بواسطة <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> / WinRM أو أي ملحق اتصال آخر إلى الخوادم التي يُراد تنفيذها عليها، ويمكن الكتابة باستخدام أي لغة قادرة على إرجاع <a href="https://academy.hsoub.com/programming/javascript/%D8%B5%D9%8A%D8%BA%D8%A9-json-%D9%88%D8%AA%D9%88%D8%A7%D8%A8%D8%B9%D9%87%D8%A7-r826/" rel="">صيغة JSON</a> على الرغم من أن معظم وحدات Ansible (باستثناء Windows PowerShell) مكتوبة بلغة بايثون Python باستخدام واجهة برمجة تطبيقات Ansible وهذا ما يسهل تطوير وحدات جديدة.
</p>

<h2>
	الملحقات
</h2>

<p>
	تعد الملحقات إحدى طرق توسيع قدرات Ansible ويمكن للبدائل الأخرى مثل الملحقات والقوائم الديناميكية أن تزيد أيضًا من قوة وفعالية Ansible وتنقسم الملحقات إلى عدة فئات ذات أهداف مختلفة لكل فئة ومن الملحقات الأكثر شيوعًا:
</p>

<ul>
<li>
		ملحقات الاتصال Connection: تنفذ هذه الملحقات طريقة للتواصل مع الخوادم الموجودة في قائمة الخوادم، أي كيفية نقل شيفرة التشغيل الآلي عبر الشبكة ليتم تنفيذها مثل: <a href="https://academy.hsoub.com/devops/security/ssh/%D8%AF%D9%84%D9%8A%D9%84-%D8%A8%D8%B5%D8%B1%D9%8A-%D9%84%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D9%86%D9%81%D8%A7%D9%82-ssh-r508/" rel=""><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></a> و WinRM و Telnet.
	</li>
	<li>
		ملحقات المرشحات Filters: تسمح للمستخدم بمعالجة البيانات داخل دليل التشغيل الخاص به، وهذه ميزة Jinja2 وتستخدم لحل مشاكل عملية IaC وهي اختصار infrastructure-as-code أي بنية تحتية كشيفرة والتي يتم فيها إدارة وتوفير البنية التحتية من خلال الشيفرة البرمجية بدلًا من العمليات اليدوية.
	</li>
	<li>
		ملحقات البحث Lookup: تجلب البيانات من مصدر خارجي مثل ملف أو قاعدة بيانات أو ملفات بيئة env، أو نظام البحث هيرا Hiera أو أداة تخزين واسترجاع البيانات السرية فاولت Vault من شركة HashiCorp أو غيرها.
	</li>
</ul>
<p>
	يوجد أمثلة أخرى للملحقات وهي Action و Cache و Callback و Vars، ويمكن الاستعانة بتوثيق Ansible الرسمي <a href="https://docs.ansible.com/ansible/latest/dev_guide/developing_plugins.html#developing-plugins" rel="external nofollow">لتطوير الملحقات</a>.
</p>

<h2>
	تطوير الوحدات
</h2>

<p>
	على الرغم من امتلاك Ansible لمئات الوحدات إلا أنه قد يوجد مشكلة ما لم تتم تغطيتها بعد أو أنها شيء محدد للغاية كحل محلي في مؤسسة معينة، عندها يمكن تطوير وحدة جديدة تناسب الاحتياجات ولكن يجب التحقق بدايةً من وجود هذه الوحدة مسبقًا أو أنها قد التطوير حاليًا، وذلك من خلال التواصل مع المطورين في قناة (IRC/Freenode) في ansible-devel# أو البحث في <a href="https://groups.google.com/forum/#!forum/ansible-devel" rel="external nofollow">قائمة التطوير</a> أو <a href="https://github.com/ansible/community/" rel="external nofollow">مجموعات العمل</a> الحالية.
</p>

<p>
	قد تتساءل متى يجب تطوير وحدة جديدة؟ الحالات التالية تدل على أنك بحاجة إلى تطوير وحدة جديدة بدلًا من الاعتماد على وحدة حالية موجودة بالفعل:
</p>

<ul>
<li>
		طرق إدارة الضبط التقليدية لا تحل مشكلة ما بشكل صحيح مثل القوالب والملف وتعديل سطر محدد في ملف الحصول على محدِّد الموارد المُوحَّد get_url
	</li>
	<li>
		لتحقيق الهدف المطلوب يلزم استخدام مجموعة معقدة من الأوامر وبيئات سطر الأوامر والمرشحات ومعالجة النصوص باستخدام magic regexes واستدعاءات واجهة برمجة التطبيقات <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> باستخدام curl.
	</li>
	<li>
		أدلة التشغيل الخاصة بالمستخدم ضرورية ولكنها معقدة وغير مستقرة وتعطي نتائج مختلفة مع كل تنفيذ.
	</li>
</ul>
<p>
	تحتوي الأداة أو الخدمة في الحالة المثالية على واجهة برمجة تطبيقات أو واجهة سطر الأوامر CLI للإدارة وتقوم بإرجاع نوع من البيانات المُهيكلة مثل JSON أو XML أو YAML.
</p>

<h2>
	التأكد من فعالية دليل التشغيل
</h2>

<p>
	تعد أدلة التشغيل مهمة بنفس أهمية الوحدات حيث يؤثر دليل التشغيل السيء سلبًا على عملية الأتمتة فبدلًا من من تسخير أدوات إدارة الضبط لزيادة السرعة، تجعلنا نواجه نفس المشكلات مثل نهج التشغيل الآلي الأساسي القائم على السكربتات وتنفيذ الأوامر، ويصبح الأمر عبارة عن استخدام Ansible كوسيلة لتسليم السكربتات القديمة ونسخ ما هو موجود مسبقًا إلى ملفات YAML، وفيما يلي مثال على دليل تشغيل سيء:
</p>

<pre class="ipsCode">
- name: Read a remote resource
   command: "curl -v http://xpto/resource/abc"
 register: resource
 changed_when: False

 - name: Create a resource in case it does not exist
   command: "curl -X POST http://xpto/resource/abc -d '{ config:{ client: xyz, url: http://beta, pattern: *.* } }'"
   when: "resource.stdout | 404"
 # Leave it here in case I need to remove it hehehe
 #- name: Remove resource
 #  command: "curl -X DELETE http://xpto/resource/abc"
 #  when: resource.stdout == 1
</pre>

<p>
	يعد هذا الدليل سيء لأنه ضعيف ويتطلب شيفرة إضافية ليكون مستقرًا ولا يستطيع تحديث المورد عندما تتغير حالته.
</p>

<p>
	لا تحقق أدلة التشغيل المكتوبة بهذه الطريقة العديد من معايير نهج IaC حيث يصعب على المطور قراءتها وإعادة استخدامها وتحديد متغيراتها ولا تلتزم بالنموذج التصريحي المُتبع من قبل معظم أدوات إدارة الضبط، كما تعد غير مستقرة ولا تتقارب مع الحالة المعلنة.
</p>

<p>
	أما كتابة دليل التشغيل وفق معايير نهج IaC تجعله يتصف بما يلي:
</p>

<ul>
<li>
		يسهل على المطور قراءته
	</li>
	<li>
		يسهل تحديد المتغيرات أو إعادة استخدامه
	</li>
	<li>
		تصريحي يتم تمثيل الموارد بشكل صحيح في YAML
	</li>
	<li>
		مستقر
	</li>
	<li>
		يتقارب من الحالة المعلنة إلى الحالة الحالية
	</li>
</ul>
<p>
	لذا سنعيد كتابة المثال السابق لاتباع معايير نهج IaC كما يلي:
</p>

<pre class="ipsCode">
- name: XPTO
  xpto:
    name: abc
    state: present
    config:
      client: xyz
      url: http://beta
      pattern: "*.*"
</pre>

<h2>
	تنفيذ وحدة مخصصة
</h2>

<p>
	سنستخدم <a href="https://www.wildfly.org/" rel="external nofollow">WildFly</a> وهو خادم تطبيق جافا مفتوح المصدر كمثال لتقديم وحدة مخصصة لدليل التشغيل غير الجيد:
</p>

<pre class="ipsCode">
- name: Read datasource
   command: "jboss-cli.sh -c '/subsystem=datasources/data-source=DemoDS:read-resource()' "
   register: datasource

 - name: Create datasource
   command: "jboss-cli.sh -c '/subsystem=datasources/data-source=DemoDS:add(driver-name=h2, user-name=sa, password=sa, min-pool-size=20, max-pool-size=40, connection-url=.jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE..)' "
   when: 'datasource.stdout | outcome =&gt; failed'
</pre>

<p>
	المشكلات:
</p>

<ul>
<li>
		غير تصريحي
	</li>
	<li>
		يقوم JBoss-CLI بإظهار نص عادي كخرج بصيغة مشابهة لصيغة JSON وهو ما يضعف هذا النهج لأننا بحاجة إلى محلل لغوي لهذه الصياغة، حتى المحلل اللغوي الذي يبدو بسيطًا يمكن أن يكون معقدًا للغاية لمعالجة العديد من <a href="https://datatracker.ietf.org/doc/html/rfc7159" rel="external nofollow">الاستثناءات</a>.
	</li>
	<li>
		يعتبر JBoss-CLI واجهة فقط لإرسال الطلبات إلى واجهة برمجة تطبيقات الإدارة عبر المنفذ 9990.
	</li>
	<li>
		يعد إرسال طلب HTTP أكثر فاعلية من فتح جلسة JBoss-CLI جديدة والاتصال وإرسال أمر
	</li>
	<li>
		لا تتقارب مع الحالة المرغوبة بل يقوم فقط بإنشاء المورد عندما لا يكون موجودًا
	</li>
</ul>
<p>
	لجعل الدليل تصريحيًا ومستقرًا وسهل القراءة ويتقارب مع الحالة المرغوبة بغض النظر عن الحالة الحالية، قد تبدو الوحدة المخصصة لذلك كما يلي:
</p>

<pre class="ipsCode">
- name: Configure datasource
      jboss_resource:
        name: "/subsystem=datasources/data-source=DemoDS"
        state: present
        attributes:
          driver-name: h2
          connection-url: "jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
          jndi-name: "java:jboss/datasources/DemoDS"
          user-name: sa
          password: sa
          min-pool-size: 20
          max-pool-size: 40
</pre>

<h2>
	أهمية تعلم بناء وحدات مخصصة
</h2>

<p>
	يوجد العديد من الأهداف التي يستلزم تحقيقها إنشاء وحدات مخصصة وهي:
</p>

<ul>
<li>
		تحسين الوحدات الموجودة
	</li>
	<li>
		تحسين أدلة التشغيل السيئة
	</li>
	<li>
		تجنب وجود أدلة تشغيل سيئة
	</li>
	<li>
		زيادة الإنتاجية بسبب تحسين قدرة المستخدم على تصحيح المشكلات في أدلة التشغيل
	</li>
</ul>
<h2>
	وحدات Ansible المخصصة
</h2>

<p>
	تتصف بما يلي:
</p>

<ul>
<li>
		يمكن كتابتها بأي لغة لكن عادةً ما تكون <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">لغة بايثون Python</a> هي الخيار الأفضل أو ثاني أفضل خيار
	</li>
	<li>
		معظم الوحدات التي يتم تسليمها باستخدام Ansible ‏(lib/ansible/modules) مكتوبة بلغة بايثون Python ويجب أن تدعم الإصدارات المتوافقة
	</li>
	<li>
		يكون الخرج المعيار بصيغة JSON
	</li>
</ul>
<h3>
	طريقة Ansible
</h3>

<p>
	يجب كتابة الأمر التالي:
</p>

<pre class="ipsCode">
git clone https://github.com/ansible/ansible.git
</pre>

<p>
	ثم اتباع المسار ‎/lib/ansible/modules ثم قراءة شيفرة الوحدة الحالية.
</p>

<p>
	تكون الأدوات المتاحة هي: Git و Python و virtualenv و pdb وهو مصحح الأخطاء في بايثون، ويمكن الحصول على تعليمات شاملة من خلال الاستعانة <a href="https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html#developing-modules-general" rel="external nofollow">بالتوثيق الرسمي</a>.
</p>

<p>
	يوجد بديل وهو وضع الوحدة في مجلد library، ويمكن استخدام تصميم المجلد هذا لتعديل أو تصحيح الوحدات الموجودة وهو مناسب للوحدات التي ستُستخدم داخليًا وأسهل في البداية ولا يتطلب أي شيء سوى Ansible وبيئة التطوير المتكاملة IDE ومحرر نصوص، وذلك بالشكل التالي:
</p>

<pre class="ipsCode">
library/                  # تُوضع الوحدات المخصصة هنا في حال وجودها (الأمر اختياري)
module_utils/             # تُوضع الأدوات المُساعدة للوحدات المخصصة في حال وجودها هنا
filter_plugins/           # تُوضع ملحقات المرشحات المخصصة في حال وجودها هنا، الأمر اختياري

site.yml                  # دليل التشغيل الرئيسي
webservers.yml            # دليل التشغيل الخاص بطبقة خادم الويب
dbservers.yml             # دليل التشغيل الخاص بطبقة خادم قاعدة البيانات

roles/
    common/               # تمثل هذه الهرمية دورًا
        library/          # يمكن أن تتضمن الأدوار أيضًا وحدات مخصصة
        module_utils/     # يمكن أن تتضمن الأدوار أيضًا أدوات وحدات مخصصة
        lookup_plugins/   # أو تتضمن أنواع أخرى من الملحقات، مثل ملحقات البحث في هذا المثال
</pre>

<h3>
	الحل البديل لطريقة Ansible
</h3>

<p>
	يمكن القيام بذلك بأي أسلوب وحتى باستخدام لغة أخرى، أو يمكن استخدام الصنف AnsibleModule لأنه من الأسهل تمرير صيغة JSON إلى الخرج المعياري (()exit_json(), fail_json) بالطريقة التي يتوقعها Ansible وهي (msg, meta, has_changed, result)، ومن الأسهل أيضًا معالجة المدخلات ([]params) وتسجيل تنفيذها (()log(), debug).
</p>

<pre class="ipsCode">
def main():

  arguments = dict(name=dict(required=True, type='str'),
                  state=dict(choices=['present', 'absent'], default='present'),
                  config=dict(required=False, type='dict'))

  module = AnsibleModule(argument_spec=arguments, supports_check_mode=True)
  try:
      if module.check_mode:
          # لا ينفذ أي شيء، بل يتحقق فقط من الحالة الحالية ويبلغ عنها
          module.exit_json(changed=has_changed, meta=result, msg='Fez alguma coisa ou não...')

      if module.params['state'] == 'present':
          # يتحقق من وجود مورد
          # ‫يتحقق من مطابقة الحالة المطلوبة module.params['param_name']‎ مع الحالة الحالية
          module.exit_json(changed=has_changed, meta=result)

      if module.params['state'] == 'absent':
          # يزيل المصدر في حال وجوده
          module.exit_json(changed=has_changed, meta=result)

  except Error as err:
      module.fail_json(msg=str(err))
</pre>

<p>
	يسمح وضع التحقق "dry run" بتنفيذ دليل التشغيل أو التحقق فقط مما إذا كانت التغييرات مطلوبة ولا يتم تنفيذها، ويمكن استخدام مجلد module_utils للشيفرة البرمجية المشتركة بين الوحدات المختلفة.
</p>

<p>
	للحصول على مثال Wildfly الكامل، يمكن الاطلاع على <a href="https://github.com/ansible/ansible/pull/43682/files" rel="external nofollow">طلب السحب هذا</a>.
</p>

<h2>
	إجراء الاختبارات
</h2>

<p>
	هنالك طريقتان لإجراء الاختبارات، الأولى وفق طريقة Ansible والثانية طريقة بديلة.
</p>

<p>
	في طريقة Ansible، يتم اختبار شيفرة Ansible الأساسية بصعوبة حيث تؤدي كل عملية تنفيذ إلى إنشاء بناء في خادم التكامل المستمر CI، و <a href="https://app.shippable.com/github/ansible/ansible/dashboard" rel="external nofollow">Shippable</a> والذي يتضمن الفحص واختبارات الوحدة واختبارات التكامل، أما بالنسبة لاختبارات التكامل فإنه يستخدم الحاويات و Ansible نفسه لأداء مرحلة الإعداد والتحقق.
</p>

<p>
	فيما يلي حالة اختبار مكتوبة في Ansible لنموذج شيفرة الوحدة المخصصة لدينا:
</p>

<pre class="ipsCode">
- name: Configure datasource
 jboss_resource:
   name: "/subsystem=datasources/data-source=DemoDS"
   state: present
   attributes:
     connection-url: "jdbc:h2:mem:demo;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
     ...
 register: result

- name: assert output message that datasource was created
 assert:
   that:
      - "result.changed == true"
      - "'Added /subsystem=datasources/data-source=DemoDS' in result.msg"
</pre>

<p>
	يوجد بديل وهي الطريقة الثانية وذلك عبر تجميع وحدة اعتمادًا على صلاحيات ودور المستخدم، وتوفر قدرًا أكبر من المرونة لاختيار ما يلي:
</p>

<ul>
<li>
		إعداد مبسط
	</li>
	<li>
		كيفية تطوير البنية التحتية الخاصة بالمستخدم: Vagrant و Docker و OpenStack و EC2
	</li>
	<li>
		كيفية التحقق من اختبارات البنية التحتية: Testinfra و Goss
	</li>
</ul>
<p>
	ولكن تتطلب هذه الطريقة كتابة الاختبارات باستخدام إطار العمل pytest بواسطة Testinfra أو Goss بدلًا من Ansible العادي، وفيما يلي <a href="https://github.com/jairojunior/ansible-role-jboss/tree/with_modules" rel="external nofollow">مثال كامل</a> داخل دور بسيط: <a href="https://molecule.readthedocs.io/en/latest/" rel="external nofollow">Molecule</a> + <a href="https://www.vagrantup.com/" rel="external nofollow">Vagrant</a> + <a href="https://docs.pytest.org/en/7.1.x/" rel="external nofollow">pytest</a>: <code>molecule init</code> (داخل roles/).
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		"الأفكار المجردة توفر علينا وقت العمل لكنها لا توفر علينا وقت التعلم" —جويل سبولسكي Joel Spolsky، <a href="https://en.wikipedia.org/wiki/Leaky_abstraction#The_Law_of_Leaky_Abstractions" rel="external nofollow">قانون التجريد المتناقص</a>
	</p>
</blockquote>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://opensource.com/article/19/3/developing-ansible-modules" rel="external nofollow">What you need to know about Ansible modules</a> لصاحبه Jairo da Silva Junior.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/devops/linux/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%A7%D8%B9%D8%AF-ansible-%D8%B9%D9%84%D9%89-%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D9%85%D9%87%D8%A7%D9%85-%D8%A8%D8%B3%D9%8A%D8%B7%D8%A9-%D9%84%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%AD%D9%88%D8%A7%D8%B3%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D9%86%D8%B2%D9%84-r635/" rel="">كيف تساعد Ansible على أتمتة مهام بسيطة لإدارة حواسيب المنزل</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81-%D8%AA%D8%A4%D8%AA%D9%85%D8%AA-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r275/" rel="">كيف تؤتمت تثبيت ووردبريس على أوبنتو باستخدام Ansible</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-ansible-%D9%84%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-%D9%88%D9%86%D8%B4%D8%B1-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-ubuntu-r158/" rel="">كيفية تثبيت وإعداد Ansible لأتمتة إدارة الإعدادات ونشر التطبيقات على خادوم Ubuntu</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">637</guid><pubDate>Tue, 26 Jul 2022 10:00:35 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x651;&#x629; &#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x648;&#x636;&#x628;&#x637; Ansible &#x639;&#x644;&#x649; Ubuntu 18.04</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-ansible-%D8%B9%D9%84%D9%89-ubuntu-1804-r394/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_01/ansible.png.e851dd040a22ebe040e86cc90a3cb2b8.png" /></p>

<h2>
	مقدمة
</h2>

<p>
	صُممت أنظمة إدارة الضبط لتجعل من التحكم في عددٍ كبيرٍ من الخوادم أمرًا سهلًا للمدراء وفِرق العمليات. فهي تسمح بالتحكم في العديد من الأنظمة المختلفة بطريقةٍ آلية ومن موقع مركزي واحد.
</p>

<p>
	وعلى الرغم من وجود العديد من أنظمة إدارة الضبط الشائعة المتوفرة لأنظمة Linux، مثل Chef وPuppet، إلاّ أنّ هذه الأنظمة غالباً ما تكون أكثر تعقيدًا مما يريده أو يحتاجه الكثير من الأشخاص. يُعدّ Ansible بديلاً هامًا لهذه الخيارات نظرًا لأنّه يتطلب عبئا أقل بكثير للبدء.
</p>

<p>
	سنناقش في هذا الدليل كيفيّة تثبيت Ansible على خادم Ubuntu 18.04 وسنتحدّث عن بعض الأساسيّات حول كيفيّة استخدام البرنامج.
</p>

<h2>
	كيف يعمل Ansible؟
</h2>

<p>
	يعمل Ansible عن طريق ضبط أجهزة العميل  من خلال حاسب يحوي مكوّنات Ansible مُثبّتة ومُهيأة.
</p>

<p>
	يتصل عبر قنوات <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> الاعتيادية لاسترداد المعلومات من الأجهزة البعيدة، وإصدار الأوامر، ونسخ الملفات. ولذلك لا يتطلب نظام Ansible تثبيت أيّة برمجيّات إضافيّة على أجهزة حواسب العملاء.
</p>

<p>
	هذه هي إحدى الطرق التي يّبسط فيها Ansible إدارة الخوادم. يمكن ضم أي خادم لديه منفذ <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> مكشوف تحت مظلة ضبط Ansible بغض النظر عن الطور الذي يتواجد فيه ضمن دورة حياته. وهذا يعني أن أي حاسب يمكنك إدارته من خلال <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>، يمكنك إدارته أيضًا من خلال Ansible.
</p>

<p>
	يتخذ Ansible نهجًا معياريًا، جاعلًا من السهل التوسع لاستخدام وظائف النظام الرئيسي للتعامل مع سيناريوهات محدّدة. يمكن كتابة الوحدات باستخدام أيّة لغة وتتواصل في JSON القياسيّة.
</p>

<p>
	إن ملفات الضبط مكتوبة بشكل أساسي بصيغة تسلسل بيانات YAML بسبب طبيعتها الدلاليّة وتشابهها مع لغات الترميز الشائعة. ويمكن أن يتفاعل Ansible مع المضيفات hosts إما عبر أدوات سطر الأوامر أو من خلال سكربتات الضبط ، والتي تُعرف باسم Playbooks.
</p>

<h2>
	المتطلبات المسبقة
</h2>

<p>
	ستحتاج لمتابعة هذه الدورة التعليميّة إلى:
</p>

<ul>
<li>
		اثنين أو أكثر من خوادم Ubuntu 18.04. سيُستخدم واحد منها كخادم Ansible الخاص بك، بينما سيُستخدم الباقي كمضيفين Ansible الخاصين بك. يجب أن يكون لكل منهم مستخدم غير جذري non-root بامتيازات sudo وجدار ناري firewall أساسي مُهيئ. يمكنك إعداد ذلك باتباع دليل إعداد الخادم المبدئي لـ Ubuntu 18.04. ويرجى ملاحظة أنّ الأمثلة في هذا الدليل تحدّد ثلاثة مضيفين Ansible، ولكن يمكن ضبط الأوامر لأيّ عدد تريده من العملاء.
	</li>
	<li>
		أُنشئت مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> للمستخدم الغير جذري non-root user على خادم Ansible الخاص بك. وللقيام بذلك، تابع الخطوة 1 من دليلنا حول كيفية إعداد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> على Ubuntu 18.04. يمكنك من أجل هذه الدورة التعليميّة حفظ زوج المفاتيح إلى الموقع الافتراضي (<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/id_rsa./~) ولا تحتاج إلى حماية بكلمة المرور.
	</li>
</ul>
<h2>
	الخطوة 1 - تثبيت Ansible
</h2>

<p>
	يجب تثبيت برنامج Ansible على جهاز واحد على الأقل لبدء استخدامه كوسيلة لإدارة الخوادم المختلفة.
</p>

<p>
	يمكنك إضافة أرشيف الحزمة الشخصيّة للمشروع (PPA (personal package archive إلى النظام الخاص بك للحصول على أحدث إصدار من Ansible على نظام Ubuntu. عليك قبل القيام بذلك أولاً تحديث فهرس الحزمة وتثبيت حزمة software-properties-common. حيث تسهّل هذه البرمجية إدارة هذا المستودع ومستودعات البرمجيات المستقلة الأخرى:
</p>

<pre class="ipsCode">
$ sudo apt update
$ sudo apt install software-properties-common
</pre>

<p>
	ثم أضف PPA Ansible عن طريق كتابة الأمر التالي:
</p>

<pre class="ipsCode">
$ sudo apt-add-repository ppa: ansible / ansible
</pre>

<p>
	اضغط ENTER لقبول إضافة PPA.
</p>

<p>
	بعدها، حدّث فهرس حزمة النظام مرّةً أخرى حتى يصبح على معرفةٍ بالحزم المتاحة في PPA:
</p>

<pre class="ipsCode">
$ sudo apt update
</pre>

<p>
	يمكنك تثبيت برمجيّة Ansible بعد هذا التحديث:
</p>

<pre class="ipsCode">
$ sudo apt install ansible
</pre>

<p>
	يحتوي الآن خادم Ansible على جميع البرمجيّات المطلوبة لإدارة المضيفات hosts.
</p>

<h2>
	الخطوة 2 - تهيئة الـ <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> للوصول إلى مضيفات Ansible
</h2>

<p>
	يتصل Ansible كما ذُكر سابقًا بشكل أساسي مع أجهزة الحواسب العميلة من خلال <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>. وعلى الرغم من أن لديها بالتأكيد القدرة على التعامل مع استيثاق <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> المعتمد على كلمة المرور، إلاّ أن استخدام مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> يمكن أن يساعد في إبقاء الأمور بسيطة.
</p>

<p>
	استخدم أمر cat على خادم Ansible خاصتك لطباعة محتويات ملف مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> العام للمستخدم الغير جذري non-root الخاص بك إلى خرْج الطرفيّة terminal:
</p>

<pre class="ipsCode">
$ cat ~ / .<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> / id_rsa.pub
</pre>

<p>
	انسخ الخرج الناتج إلى حافظتك، ثم افتح طرفيّة جديدة terminal واتصل بأحد مضيفي Ansible مُستخدمًا <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>:
</p>

<pre class="ipsCode">
$ <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> sammy @ ansible_host_ip
</pre>

<p>
	بدّل إلى المستخدم الجذري root لجهاز العميل:
</p>

<pre class="ipsCode">
$ su –
</pre>

<p>
	افتح الدليل authorized_keys ضمن المسار ~/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> كمستخدم جذر root :
</p>

<pre class="ipsCode">
# nano ~/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/authorized_keys
</pre>

<p>
	الصق مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> لمستخدم Ansible server في الملف، ثم احفظ الملف وأغلق المحرر (, اضغط CTRL + X, Y، ثم ENTER). ثم شغِّل الأمر exit للرجوع إلى المستخدم العادي للمضيف:
</p>

<pre class="ipsCode">
# exit
</pre>

<p>
	أخيرًا، ونظرًا لأن Ansible يستخدم مُفسّر بايثون python interpreter الموجود في المسار / usr / bin / python لتشغيل وحداته، فستحتاج إلى تثبيت Python 2 على المضيف حتى يتمكن Ansible من الاتصال به. شغّل الأوامر التالية لتحديث فهرس حزمة المضيف وتثبيت حزمة python:
</p>

<pre class="ipsCode">
$ sudo apt update
$sudo apt install python
</pre>

<p>
	يمكنك بعد ذلك تشغيل أمر exit مرّةً أخرى لإغلاق الاتصال بالعميل:
</p>

<pre class="ipsCode">
$ exit
</pre>

<p>
	كرّر هذه العملية من أجل كل خادم تنوي التحكم فيه باستخدام خادم Ansible الخاص بك. بعد ذلك، سنُهيئ خادم Ansible للاتصال بالمضيفات باستخدام ملف (hosts)الخاص بـ Ansible.
</p>

<h2>
	الخطوة 3 - إعداد مضيفات Ansible
</h2>

<p>
	يتتبع Ansible كافة الخوادم الذي يتعرف عليها من خلال ملف المضيفات hosts. نحتاج أولًا إلى إعداد هذا الملف قبل أن نتمكن من بدء الاتصال بحواسبنا الأخرى:
</p>

<pre class="ipsCode">
$ sudo nano /etc/ansible/hosts
</pre>

<p>
	سترى ملفًا يحوي عددًا من أمثلة "نماذج" الضبط المُعقّب عليها (بإشارة # تسبق كل سطر). لن تعمل هذه الأمثلة فعليًا في حالتنا نظرًا لأن المضيفات المُدرجات في كل منها وهميّة. بكافة الأحوال سنحتفظ بهذه الأمثلة في الملف لمساعدتنا في الضبط في حال أردنا تنفيذ حالات أكثر تعقيدًا في المستقبل. إن ملف hosts مرن إلى حدّ ما ويمكن ضبطته بعدّة بطرق مختلفة. وبناءً عليه، ستبدو الصياغة التي سنستخدمها كما يلي:
</p>

<pre class="ipsCode">
[group_name]
alias ansible_ssh_host=your_server_ip
</pre>

<p>
	في هذا المثال، إن group_name وسم تنظيمي يتيح لك الإشارة إلى أي خادم مدرج تحته بكلمة واحدة، بينما alias هو مجرد اسم للإشارة إلى خادم معيّن. نعتبر في حالتنا أن لدينا ثلاثة خوادم سنتحكم بهم باستخدام Ansible. يمكن عند هذه النقطة الوصول إلى هذه الخوادم من خادم Ansible بكتابة:
</p>

<pre class="ipsCode">
$ <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> root@ansible_host_ip
</pre>

<p>
	إذا أعددت هذا بشكل صحيح فلا يجب أن تُطالب بكلمة مرور. سنفترض هنا لأغراض العرض التوضيحي أن عناوين IP لمضيفاتنا هي 203.0.113.1 و 203.0.113.2 و 203.0.113.3. وسنضبط ذلك بحيث يمكننا الإشارة إليها بشكل فردي كـ host1، و host2، و host3، أو كمجموعة باسم servers. و لإتمام ذلك يتوجب إضافة هذه الكتلة إلى ملف hosts الخاص بنا:
</p>

<pre class="ipsCode">
[servers]
host1 ansible_ssh_host=203.0.113.1
host2 ansible_ssh_host=203.0.113.2
host3 ansible_ssh_host=203.0.113.3
</pre>

<p>
	يمكن أن تكون المضيفات في مجموعاتٍ متعددة، ويمكن للمجموعات ضبط المعاملات parameters من أجل جميع أعضائها. فلنجرّب هذا الآن.
</p>

<p>
	إن حاولنا باستخدام إعداداتنا الحاليّة الاتصال بأي من هذه الأجهزة المضيفة hosts من خلال Ansible، فسيفشل الأمر (على افتراض أنك لا تعمل كمستخدم جذر root). يحدث هذا لأنّه تم تضمين مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من أجل المستخدم الجذر على الأنظمة البعيدة وسيحاول Ansible الاتصال بشكل افتراضي بواسطة المستخدم الحالي، ستعطينا محاولة الاتصال هذا الخطأ:
</p>

<pre class="ipsCode">
[servers]
Output
host1 | UNREACHABLE! =&gt; {
	"changed": false,
	"msg": "Failed to connect to the host via <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>.",
	"unreachable": true
}
</pre>

<p>
	نستخدم على خادم Ansible مستخدمًا اسمه sammy. سيحاول Ansible الاتصال بكل مضيف باستخدام <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> sammy @ server. ولن يعمل هذا إذا لم يكن المستخدم sammy موجودًا على النظام البعيد أيضًا.
</p>

<p>
	يمكننا إنشاء ملف يخبر جميع الخوادم في مجموعة "servers " للاتصال كمستخدم جذر root.
</p>

<p>
	سننشئ لعمل ذلك دليلًا في بنية ضبط Ansible يدعى group_vars. ويمكننا ضمن هذا المجلد إنشاء ملفات بتنسيق YAML لكل مجموعة نريد ضبطها:
</p>

<pre class="ipsCode" id="ips_uid_1205_10">
$ sudo mkdir /etc/ansible/group_vars
$sudo nano /etc/ansible/group_vars/servers
</pre>

<p>
	يمكننا وضع ضبطنا هنا. تبدأ ملفات YAML بـ "---"، لذا تأكد من عدم نسيان هذا الجزء.
</p>

<p>
	/etc/ansible/group_vars/servers
</p>

<pre class="ipsCode" id="ips_uid_1205_14">
---
ansible_ssh_user: root
</pre>

<p>
	احفظ وأغلق هذا الملف عند الانتهاء.
</p>

<p>
	إذا كنت تريد تحديد تفاصيل الضبط لكل خادم، بغض النظر عن المجموعة المرتبط بها، فيمكنك وضع هذه التفاصيل في ملف في المسار etc/ansible/group_vars/all/. يمكن ضبط المضيفات بشكل فردي عن طريق إنشاء ملفات مُسماة بالاسم البديل alias تحت الدليل في /etc/ansible/host_vars.
</p>

<h2>
	الخطوة 4 - استخدام أوامر Ansible بسيطة
</h2>

<p>
	يمكننا الآن -وبعد أن أعددنا مضيفاتنا و ضبطنا تفاصيل تهيئة كافية للسماح لنا بالاتصال بنجاح مع مضيفاتنا- تجربة الأمر الأول.
</p>

<p>
	عمل اختبار ping لجميع خوادمنا المُهيئة وذلك بكتابة:
</p>

<pre class="ipsCode" id="ips_uid_8957_6">
$ anmible -m ping all
</pre>

<p>
	ستكون المخرجات كالتالي:
</p>

<pre class="ipsCode" id="ips_uid_8957_8">
host1 | SUCCESS =&gt; {
	"changed": false,
	"ping": "pong"
}
 
host3 | SUCCESS =&gt; {
	"changed": false,
	"ping": "pong"
}
 
host2 | SUCCESS =&gt; {
	"changed": false,
	"ping": "pong"
}
</pre>

<p>
	وهو اختبار بسيط للتأكّد من أنّ Ansible يتصل بجميع مضيفاته.
</p>

<p>
	تعني all جميع المضيفات. ويمكننا بسهولة تحديد مجموعة معيّنة كما يلي:
</p>

<pre class="ipsCode">
$ ansible -m ping servers
</pre>

<p>
	يمكننا أيضًا تحديد مضيف بشكل فردي:
</p>

<pre class="ipsCode">
$ anmible -m ping host1
</pre>

<p>
	يمكننا تحديد عدّة مضيفات من خلال فصلها باستخدام النقطتين:
</p>

<pre class="ipsCode">
$ anmible -m ping host1: host2
</pre>

<p>
	إنّ المقطع -m ping من الأمر عبارة عن تعليمة لـ Ansible لاستخدام الوحدة "ping". وهي في الأساس أوامر يمكنك تشغيلها على المضيفات عن بعد. تعمل وحدة ping بعدّة طرق مثل أداة ping العادية في Linux، ولكنها بدلاً من ذلك تتحقق من اتصال Ansible.
</p>

<p>
	لا تأخذ وحدة ping في الواقع أيّة وسائط arguments، لكن يمكننا تجربة أمر آخر لمعرفة كيفيّة عمل ذلك. نمرّر المعاملات في تدوين نصي "سكريبت" عن طريق كتابة -a.
</p>

<p>
	تتيح لنا الوحدة "shell" إرسال أمر طرفيّة terminal command إلى المضيف البعيد واسترداد النتائج. على سبيل المثال، يمكننا استخدام الأمر التالي لمعرفة استخدام الذاكرة على جهاز host1:
</p>

<pre class="ipsCode">
$ ansible -m shell -a 'free -m' host1
</pre>

<p>
	ستكون مخرجات Shell كالتالي:
</p>

<pre class="ipsCode">
host1 | SUCCESS | rc=0 &gt;&gt;
         	total   	used   	free 	shared	buffers 	cached
Mem:      	3954    	227   	3726      	0     	14     	93
-/+ buffers/cache:    	119   	3834
Swap:        	0      	0      	0
</pre>

<p>
	وبذلك أصبح خادم Ansible الخاص بك مُهيئًا ويمكنك الاتصال والتحكم في المضيفات بنجاح.
</p>

<p>
	الخلاصة
</p>

<p>
	ضبطنا في هذه الدورة التعليميّة Ansible وتأكّدنا من إمكانية اتصاله مع كل مضيف. واستخدمنا أيضًا الأمر ansible لتنفيذ مهام بسيطة عن بُعد.
</p>

<p>
	وعلى الرغم من أن هذا مفيد، إلا أنّنا لم نُغطّي أهم ميزة لـ Ansible في هذا المقال وهي الـ Playbooks. تعتبر Ansible Playbooks طريقةً قويّة وبَسيطة لإدارة عمليات تهيئة الخادم وعمليات النشر المتعدّدة الأجهزة. للحصول على تمهيد حول كتب Playbook، راجع <a href="https://www.digitalocean.com/community/tutorials/configuration-management-101-writing-ansible-playbooks" rel="external nofollow">هذا الدليل</a>. بالإضافة إلى ذلك، فإننا نشجعك على مراجعة <a href="https://docs.ansible.com/ansible/latest/index.html" rel="external nofollow">توثيق Ansible</a> الرسميّة لمعرفة المزيد عن الأداة
</p>

<p>
	<br>
	ترجمة وبتصرّف للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-ansible-on-ubuntu-18-04" rel="external nofollow">How to Install and Configure Ansible on Ubuntu 18.04</a> لصاحبيه Stephen Rees-Carter و Mark Drake
</p>
]]></description><guid isPermaLink="false">394</guid><pubDate>Fri, 25 Jan 2019 13:05:43 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x624;&#x62A;&#x645;&#x62A; &#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x648;&#x648;&#x631;&#x62F;&#x628;&#x631;&#x64A;&#x633; &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ansible</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81-%D8%AA%D8%A4%D8%AA%D9%85%D8%AA-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r275/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_06/ansible-automate-wp-install.png.9c698f28dec4234684cb91a16ee0cb36.png" /></p>

<p>
	يعتبر <a href="https://www.ansible.com/" rel="external nofollow">Ansible</a> حلًا مناسبًا لأتمتة الأعمال التقنية البسيطة، فإن وجدت نفسك تقوم بتثبيت ووردبريس بشكل متكرر ومُمل، فقد يوفّر عليك Ansible الكثير من الوقت، وباستخدام بعض الأسطر بلغة YAML (وهي لغة توصيف واضحة ومباشرة) سنقوم بأتمتة عملية تثبيت ووردبريس على خادوم يعمل بنظام تشغيل Ubuntu 14.04، وفق الخطوات بصورة أوتوماتيكية.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="17889" data-unique="uctlyhh3i" src="https://academy.hsoub.com/uploads/monthly_2016_06/ansible-automate-wp-install.png.5d86165b671a80cd75d61f1f87ed7e0e.png" alt="ansible-automate-wp-install.png"></p>

<p>
	سنستخدم خادومين: أحدهما الخادوم الباني ويتم تشغيل Ansible عليه، والآخر الذي سنقوم بتثبيت ووردبريس عليه باستخدام Ansible.
</p>

<h2>
	المتطلبات الأولية
</h2>

<p>
	قبل المتابعة في المقال، سنحتاج للأمور التالية:
</p>

<ul>
<li>
		خادوم يعمل بنظام تشغيل Ubuntu 14.04. سنقوم بتثبيت Ansible على هذا الخادوم (ونشير إليه في المقال بـ الخادوم الباني). سنقوم بتسجيل الدخول إلى هذا الخادوم وجميع الأوامر والملفّات المذكورة في المقال على هذا الخادوم،
	</li>
	<li>
		خادوم آخر يعمل بنظام تشغيل Ubuntu 14.04. سنقوم بتثبيت ووردبريس عليه باستخدام Ansible (وسنشير إليه في المقال بـ خادوم ووردبريس)،
	</li>
	<li>
		حساب مستخدم عادي -على كِلا الخادومين- لا يملك صلاحيات مدير نظام، لكنّه يملك صلاحية تنفيذ الأمر <span style="font-family:courier new,courier,monospace;">sudo</span>،
	</li>
	<li>
		إضافة مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr></abbr></abbr> الخاص بالمستخدم -الذي أنشأناه على الخادوم الباني- إلى المفاتيح المصادقة <span style="font-family:courier new,courier,monospace;">authorized_keys</span> للمستخدم الذي أنشأناه على خادوم ووردبريس، وينبغي تنفيذ هذه العملية على الخادوم الباني ورفع المفاتيح إلى خادوم ووردبريس.
	</li>
</ul>
<h3>
	تنفيذ أوامر sudo بدون تأكيد باستخدام كلمة مرور
</h3>

<p>
	إنّ من الأسرع -ولكن أقل أمانًا- تنفيذ أوامر <span style="font-family:courier new,courier,monospace;">sudo</span> على خادوم ووردبريس بدون الحاجة لإدخال كلمة مرور تأكيد في كل مرّة.
</p>

<p>
	لإعطاء المستخدم على خادوم ووردبريس هذه الإمكانية، سنقوم بتعديل ملف <span style="font-family:courier new,courier,monospace;">sudoers</span> باستخدام الأمر <span style="font-family:courier new,courier,monospace;">visudo</span> على سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_8">
<span class="pln">$ visudo</span></pre>

<p>
	ومن ثم سنضيف السطر التالي في نهاية الملف:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_10">
<span class="pln">sammy ALL=(ALL) NOPASSWD: ALL</span></pre>

<p>
	<strong>ملاحظة</strong>: لا تنس استبدال اسم المستخدم (sammy في هذه الحالة) باسم المستخدم الموجود لديك، وتأكد من وضع السطر في نهاية الملف حتى لا يتم تجاوزه بالصلاحيات الافتراضية الموجودة في الملف.
</p>

<p>
	<strong>نصيحة</strong>: قم دومًا باستخدام الأمر <span style="font-family:courier new,courier,monospace;">visudo</span> عند تعديل ملف <span style="font-family:courier new,courier,monospace;">sudoers</span>، لأن الأمر سيقوم بالتحقق من التعديلات قبل حفظ الملف ويحميك بالتالي من ارتكاب أخطاء في الملف قد تؤدي إلى منعك من الدخول.
</p>

<p>
	حالما تنتهي من تنفيذ العملية السابقة سيغدو بإمكانك تنفيذ الأمر التالي على خادوم ووردبريس بدون إدخال كلمة مرور لتأكيده:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_12">
<span class="pln">$ sudo echo "Hello"</span></pre>

<p>
	وفي بقية المقال، تستطيع تنفيذ الأمر <span style="font-family:courier new,courier,monospace;">ansible-playbook</span> بدون المُعامل <span style="font-family:courier new,courier,monospace;">K- </span>كي تتجنب الحاجة لإدخال كلمة المرور للتأكيد بشكل يدوي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_14">
<span class="pln">$ ansible-playbook playbook.yml -i hosts -u sammy</span></pre>

<h2>
	الخطوة الأولى: تثبيت Ansible
</h2>

<p>
	سنقوم الآن بتثبيت Ansible على الخادوم الباني، ونبدأ بتسجيل الدخول عبر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr></abbr></abbr> إلى الخادوم وتنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_16">
<span class="pln">$ sudo apt-get install ansible -y</span></pre>

<p>
	وتستطيع التأكد من تثبيت Ansible بتنفيذ الأمر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_18">
<span class="pln">$ ansible --version</span></pre>

<p>
	حيث ينبغي أن يكون الخرج مشابهًا (وليس بالضرورة مطابقًا) لما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_20">
<span class="pln">ansible 1.5.4</span></pre>

<h2>
	الخطوة الثانية: إعداد بنية الملفات
</h2>

<p>
	الآن وبعد أن انتهينا من تثبيت Ansible، دعونا نقوم بإعداد بنية الملفات من أجل Ansible playbook.
</p>

<p>
	سنقوم بإنشاء مجلّد على النحو التالي:
</p>

<pre class="ipsCode" id="ips_uid_1556_22">
$ cd ~
$ mkdir wordpress-ansible &amp;&amp; cd wordpress-ansible</pre>

<p>
	سنقوم الآن بإنشاء ملفّين: الأول يدعى<span style="font-family:courier new,courier,monospace;"> playbook.yml</span> (حيث سنقوم بكتابة الأوامر الخاصة بتثبيت ووردبريس فيه) والثاني يدعى <span style="font-family:courier new,courier,monospace;">hosts</span> (وهذا يُخبر Ansible عن الخواديم التي سيتم تنفيذ الأوامر عليها):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_24">
<span class="pln">$ touch playbook.yml
$ touch hosts</span></pre>

<p>
	إنّ من الأفضل فصل الأوامر بحسب الأدوار، ومن الممكن اعتبار الأدوار كأجزاء من الممكن إعادة استخدامها، وسنقوم في هذا المشروع بإنشاء 4 أدوار:
</p>

<ul>
<li>
		server
	</li>
	<li>
		php
	</li>
	<li>
		mysql
	</li>
	<li>
		wordpress
	</li>
</ul>
<p>
	سنقوم بإنشاء مجلد الأدوار في الجذر الرئيسي للمجلد الذي أنشأناه سابقًا <span style="font-family:courier new,courier,monospace;">wordpress-ansible/~</span> بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_1556_31">
$ mkdir roles &amp;&amp; cd roles</pre>

<p>
	والآن سنقوم بتجهيز الأدوار باستخدام أداة من أدوات Ansible تدعى <span style="font-family:courier new,courier,monospace;">ansible-galaxy</span>، حيث سنقوم من أجل كل دور بتنفيذ الأمر <span style="font-family:courier new,courier,monospace;">ansible-galaxy init</span> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_28">
<span class="pln">$ ansible-galaxy init server
$ ansible-galaxy init php
$ ansible-galaxy init mysql
$ ansible-galaxy init wordpress</span></pre>

<p>
	ستلاحظ بأن هذا الأمر سيقوم بإنشاء هيكل ملفات متكامل لكل دور من الأدوار، وهذه الخطوة هي إحدى الأمور التي ينصح بها في توثيق Ansible. ما يهمّنا غالبًا هو التعامل مع محتوى ملف <span style="font-family:courier new,courier,monospace;">tasks/main.yml</span> لكل دور.
</p>

<p>
	عند الوصول إلى هذه المرحلة سيكون لدينا الهيكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_33">
<span class="pln">[.]
|_ playbook.yml
|_ hosts
|_ [roles]
      |_ [server]
            |_ ...
      |_ [php]
            |_ ...
      |_ [mysql]
            |_ ...
      |_ [wordpress]
            |_ ...   </span></pre>

<h2>
	الخطوة الثالثة: إنشاء الـ Playbook
</h2>

<p>
	سنقوم الآن بكتابة الأوامر التي ستقوم بتثبيت ووردبريس على خادوم ووردبريس.
</p>

<h3>
	ملف المخزون hosts
</h3>

<p>
	يُخبر هذا الملف Ansible بالخواديم التي نرغب بتثبيت ووردبريس عليها، ومن الممكن تنفيذ الأوامر للخواديم أو مجموعة الخواديم المعرّفة في ملف المخزون <span style="font-family:courier new,courier,monospace;">hosts</span>.
</p>

<p>
	سنقوم بتحرير ملف <span style="font-family:courier new,courier,monospace;">hosts</span> باستخدام محرر <span style="font-family:courier new,courier,monospace;">nano</span> أو أي محرر آخر تفضّله وكتابة التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_35">
<span class="pln">[wordpress]
wordpress_server_ip</span></pre>

<p>
	<strong>ملاحظة</strong>: من الممكن وضع أي عدد نرغب به من العناوين الرقمية IPs تحت مجموعة <span style="font-family:courier new,courier,monospace;">[wordpress]</span>. سيؤدي هذا إلى تنفيذ الأوامر على جميع الخواديم المذكورة على افتراض أننا نملك صلاحية استخدام هذه الخواديم. سيمكّننا هذا من تثبيت ووردبريس على أي عدد من الخواديم دفعة واحدة.
</p>

<h3>
	ملف Playbook
</h3>

<p>
	يمكن اعتبار هذا الملف كتعريف لتطبيق ووردبريس الذي سنقوم بتثبيته. سيحتوي الملف على جميع الأدوار التي قمنا بإنشائها بغرض تجهيز تطبيق مفيد (ووردبريس في حالتنا).
</p>

<p>
	سنقوم بداية بتحرير الملف باستخدام محرر <span style="font-family:courier new,courier,monospace;">nano</span> أو أي محرر آخر ترغب به:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_37">
<span class="pln">$ nano ~/wordpress-ansible/playbook.yml</span></pre>

<p>
	ومن ثم سنضيف المحتويات التالية إلى الملف، والتي ستُخبر Ansible أية أدوار سيتم تنفيذها على أية خواديم (سيتم تنفيذ الأدوار المذكورة في حالتنا على مجموعة العناوين الرقمية المدرجة في مجموعة <span style="font-family:courier new,courier,monospace;">wordpress</span> المسجّلة في ملف <span style="font-family:courier new,courier,monospace;">hosts</span> الذي أنشأناه سابقًا):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_39">
<span class="pln">- hosts: wordpress

  roles:
    - server
    - php
    - mysql
    - wordpress</span></pre>

<p>
	والآن لنعد إلى الجذر الرئيسي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_41">
<span class="pln">$ cd ~/wordpress-ansible/</span></pre>

<p>
	سنتأكد الآن من أنه من الممكن إجراء اتصال ما بين الخادوم الباني وخادوم ووردبريس من خلال تنفيذ ملف playbook الذي لن يقوم بأي شيء سوى التحقق من الاتصال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_43">
<span class="pln">$ ansible-playbook playbook.yml -i hosts -u sammy -K</span></pre>

<p>
	ستُطالب بإدخال كلمة المرور لتأكيد الأمر، ولا تنس أن تقوم باستبدال اسم المستخدم بالموجود لديك.
</p>

<p>
	سيظهر لنا خرج يشبه التالي عند تنفيذ الأمر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_47">
<span class="pln">ansible-playbook playbook.yml -i hosts -u sammy -K

PLAY [wordpress] ************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [188.166.68.134]

PLAY RECAP ******************************************************************** 
188.166.68.134             : ok=1    changed=0    unreachable=0    failed=0 </span></pre>

<p>
	والذي سيؤكد لنا بأن الاتصال قد تم بنجاح، دون أن يتم تنفيذ أي تعديلات لأننا لم نقم بتحديد أي أوامر لتنفيذها حتى الآن.
</p>

<p>
	إن فشل تنفيذ الأمر فتأكّد من أن باستطاعتك تسجيل الدخول إلى خادوم ووردبريس من الخادوم الباني باستخدام مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></abbr></abbr></abbr> الذي قمت بنسخه في البداية.
</p>

<h2>
	الخطوة الثالثة: إنشاء الأدوار
</h2>

<h3>
	دور Server
</h3>

<p>
	سنقوم بداية بتعريف الأوامر التي سيتم تنفيذها على الخادوم ولهذا الغرض سنقوم بتحرير أوامر دور <span style="font-family:courier new,courier,monospace;">server</span>.
</p>

<p>
	ستقوم الأوامر التي سنصرّح عنها بتثبيت جميع البرمجيات التي سنحتاجها على السيرفر الهدف. نبدأ بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_49">
<span class="pln">$ nano roles/server/tasks/main.yml</span></pre>

<p>
	قم بإضافة المحتويات التالية وتأكد من وجود سطر واحد فقط يحتوي على <span style="font-family:courier new,courier,monospace;">--- </span>(حيث يوجد هذا السطر سلفًا بشكل افتراضي):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_51">
<span class="pln">---
- name: Update apt cache
  apt: update_cache=yes cache_valid_time=3600
  sudo: yes

- name: Install required software
  apt: name={{ item }} state=present
  sudo: yes
  with_items:
    - apache2
    - mysql-server
    - php5-mysql
    - php5
    - libapache2-mod-php5
    - php5-mcrypt
    - python-mysqldb</span></pre>

<p>
	سيقوم المحتوى السابق بما يلي:
</p>

<ul>
<li>
		تحديث خبء <span style="font-family:courier new,courier,monospace;">apt-cache</span> (تنفيذ الأمر <span style="font-family:courier new,courier,monospace;">apt-get update</span>)،
	</li>
	<li>
		تثبيت Apache ،MySQL ،PHP وبرمجيات أخرى مرتبطة باستخدام <span style="font-family:courier new,courier,monospace;">apt-get install</span>.
	</li>
</ul>
<p>
	وإن كنت مهتمًّا بمعرفة تفاصيل ما نقوم بتثبيته، فيمكنك الاطلاع على هذا المقال حول <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-%D8%AD%D8%B2%D9%85-mysql-%D8%8Capache-%D8%8Clinux-lamp-%D9%88-php-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r27/" rel="">تثبيت LAMP على Ubuntu 14.04 بشكل يدوي</a>.
</p>

<p>
	سنقوم الآن بتنفيذ<span style="font-family:courier new,courier,monospace;"> ansible-playbook</span> مرة أخرى على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_55">
<span class="pln">$ ansible-playbook playbook.yml -i hosts -u sammy -K</span></pre>

<p>
	ويفترض هذه المرة أن يكون الخرج بما يشبه التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1556_57">
<span class="pln">ansible-playbook playbook.yml -i hosts -u sammy -K

PLAY [wordpress] ************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [188.166.68.134]

TASK: [server | Update apt cache] ********************************************* 
ok: [188.166.68.134]

TASK: [server | Install required software] ************************************ 
changed: [188.166.68.134] =&gt; (item=apache2,mysql-server,php5-mysql,php5,libapache2-mod-php5,php5-mcrypt,python-mysqldb)

PLAY RECAP ******************************************************************** 
188.166.68.134             : ok=3    changed=1    unreachable=0    failed=0  </span></pre>

<p>
	وبعد التنفيذ، ينبغي أن تكون قادرًا على استعراض الصفحة الافتراضية لـ Apache عبر فتح العنوان<span style="font-family:courier new,courier,monospace;"> http://wordpress_server_ip</span> في المتصفح.
</p>

<p>
	<strong>ملاحظة</strong>: إن توقّف تنفيذ الأمر بشكل نهائي عند سطر <span style="font-family:courier new,courier,monospace;">[TASK: [server | Update apt cache</span> فمن المحتمل أن يكون هناك نقص في الصلاحيات المطلوبة على الخادوم الهدف، لذا تأكّد من أن الوصول باستخدام <span style="font-family:courier new,courier,monospace;">sudo</span> تم إعداده بشكل صحيح على خادوم ووردبريس.
</p>

<h3>
	دور PHP
</h3>

<p>
	سنقوم الآن بتجهيز الأوامر التي تستهدف PHP، ولهذا الغرض سنقوم بتحرير الملف الخاص بهذا الدور:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_9">
<span class="pln">$ nano roles/php/tasks/main.yml</span></pre>

<p>
	ومن ثم سنضيف المحتوى التالي (تأكّد من وجود سطر واحد فقط يحتوي على <span style="font-family:courier new,courier,monospace;">---</span> في بداية الملف):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_11">
<span class="pln">---
- name: Install php extensions
  apt: name={{ item }} state=present
  sudo: yes
  with_items:
    - php5-gd 
    - libssh2-php</span></pre>

<p>
	سيقوم المحتوى السابق بتثبيت الملحقات extensions الضرورية لـ PHP وهي:<span style="font-family:courier new,courier,monospace;"> php5-gd</span> و <span style="font-family:courier new,courier,monospace;">libssh2-php</span>.
</p>

<h3>
	دور MySQL
</h3>

<p>
	سنقوم الآن بإعداد قاعدة بيانات MySQL لموقع ووردبريس، وذلك في دور <span style="font-family:courier new,courier,monospace;">mysql</span>.
</p>

<p>
	سنحتاج من أجل القيام بذلك إلى بعض المتغيّرات، والتي من الممكن تخزينها في ملف المتغيرات الافتراضية<span style="font-family:courier new,courier,monospace;"> defaults/main.yml</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_13">
<span class="pln">$ nano roles/mysql/defaults/main.yml</span></pre>

<p>
	سنضيف في الملف اسم قاعدة البيانات، اسم المستخدم الخاص بالقاعدة، كلمة المرور الخاصة بالمستخدم وبنفس الترتيب، ولا تنس أن تستخدم كلمة مرور معقّدة لأغراض أمنية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_15">
<span class="pln">---
wp_mysql_db: wordpress
wp_mysql_user: wordpress
wp_mysql_password: wp_db_password</span></pre>

<p>
	والآن نستخدم <span style="font-family:courier new,courier,monospace;">nano</span> لتحرير ملف المهام:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_17">
<span class="pln">$ nano roles/mysql/tasks/main.yml</span></pre>

<p>
	ونضيف المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_19">
<span class="pln">---
- name: Create mysql database
  mysql_db: name={{ wp_mysql_db }} state=present

- name: Create mysql user
  mysql_user: 
    name={{ wp_mysql_user }} 
    password={{ wp_mysql_password }} 
    priv=*.*:ALL</span></pre>

<p>
	يقوم المحتوى السابق بـ:
</p>

<ul>
<li>
		إنشاء قاعدة بيانات MySQL،
	</li>
	<li>
		إنشاء مستخدم MySQL،
	</li>
	<li>
		إعطاء المستخدم صلاحية الوصول إلى قاعدة البيانات.
	</li>
</ul>
<p>
	وكما ترى فسيتم استخدام قيم المتغيرات بشكل تلقائي من ملف<span style="font-family:courier new,courier,monospace;"> defaults/main.yml</span> عند تنفيذ الأوامر.
</p>

<p>
	<strong>ملاحظة</strong>: توفّر أدوات Ansible أداة <span style="font-family:courier new,courier,monospace;"><a href="https://docs.ansible.com/ansible/playbooks_vault.html" rel="external nofollow">ansible-vault</a></span> والتي تسمح بتخزين كلمات المرور بصورة مشفّرة حتى لا تكون قابلة للقراءة في الملف، ولكن الحديث عن هذا خارج إطار حديثنا الآن.
</p>

<h3>
	دور WordPress
</h3>

<p>
	والآن نأتي للحظة التي كنا ننتظرها.. تثبيت ووردبريس.
</p>

<p>
	نبدأ بتحرير ملف المهام كالمعتاد:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_21">
<span class="pln">$ nano roles/wordpress/tasks/main.yml</span></pre>

<p>
	وسنقوم بنسخ المحتوى التالي إليه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_23">
<span class="pln">---
- name: Download WordPress  get_url: 
    url=https://wordpress.org/latest.tar.gz 
    dest=/tmp/wordpress.tar.gz
    validate_certs=no 
    sudo: yes</span></pre>

<p>
	سيقوم المحتوى السابق بتحميل ووردبريس إلى مجلد <span style="font-family:courier new,courier,monospace;">tmp/ </span>(ويمكن للحذرين أن ينتبهوا إلى أننا قمنا بتعطيل التحقق من الشهادة الأمنية، لأنه سيمنع عملية التحميل).
</p>

<p>
	بعد اكتمال التحميل سنقوم بفك ضغط الملف إلى <span style="font-family:courier new,courier,monospace;">var/www/</span>، وهو المسار الذي يستخدمه Apache لتخزين محتوى الويب، وبالتالي سنضيف الجزء التالي لمحتوى الملف أيضًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_25">
<span class="pln">- name: Extract WordPress unarchive: src=/tmp/wordpress.tar.gz dest=/var/www/ copy=no
  sudo: yes</span></pre>

<p>
	وبعد أن يتم فك ضغط الملفات، سنقوم بتحديث مسار الجذر الافتراضي <span style="font-family:courier new,courier,monospace;">DocumentRoot</span> في ملف إعدادات Apache كي يشير إلى موقع ووردبريس:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_27">
<span class="pln">- name: Update default Apache site
  sudo: yes
  lineinfile: 
    dest=/etc/apache2/sites-enabled/000-default.conf 
    regexp="(.)+DocumentRoot /var/www/html"
    line="DocumentRoot /var/www/wordpress"
  notify:
    - restart apache
  sudo: yes</span></pre>

<p>
	لاحظ أننا استخدمنا الكتلة <span style="font-family:courier new,courier,monospace;">notify</span>، والتي نحتاجها عند الرغبة بإعادة تشغيل خدمات بعد أن يتم تنفيذ مهمّة بنجاح، ولا يتم تنفيذ معالجات <span style="font-family:courier new,courier,monospace;">notify</span> إلا عندما يحصل تغيير على حالة المهمّة.
</p>

<p>
	سنقوم بإضافة المعالج الخاص بنا لإعادة تشغيل Apache باستخدام <span style="font-family:courier new,courier,monospace;">restart apache</span> ويتم ذلك في الملف<span style="font-family:courier new,courier,monospace;"> roles/wordpress/handlers/main.yml</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_29">
<span class="pln">$ nano roles/wordpress/handlers/main.yml</span></pre>

<p>
	نضيف المحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_31">
<span class="pln">---
- name: restart apache
  service: name=apache2 state=restarted
  sudo: yes   </span></pre>

<p>
	ويتم تنفيذ هذه المهمّة عندما تتغير حالة المهمّة التي تحتوي على الكتلة <span style="font-family:courier new,courier,monospace;">notify: restart apache</span>، مما يؤدي إلى إعادة تشغيل الخدمة.
</p>

<h3>
	إعداد ووردبريس
</h3>

<p>
	بالعودة إلى<span style="font-family:courier new,courier,monospace;"> roles/wordpress/tasks/main.yml</span>، سنقوم الآن بتجهيز إعدادات موقع ووردبريس، فنقوم أولًا بنسخ ملف الإعدادات <span style="font-family:courier new,courier,monospace;">config</span> الافتراضي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_33">
<span class="pln">- name: Copy sample config file
  command: mv /var/www/wordpress/wp-config-sample.php /var/www/wordpress/wp-config.php creates=/var/www/wordpress/wp-config.php
  sudo: yes</span></pre>

<p>
	ومن ثم نقوم بتغيير بعض الثوابت في الملف لتتطابق مع معلومات الاتصال بقاعدة البيانات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_35">
<span class="pln">- name: Update WordPress config file
  lineinfile:
    dest=/var/www/wordpress/wp-config.php
    regexp="{{ item.regexp }}"
    line="{{ item.line }}"
  with_items:
    - {'regexp': "define\\('DB_NAME', '(.)+'\\);", 'line': "define('DB_NAME', '{{wp_mysql_db}}');"}        
    - {'regexp': "define\\('DB_USER', '(.)+'\\);", 'line': "define('DB_USER', '{{wp_mysql_user}}');"}        
    - {'regexp': "define\\('DB_PASSWORD', '(.)+'\\);", 'line': "define('DB_PASSWORD', '{{wp_mysql_password}}');"}
  sudo: yes   </span></pre>

<p>
	حيث ستقوم المهمّة بجلب معلومات الاتصال بالقاعدة من ملف المتغيّرات الافتراضية الذي قمنا بتحريره سابقًا.
</p>

<p>
	بعد الانتهاء من الخطوات السابقة بنجاح، سيكون قد أصبح لدينا ملفّين لدور <span style="font-family:courier new,courier,monospace;">wordpress</span>، وفيما يلي النسخة الكاملة لمحتوى الملفّين..
</p>

<ul>
<li>
		ملف <span style="font-family:courier new,courier,monospace;">roles/wordpress/tasks/main.yml</span>:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_37">
<span class="pln">---
- name: Download WordPress  get_url: 
    url=https://wordpress.org/latest.tar.gz 
    dest=/tmp/wordpress.tar.gz
    validate_certs=no

- name: Extract WordPress  unarchive: src=/tmp/wordpress.tar.gz dest=/var/www/ copy=no
  sudo: yes

- name: Update default Apache site
  sudo: yes
  lineinfile: 
    dest=/etc/apache2/sites-enabled/000-default.conf 
    regexp="(.)+DocumentRoot /var/www/html"
    line="DocumentRoot /var/www/wordpress"
  notify:
    - restart apache

- name: Copy sample config file
  command: mv /var/www/wordpress/wp-config-sample.php /var/www/wordpress/wp-config.php creates=/var/www/wordpress/wp-config.php
  sudo: yes

- name: Update WordPress config file
  lineinfile:
    dest=/var/www/wordpress/wp-config.php
    regexp="{{ item.regexp }}"
    line="{{ item.line }}"
  with_items:
    - {'regexp': "define\\('DB_NAME', '(.)+'\\);", 'line': "define('DB_NAME', '{{wp_mysql_db}}');"}        
    - {'regexp': "define\\('DB_USER', '(.)+'\\);", 'line': "define('DB_USER', '{{wp_mysql_user}}');"}        
    - {'regexp': "define\\('DB_PASSWORD', '(.)+'\\);", 'line': "define('DB_PASSWORD', '{{wp_mysql_password}}');"}
  sudo: yes</span></pre>

<ul>
<li>
		ملف <span style="font-family:courier new,courier,monospace;">roles/wordpress/handlers/main.yml</span>:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_39">
<span class="pln">---
- name: restart apache
  service: name=apache2 state=restarted
  sudo: yes</span></pre>

<p>
	ونكون قد انتهينا. لنقم الآن بتشغيل <span style="font-family:courier new,courier,monospace;">ansible-playbook</span> لآخر مرة لإعداد موقع ووردبريس:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_41">
<span class="pln">$ ansible-playbook playbook.yml -i hosts -u sammy -K</span></pre>

<p>
	وبعد تنفيذ الأمر ينبغي أن نكون قادرين على تصفّح الموقع عبر طلب عنوانه <span style="font-family:courier new,courier,monospace;">http://your_server_ip </span>في المتصفح
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="17888" href="https://academy.hsoub.com/uploads/monthly_2016_06/001-initial_config.png.9fc99f007dca83909c8fcb4a83beea5f.png" rel="external"><img alt="001-initial_config.png" class="ipsImage ipsImage_thumbnailed" data-fileid="17888" data-unique="900dqju21" src="https://academy.hsoub.com/uploads/monthly_2016_06/001-initial_config.thumb.png.610a90ed552a2ab32b582d80a5c351c0.png"></a>
</p>

<p>
	ويمكن الآن متابعة إعداد موقع ووردبريس بشكل يدوي عند هذه المرحلة.
</p>

<h2>
	الخلاصة
</h2>

<p>
	تهانينا! ستتمكن الآن من تثبيت مواقع ووردبريس على أي عدد من الخواديم التي تعمل بنظام تشغيل Ubuntu باستخدام أمر واحد:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5149_43">
<span class="pln">$ ansible-playbook playbook.yml -i hosts -u sammy -K</span></pre>

<p>
	وكل ما تحتاج للقيام به هو إضافة العنوان الرقمي IP إلى قائمة الخواديم المستهدفة في ملف <span style="font-family:courier new,courier,monospace;">hosts</span> والتأكّد من أن الصلاحيات قد تم إعدادها مسبقًا على الخادوم الهدف.
</p>

<p>
	تناولنا في المقال بصورة سريعة كيفية استخدام Ansible لتثبيت مواقع ووردبريس بشكل اوتوماتيكي، وقد تكون مهتمًّا ببعض التحسينات الإضافية الممكنة:
</p>

<ul>
<li>
		تعلّم كيفية استضافة أدوارك الخاصة في الـ <a href="https://galaxy.ansible.com/" rel="external nofollow">Ansible Galaxy</a>.
	</li>
	<li>
		أتمتة عملية الإعداد النهائية لموقع ووردبريس حتى لا يكون هناك حاجة للقيام بأي إعداد يدوي للموقع المطلوب إطلاقًا.
	</li>
</ul>
<p>
	ترجمة -وبتصرّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-automate-installing-wordpress-on-ubuntu-14-04-using-ansible" rel="external nofollow">How To Automate Installing WordPress on Ubuntu 14.04 Using Ansible</a> لصاحبه Christo Crampton.
</p>
]]></description><guid isPermaLink="false">275</guid><pubDate>Thu, 16 Jun 2016 17:21:29 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; PHP &#x645;&#x62A;&#x639;&#x62F;&#x62F;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ansible &#x639;&#x644;&#x649; Ubuntu</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-php-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%B9%D9%84%D9%89-ubuntu-r167/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php.png.a0effb1e11a976be77fbf4c196e951d8.png" /></p>

<p>هذا الدّرس هو جزء من <a href="https://academy.hsoub.com/search/?tags=%D9%86%D8%B4%D8%B1+%D8%AA%D8%B7%D8%A8%D9%8A%D9%82+php+%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85+ansible">سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu</a>، تحدّثنا في الأجزاء الأولى عن الخطوات الأساسيّة لنشر تطبيق، وفي بقيّة الأجزاء تكلمنا عن مواضيع أكثر تقدّمًا مثل <a href="https://academy.hsoub.com/devops/servers/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%86%D8%AF-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r164/">قواعد البيانات</a>، <a href="https://academy.hsoub.com/devops/servers/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AC%D8%AF%D9%88%D9%84%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D8%A7%D9%85-%D8%B9%D9%86%D8%AF-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r165/">عفاريت الطابور queue daemons، وجدولة المهام (عبر cron)</a>.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php.png.318c66e463d6d3c2d9fe42956dca9c2f.png"><img data-fileid="10241" class="ipsImage ipsImage_thumbnailed" alt="ansible-php.thumb.png.744f530b0f98a71c87" src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php.thumb.png.744f530b0f98a71c870a7de064a74234.png"></a></p><p>سنقوم في هذا الدّرس بالبناء على ما تعلمناه في الدروس السابقة عن طريق تحويل playbook في Ansible من دعمها لتطبيق واحد إلى دعمها لنشر تطبيقات PHP متعدّدة على خادوم أو عدّة خواديم.</p><p>سنستخدم تطبيقات <a rel="external nofollow" href="http://lumen.laravel.com/">Lumen</a> بسيطة كجزء أمثلتنا، ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك، من المفضّل أن تستخدم تطبيقات الأمثلة حتى تجد نفسك متآلفًا مع القيام بالتغييرات لِـ playbook.</p><h2 id="الخطوة-الأولى-إضافة-المزيد-من-التطبيقات">الخطوة الأولى – إضافة المزيد من التطبيقات</h2><p>في هذه الخطوة سنقوم بإعداد تطبيقين إضافيين في الـ playbook لدينا.</p><p>الآن وقد أعدنا تصنيع الـ playbook سنستخدم متغيرات لتعريف التطبيقات، إنّ عملية إضافة تطبيقات جديدة لخادومنا هي عملية سهلة جدًّا، نقوم بإضافتها ببساطة إلى قائمة المتغيرات <code>applications</code>، وهنا تظهر قوة متغيرات Ansible.</p><p>نفتح playbook من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نبحث في أعلى القسم <code>vars</code> عن الكتلة <code>applications</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نضيف تطبيقين اثنين:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نحفظ الـ playbook ونقوم بتشغيلها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>قد تستغرق هذه الخطوة بعض الوقت بينما يقوم الـ composer بإعداد التطبيقات الجديدة، وعندما ينتهي سنلاحظ تغيير عدد من المهام، وإن دققنا أكثر سنلاحظ أنّه سيتم عرض كل عنصر ناتج عن الحلقة، يخبرنا الأول وهو تطبيقنا الأصل بعبارة <code>ok</code> أو <code>skipped</code>، بينما يخبرنا التطبيقان الجديدان بالحالة <code>changed</code>.</p><p>والأهم من ذلك أنّه إذا زرنا النطاقات الثلاثة لمواقعنا التي أعددناها في متصفح الإنترنت فينبغي أن نلاحظ ثلاثة مواقع مختلفة.</p><p>الأول يبدو مألوفًا لنا، أما الموقعان الآخران سيعرضان:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                http://one.example.com/
This is example app one!
</pre><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                http://two.example.com/
This is example app two!
</pre><p>وبذلك قمنا بنشر تطبيقي ويب جديدين عن طريق تحديث قائمة التطبيقات ببساطة.</p><h2 id="الخطوة-الثانية-استخدام-متغيرات-المضيفين-host-variables">الخطوة الثانية – استخدام متغيرات المضيفين Host Variables</h2><p>سنستخرج في هذه الخطوة متغيراتنا إلى متغيرات المضيفين.</p><p>بالرجوع إلى الوراء نجد أنّ متغيرات الـ playbook جيدة، ولكن ماذا لو أردنا نشر تطبيقات مختلفة على خواديم مختلفة باستخدام نفس الـ playbook؟ نستطيع عمل تحقّق شرطي على كل مهمّة لإيجاد الخادوم الذي يقوم بتشغيل المهمة، أو نستطيع استخدام متغيرات المضيفين، وهي تمامًا كما تبدو عليه: متغيرات تُطبَّق على مضيف معيّن بدلًا من كافّة المضيفين عبر الـ playbook.</p><p>يمكن تعريف متغيرات المضيف سطريًّا inline بداخل الملف <code>hosts</code> كما فعلنا مع المتغير <code>ansible_ssh_user</code> أو يمكن تعريفها في ملف مخصّص لكل مضيف داخل الدليل <code>host_vars</code>.</p><p>في البداية نقوم بإنشاء دليل جديد إلى جانب الملف <code>hosts</code> والـ playbook، نقوم بتسمية الدليل بـ <code>host_vars</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">mkdir host_vars
</pre><p>نحتاج بعدها إلى إنشاء ملف من أجل المضيف، الاتفاقية التي تستخدمها Ansible هي من أجل أن يتوافق اسم الملف مع اسم المضيف في الملف <code>hosts</code>، لذلك على سبيل المثال إن كان يبدو الملف <code>hosts</code> لدينا كما يلي:<code> </code></p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Ansible hosts file

your_first_server_ip ansible_ssh_user=sammy </pre><p>فينبغي أن نقوم بإنشاء ملف يُدعى <code>host_vars/your_first_server_ip</code>، فلنقم بإنشائه الآن:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano host_vars/your_first_server_ip
</pre><p>تستخدم ملفّات المضيفين YAML من أجل تنسيقها تمامًا كما هو الحال مع الـ playbooks، ويعني هذا أنّنا نستطيع نسخ القائمة applications إلى ملف المضيفين الجديد لدينا بحيث يبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نقوم بحفظ ملف المضيفين الجديد ونفتح الـ playbook لتحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نحدّث أعلى الملف لإزالة كامل القسم <code>applications</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">               Updated top of php.yml
---
- hosts: php
  sudo: yes

  vars:
    wwwuser: www-data

  tasks:
. . .
</pre><p>نحفظ الـ playbook ونقوم بتشغيلها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>وعلى الرغم من أنّنا نقلنا متغيراتنا من الـ playbook إلى ملف المضيفين فيجب أن يبقى الخرج نفسه ولا يجب أن يتم تبليغنا عن تغييرات من قبل Ansible، وكما نرى يعمل <code>host_vars</code> بنفس الطريقة التي يعمل بها <code>vars</code> في الـ playbook، ولكنّه مُخصّص للمضيف.</p><p>ستكون المتغيرات المُعرّفة في ملفّات <code>host_vars</code> قابلة للوصول عبر كامل الـ playbooks التي تدير الخادوم، وهو مفيد من أجل الخيارات والإعدادات الشائعة، ومع ذلك كن حذرًا من استخدام اسم شائع قد يعني أشياء مختلفة عبر الـ playbooks المختلفة.</p><h2 id="الخطوة-الثالثة-نشر-التطبيقات-على-خادوم-آخر">الخطوة الثالثة – نشر التطبيقات على خادوم آخر</h2><p>سنستخدم في هذه الخطوة ملفات المضيفين الجديدة وننشر تطبيقاتنا على خادوم آخر.</p><p>نحتاج في البداية إلى تحديث ملف المضيفين <code>hosts</code> بمضيفنا الجديد، نفتحه من أجل تحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano hosts
</pre><p>ونقوم بإضافة المضيف الجديد:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">            Ansible hosts file

your_first_server_ip ansible_ssh_user=sammy 
your_second_server_ip ansible_ssh_user=sammy </pre><p>نحفظ الملف ونغلقه.</p><p>نحتاج بعدها إلى إنشاء ملف مضيفين جديد، كما فعلنا مع أول ملف:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano host_vars/your_second_server_ip
</pre><p>تستطيع انتقاء واحد أو أكثر من تطبيقات مثالنا وإضافتها إلى ملف المضيف لديك، فإذا أردت مثلًا نشر مثالنا الأصلي والمثال الثاني إلى خادوم جديد فيجب أن تستخدم:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نقوم بحفظ playbook.<br>وأخيرًا نقوم بتشغيلها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>ستستغرق Ansible وقتًا ليتم تشغيلها لأنّها تقوم بإعداد كل شيء على خادومنا الثاني، وعندما تنتهي نفتح تطبيقاتنا التي اخترناها في المتصفح (استخدمنا في هذا المثال <code>laravel.example2.com</code> و<code>two.example2.com</code>) وللتأكد من أنّه تم إعدادها بشكل صحيح يجب أن نرى التطبيقات المحدّدة التي اخترناها من أجل ملف المضيفين، وينبغي ألّا تحدث أيّة تغييرات على خادومنا الأصلي.</p><h2 id="الخاتمة">الخاتمة</h2><p>أخذنا في هذا الدرس playbook تطبيق وحيد تعمل بشكل كامل وقمنا بتحويلها لتدعم تطبيقات متعددة عبر عدّة خواديم، وبجمعها مع المواضيع التي تمت تغطيتها في الدروس السابقة يجب أن تمتلك كل ما تحتاجه لكتابة playbook كاملة لنشر تطبيقاتك، وكما هو الحال مع الدروس السابقة فلا زلنا لم نسجل الدخول بشكل مباشر باستخدام <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>.</p><p>ومن المؤكد أنك لاحظت مدى بساطة إضافة المزيد من التطبيقات والمزيد من الخواديم بعد الانتهاء من تجهيز بنية الـ playbook، وهنا تكمن قوة Ansible وهو ما يجعلها مرنة جدًّا وسهلة الاستخدام.</p><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-deploy-multiple-php-applications-using-ansible-on-ubuntu-14-04">How To Deploy Multiple PHP Applications using Ansible on Ubuntu 14.04</a> لصاحبه Stephen Rees-Carter.</p>
]]></description><guid isPermaLink="false">167</guid><pubDate>Sun, 17 Jan 2016 19:06:25 +0000</pubDate></item><item><title>&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x627;&#x644;&#x645;&#x62A;&#x63A;&#x64A;&#x631;&#x627;&#x62A; &#x639;&#x646;&#x62F; &#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; PHP &#x645;&#x62A;&#x639;&#x62F;&#x62F;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ansible</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D9%85%D8%AA%D8%BA%D9%8A%D8%B1%D8%A7%D8%AA-%D8%B9%D9%86%D8%AF-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-php-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r166/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_01/php-app-ansible-variables.png.854fdc16aded20bd59a13395e8e4111e.png" /></p>

<p>هذا الدّرس هو جزء من سلسلة <a href="https://academy.hsoub.com/search/?tags=%D9%86%D8%B4%D8%B1+%D8%AA%D8%B7%D8%A8%D9%8A%D9%82+php+%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85+ansible">دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu</a>، تحدّثنا في الأجزاء الأولى عن الخطوات الأساسيّة لنشر تطبيق، وفي بقيّة الأجزاء تكلمنا عن مواضيع أكثر تقدّمًا مثل <a href="https://academy.hsoub.com/devops/servers/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%86%D8%AF-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r164/">قواعد البيانات</a>، <a href="https://academy.hsoub.com/devops/servers/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AC%D8%AF%D9%88%D9%84%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D8%A7%D9%85-%D8%B9%D9%86%D8%AF-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r165/">عفاريت الطابور queue daemons، وجدولة المهام (عبر cron)</a>.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/php-app-ansible-variables.png.67884fb6afd2575fa8ea367a9b17b98a.png"><img data-fileid="10937" class="ipsImage ipsImage_thumbnailed" alt="php-app-ansible-variables.thumb.png.c9c2" src="https://academy.hsoub.com/uploads/monthly_2016_01/php-app-ansible-variables.thumb.png.c9c2e8d103958a6b345c782f0810dcc0.png"></a></p><p>سنقوم في هذا الدّرس بالبناء على ما تعلمناه في الدروس السابقة عن طريق تحويل الـ playbook في Ansible من دعمها لتطبيق واحد إلى دعمها لنشر تطبيقات PHP متعدّدة على خادوم أو عدّة خواديم، سنتحدث في هذا الجزء عن إعداد المتغيرات، وسنكمل في الجزء اللاحق عن إضافة المزيد من التطبيقات ونشرها.</p><p>سنستخدم تطبيقات <a rel="external nofollow" href="http://lumen.laravel.com/">Lumen</a> بسيطة كجزء أمثلتنا، ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك، من المفضّل أن تستخدم تطبيقات الأمثلة حتى تجد نفسك متآلفًا مع القيام بالتغييرات للـ playbook.</p><h2 id="المتطلبات-الأساسية">المتطلبات الأساسية</h2><p>تحتاج من أجل متابعة الدّرس إلى:</p><ul><li>الخادومين الاثنين اللذين قمنا بإعدادهما في الأجزاء السابقة.</li><li>خادوم Ubuntu جديد (ثالث) يتم إعداده مثل خادوم PHP الأصلي الموجود في الأجزاء السابقة، مع مستخدم sudo غير جذري ومفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>، حيث سنستخدمه لإظهار كيفيّة نشر تطبيقات متعدّدة إلى خواديم متعدّدة باستخدام Ansible Playbook واحدة، سنشير لعناوين IP لخادوم PHP الأصلي وخادوم PHP الجديد بـ <code>your_first_server_ip</code> و <code>your_second_server_ip</code> على الترتيب.</li><li>ملف <span style="font-family:courier new,courier,monospace;">etc/hosts/</span> مُحدَّث على حاسوبك المحلّي مع إضافة الأسطر التالية له، تستطيع تعلّم المزيد حول هذا الملف في <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%B6%D9%8A%D9%81%D8%A7%D8%AA-%D8%A7%D9%84%D8%A7%D9%81%D8%AA%D8%B1%D8%A7%D8%B6%D9%8A%D8%A9-%D9%81%D9%8A-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D9%88%D8%A8-apache-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r10/">الخطوة السادسة من هذا الدّرس</a>.</li></ul><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint" style="text-align: justify;">your_first_server_ip laravel.example.com one.example.com two.example.com
your_second_server_ip laravel.example2.com two.example2.com</pre><p>أمثلة المواقع التي سنستخدمها في هذا الدّرس هي <code>laravel.example.com</code>، <code>one.example.com</code>، و <code>two.example.com</code>، إن أردت استخدام نطاقك الخاص ستحتاج لتحديث <a href="https://academy.hsoub.com/devops/servers/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%AF%D9%85%D8%A9-%D8%A7%D8%B3%D9%85-%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82-dns-%D8%B9%D9%84%D9%89-%D8%AE%D9%88%D8%A7%D8%AF%D9%8A%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r176/">تسجيلات DNS النشطة</a> لديك بدلًا من ذلك.</p><h2 id="الخطوة-الأولى-إعداد-متغيرات-الـ-playbook">الخطوة الأولى – إعداد متغيرات الـ Playbook</h2><p>سنقوم في هذه الخطوة بإعداد متغيّرات الـ playbook لتعريف تطبيقنا الجديد.</p><p>في الدروس السابقة قمنا بكتابة خصائص الإعدادات بشكل حرفي وهو أمر طبيعي بالنسبة للعديد من الـ playbooks التي تقوم بتنفيذ مهام محدّدة من أجل تطبيق محدّد، أمّا عندما نريد دعم عدّة تطبيقات أو توسيع مدى الـ playbook الخاصّة بنا فلن يعود هنالك معنى من كتابة كل شيء حرفيًّا.</p><p>وكما شاهدنا سابقًا تزوّدنا Ansible بمتغيرات نستطيع استخدامها في تعريفات المهام وقوالب الملفّات، ما لم نشاهده حتى الآن هو كيفيّة تعيين المتغيرات، في أعلى الـ playbook بجانب مُعامِلات <code>hosts</code> و<code>tasks</code> نستطيع تعريف مُعامِل <code>vars</code> وتعيين متغيراتنا هناك.</p><p>نقوم بالانتقال إلى الدليل <code>ansible-php</code> الذي تحدثنا عنه في الدّروس السابقة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">cd ~/ansible-php/
</pre><p>نفتح الـ playbook الحاليّة من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>ينبغي أن تبدو بداية الملف كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Top of original php.yml
---
- hosts: php
  sudo: yes

  tasks:
. . .
</pre><p>نستطيع من أجل تعريف المتغيرات إضافة القسم <code>vars</code> فقط، بجانب <code>hosts</code>، <code>sudo</code>، و<code>tasks</code>، ولإبقاء الموضوع بسيط سنبدأ مع متغيّر بسيط جدًّا من أجل المستخدم <code>www-data</code> كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Updated vars in php.yml
---
- hosts: php
  sudo: yes

  vars:
    wwwuser: www-data

  tasks:
. . .
</pre><p>نقوم بعدها بتحديث كافّة المرّات التي ورد فيها المستخدم <code>www-data</code> ونضع بدلًا منها المتغيّر <span style="font-family:courier new,courier,monospace;"><code>{{ wwwuser }}</code></span>.</p><p>نضغط على <code>CTRL+\</code> من أجل البحث والاستبدال باستخدام nano، سنشاهد مُحث prompt يقول:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> Search (to replace):. </pre><p>نكتب <strong><code>www-data</code></strong> ونضغط <code>ENTER</code>، سيتغيّر المُحِث إلى:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> Replace with:</pre><p>نكتب هنا <strong>{{ wwwuser }}</strong> ونضغط <code>ENTER</code> مرّة أخرى، سيأخذنا nano عبر كل مثال من <code>www-data</code> ويسألنا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> Replace this instanace?</pre><p>نستطيع أن نضغط <strong><code>y</code></strong> لاستبدال كل واحدة منها، أو نضغط <strong><code>a</code></strong> لاستبدالها كلّها.</p><p><strong>ملاحظة:</strong> تأكّد من عدم تغيير تعريف المتغير الذي أضفناه للتو في أعلى الملف، يجب أن يكون هنالك 11 مثال من<span style="font-family:courier new,courier,monospace;"> <code>www-data</code></span> نحتاج إلى استبدالها.</p><p>وقبل أن نكمل هنالك شيء نحتاج للانتباه له فيما يتعلّق بالمتغيرات، بإمكاننا بشكل طبيعي إضافتها كما يلي عندما تكون في سطر أطول:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    Example task in php.yml

- name: create /var/www/ directory
  file: dest=/var/www/ state=directory owner={{ wwwuser }} group={{ wwwuser }} mode=0700
</pre><p>ومع ذلك إن كان المتغيّر هو القيمة الوحيدة في السلسلة نحتاج إلى وضعه ضمن علامتي اقتباس كي يستطيع مُحلِّل YAML فهمه بشكل صحيح:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>يجب أن يحدث هذا في الـ playbook في كل مرّة نحصل فيها على:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> sudo_user: {{ wwwuser }}</pre><p>نستطيع استخدام بحث واستبدال عام بنفس الطريقة ووضع:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> sudo_user: "{{ wwwuser }}" </pre><p>بدلًا من:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> sudo_user: {{ wwwuser }}</pre><p>ينبغي وجود أربعة أسطر تحتاج إلى هذا التغيير.</p><p>وبعد أن ننتهي من تغييرها نقوم بحفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>ينبغي ألّا توجد مهام متغيّرة، وهو يعني أنّ المتغيّر <span style="font-family:courier new,courier,monospace;"><code>wwwuser</code></span> يعمل بشكل صحيح.</p><h2 id="الخطوة-الثانية-تعريف-المتغيرات-المتداخلة-من-أجل-الإعدادات-المعقدة">الخطوة الثانية – تعريف المتغيرات المتداخلة من أجل الإعدادات المعقدة</h2><p>سننظر في هذا القسم إلى المتغيّرات المتداخلة من أجل خيارات الإعدادات المعقدة.</p><p>قمنا في الخطوة السابقة بإعداد متغيّر بسيط، ولكن يمكن أيضًا أن نُداخِل بين المتغيّرات وأن نُعرِّف قائمة من المتغيّرات، يزودنا هذا بالوظيفة التي نحتاجها لتعريف قائمة من المواقع التي نرغب بإعدادها على خادومنا.</p><p>دعونا في البداية ننظر إلى مستودع git الحالي الذي قمنا بإعداده في الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Existing git task in php.yml

- name: Clone git repository
  git: &gt;
    dest=/var/www/laravel
    repo=https://github.com/do-community/do-ansible-adv-php.git
    update=yes
    version=example
</pre><p>نستطيع استخراج المعلومات المفيدة التالية: الاسم name (دليل)، المستودع repository، الفرع branch، والنطاق domain، وبما أنّنا نقوم بإعداد تطبيقات متعدّدة سنحتاج أيضًا إلى اسم نطاق من أجله للإجابة عليه، سنستخدم <code>laravel.example.com</code> ولكن إن كنت تملك نطاقك الخاص فضعه هنا.</p><p>ينتج عن هذا المتغيرات الأربعة التالية التي نستطيع تعريفها من أجل هذا التطبيق:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Application variables

name: laravel
repository: https://github.com/do-community/do-ansible-adv-php.git
branch: example
domain: laravel.example.com
</pre><p>نفتح الآن الـ playbook من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نستطيع في القسم العلوي <code>vars</code> إضافة تطبيقنا إلى قائمة التطبيقات الجديدة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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

...
</pre><p>إن قمنا الآن بتشغيل الـ playbook (باستخدام <strong><code>ansible-playbook php.yml --ask-sudo-pass</code></strong>) فلن يتغير شيء لأنّنا لم نقم بعد بإعداد مهامنا لكي تستخدم المتغير <code>applications</code> الجديد، إن ذهبنا إلى <code><a rel="external nofollow" href="http://laravel.example.com/">http://laravel.example.com/</a></code> في متصفحنا فينبغي أن يظهر تطبيقنا الأصلي.</p><h2 id="الخطوة-الثالثة-المرور-على-المتغيرات-عن-طريقة-حلقة-loop-في-المهام">الخطوة الثالثة – المرور على المتغيرات عن طريقة حلقة loop في المهام</h2><p>سنتعلم في هذا القسم كيفيّة المرور على قوائم المتغيرات عبر حلقة loop في المهام.</p><p>كما أشرنا سابقًا تحتاج قوائم المتغيرات المرور عليها عبر حلقة في كل مهمة نرغب في استخدامها فيها، وكما شاهدنا مع المهمّة <code>install packages</code> نحتاج إلى تعريف حلقة من العناصر ومن ثمّ تطبيق المهمّة لكل عنصر في القائمة.</p><p>نفتح الـ playbook من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>سنبدأ ببعض المهام السهلة، ينبغي أن نجد مهمتي env في منتصف الـ playbook تقريبًا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">               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
</pre><p>نلاحظ أنّها مكتوبة الآن بشكل حرفي مع الدليل <code>laravel</code>، نحتاج إلى تحديثها لكي تستخدم الخاصية <code>name</code> لكل تطبيق، ولفعل هذا نضيف الخيار <code>with_items</code> كي يمر على شكل حلقة خلال قائمة <code>applications</code> لدينا، وضمن المهمّة نفسها سنبدل المرجع <code>laravel</code> بالمتغير<span style="font-family:courier new,courier,monospace;"> <code>{{ item.name }}</code></span>.</p><p>ينبغي أن تبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>ننتقل بعدها إلى الأسفل إلى مهمتي Laravel cron، يمكن تحديثهما كما فعلنا تمامًا مع مهام <code>env</code>، سنقوم بإضافة <code>item.name</code> إلى المُعامِل <code>name</code> من أجل مُدخلات لأنّ Ansible تستخدم هذا الحقل لتعرّف بشكل فريد كل مُدخل cron، إن تركناها كما هي فلن نكون قادرين على الحصول على مواقع متعددة على نفس الخادوم لأنّها ستكتب فوق بعضها بشكل ثابت وسيتم حفظ القيمة الأخيرة فقط.</p><p>ينبغي أن تبدو المهمة كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                   Updated cron tasks in php.yml

- name: Laravel Scheduler
  cron: &gt;
    job="run-one php /var/www/{{ item.name }}/artisan schedule:run 1&gt;&gt; /dev/null 2&gt;&amp;1"
    state=present
    user={{ wwwuser }}
    name="{{ item.name }} php artisan schedule:run"
  with_items: applications

- name: Laravel Queue Worker
  cron: &gt;
    job="run-one php /var/www/{{ item.name }}/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1&gt;&gt; /dev/null 2&gt;&amp;1"
    state=present
    user={{ wwwuser }}
    name="{{ item.name }} Laravel Queue Worker"
  with_items: applications
</pre><p>إن قمنا بحفظ وتشغيل الـ playbook الآن (باستخدام <strong><code>ansible-playbook php.yml --ask-sudo-pass</code></strong>) فيجب أن نرى أنّه فقط تم تحديث مهمّتي cron، وهذا بسبب التغيير في المُعامِل name، ولا توجد أيّة تغييرات عدا عن ذلك، وهذا يعني أنّ قائمة تطبيقاتنا تعمل كما هو متوقع، ولم نقم بأيّة تغييرات إلى خادومنا كنتيجة لإعادة تصنيع الـ playbook لدينا.</p><h2 id="الخطوة-الرابعة-تطبيق-المتغيرات-من-الحلقة-looped-variables-في-قوالب-templates">الخطوة الرابعة – تطبيق المتغيرات من الحلقة looped variables في قوالب templates</h2><p>سنغطي في هذا القسم كيفيّة استخدام المتغيرات من الحلقة في القوالب.</p><p>نستطيع استخدام هذه المتغيرات بنفس الطريقة تمامًا التي استخدمناها في المهام، كما هو الحال مع جميع المتغيرات الأخرى، تأتي الصعوبة عندما نأخذ بعين الاعتبار مسارات الملفات بالإضافة للمتغيرات، لأنّنا سنحتاج في بعض الأحيان إلى أخذ اسم الملف بعين الاعتبار وحتى تنفيذ أوامر أخرى بسبب الملف الجديد.</p><p>نحتاج في حالة Nginx إلى إنشاء ملف إعدادات جديد لكل تطبيق وإخبار Nginx أنّه ينبغي تمكينها، نريد أيضًا إزالة ملف إعداداتنا الافتراضي:</p><p><span style="font-family:courier new,courier,monospace;"> <code>etc/nginx/sites-available/default</code><span style="line-height: 22.4px;">/</span></span> خلال العمليّة.</p><p>نفتح في البداية الـ playbook من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نقوم بإيجاد المهمة <code>Configure Nginx</code> (قرب منتصف الـ playbook) وتحديثها كما فعلنا مع المهام الأخرى:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>وبينما نحن هنا نقوم بإضافة المهمتين الإضافيتين اللتين أشرنا لهما سابقًا، نخبر Nginx في البداية حول ملف إعدادات الموقع الجديد، يتم فعل هذا باستخدام بارتباط رمزي بين أدلة <code>sites-available</code> و <code>sites-enabled</code> في <span style="font-family:courier new,courier,monospace;"><code>/var/nginx/</code></span>.</p><p>نضيف هذه المهمة بعد المهمة Configure nginx:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نرغب بعدها في إزالة ملف إعدادات الموقع المُمكّن افتراضيًّا default كي لا يسبب مشاكل مع ملفّات إعدادات موقعنا الجديد، يتم عمل هذا بسهولة باستخدام الوحدة file:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>لاحظ أنّنا لم نحتاج إلى وضع applications في حلقة لأنّنا كنّا نبحث عن ملف واحد.</p><p>يجب أن تبدو كتلة Nginx في الـ playbook كما يلي الآن:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نحفظ الـ playbook ونفتح الملف nginx.conf من أجل تحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano nginx.conf
</pre><p>نقوم بتحديث ملف الإعدادات بحيث يستخدم متغيراتنا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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;
    }
}
</pre><p>مع ذلك لم نقم بالانتهاء بعد، أتلاحظ <code>default_server</code> في الأعلى؟ نريد تضمينها فقط من أجل تطبيق <code>laravel</code> لجعله التطبيق الافتراضي، لعمل هذا نستطيع استخدام جملة <code>IF</code> بسيطة لنتحقّق إذا ما كان <code>item.name</code> يساوي <code>laravel</code> وإن كان كذلك نعرض <code>default_server</code>.</p><p>ستبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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 %};
</pre><p>نحدّث <span style="font-family:courier new,courier,monospace;">nginx.conf</span> وفقًا لذلك ونحفظه.</p><p>حان الوقت الآن لتشغيل الـ playbook لدينا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>يجب أن تلاحظ أنّه تم تعليم مهام Nginx بأنّها تغيرت، عند الانتهاء من تشغيل الـ playbook نحدّث الموقع في متصفحنا ويجب أن يعرض ما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">            http://laravel.example.com/

Queue: YES
Cron: YES
</pre><h2 id="الخطوة-الخامسة-وضع-متغيرات-متعددة-في-حلقة-معا">الخطوة الخامسة – وضع متغيرات متعددة في حلقة معا</h2><p>سنقوم في هذه الخطوة بوضع متغيّرات متعدّدة معًا في مهمّة.</p><p>حان الوقت الآن لمعالجة مثال حلقات أكثر تعقيدًا، خصوصًا المتغيّرات المُسجّلَة، من أجل دعم حالات مختلفة ومنع تشغيل مهام غير ضرورية، تتذكر أنّنا استخدمنا <code>register: cloned</code> في مهمّة استنساخ مستودع git لتسجيل المتغير <code>cloned</code> مع حالة المهمّة، نستخدم بعدها <code>when: cloned|changed</code> في المهام التالية لتحفيز المهام بشكل شرطي، نحتاج الآن إلى تحديث هذه المراجع لتدعم حلقة التطبيقات.</p><p>نفتح أوّلًا الـ playbook من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نبحث عن المهمّة Clone git repository:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">               Existing git task in php.yml

- name: Clone git repository
  git: &gt;
    dest=/var/www/laravel
    repo=<a rel="external nofollow" href="https://github.com/do-community/do-ansible-adv-php.git">https://github.com/do-community/do-ansible-adv-php.git</a>
    update=yes
    version=example
  sudo: yes
  sudo_user: "{{ wwwuser }}"
  register: cloned
</pre><p>وبما أنّنا نقوم بتسجيل المتغيرات في هذه المهمة فلن نحتاج إلى فعل أي شيء لم نفعله سابقًا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Updated git task in php.yml

- name: Clone git repository
  git: &gt;
    dest=/var/www/{{ item.name }}
    repo={{ item.repository }}
    update=yes
    version={{ item.branch }}
  sudo: yes
  sudo_user: "{{ wwwuser }}"
  with_items: applications
  register: cloned
</pre><p>نبحث الآن عن المهمة<strong> composer create-project</strong>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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
</pre><p>نحتاج الآن إلى تحديثها للمرور عبر حلقة على <code>applications</code> و <code>cloned</code>، يتم فعل هذا باستخدام الخيار <code>with_together</code> وتمرير <code>applications</code> و<code>cloned</code> إليها، وبينما تقوم <code>with_together</code> بالمرور عبر حلقة على المتغيرين فيتم الصول إلى العناصر باستخدام <code>item.#</code>، حيث أنّ <code>#</code> هي فهرس المتغير، فعلى سبيل المثال:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">with_together:
- list_one
- list_two
</pre><p>يشير item.0 إلى<span style="font-family:courier new,courier,monospace;"> list_one</span> ويشير item.1 إلى<span style="font-family:courier new,courier,monospace;"> list_two</span>.</p><p>يعني هذا أنّنا نستطيع من أجل <code>applications</code> نستطيع الوصول إلى الخصائص عبر: <span style="font-family:courier new,courier,monospace;"><code>item.0.name</code></span>، نحتاج من أجل <code>cloned</code> إلى تمرير النتائج من المهام والتي يمكن الوصول إليها عبر <code>cloned.results</code> ومن ثمّ نستطيع التحقّق إن تم تغييرها من خلال <code>item.1.changed</code>.</p><p>يعني هذا أنّ المهمة ستصبح:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نقوم الآن بحفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>ينبغي ألّا تحدث أيّة تغييرات من هذا التشغيل، ومع ذلك نمتلك الآن متغيرًا مُسجّلًا يعمل بشكل رائع مع حلقة.</p><h2 id="الخطوة-السادسة-المتغيرات-المسجلة-المعقدة-والحلقات">الخطوة السادسة – المتغيرات المسجلة المعقدة والحلقات</h2><p>سنتعلم في هذا القسم حول المزيد من المتغيرات المسجلة المعقدة والحلقات.</p><p>الجزء الأكثر تعقيدًا من التحويل هو مُداولة handling المتغير المسجّل الذي نستخدمه من أجل توليد كلمة السر لقاعدة بيانات MySQL، ولا يوجد أكثر مما فعلناه في هذه الخطوة لم نقم بتغطيته، نحتاج فقط إلى تحديث عدد من المهام في وقت واحد.</p><p>نفتح الـ playbook من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نبحث عن مهام MySQL ونقوم بإضافة المتغيرات البسيطة كما فعلنا في المهمة السابقة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>نضيف بعدها <code>with_together</code> كي نستطيع استخدام كلمة سر قاعدة بياناتنا، ومن أجل توليد كلمة السر نحتاج إلى المرور بحلقة خلال <code>dbpwd.results</code> وسنكون قادرين على الوصول لكلمة السر من <code>item.1.stdout</code> بما أنّه سيتم الوصول لـ <code>applications</code> عبر <code>item.0</code>.</p><p>نستطيع تحديث الـ playbook وفق ذلك:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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
</pre><p>بعد أن يتم تحديثها نقوم بحفظها وتشغيلها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>بالرغم من جميع التغييرات التي قمنا بها على الـ playbook فلا يجب أن يكون هنالك تغييرات في مهام قاعدة البيانات، ومع التغييرات في هذه الخطوة نكون قد انتهينا من التحويل من playbook تدعم تطبيق وحيد إلى playbook تدعم تطبيقات متعددة.</p><h2 id="الخاتمة">الخاتمة</h2><p>تحدثنا في هذا الجزء عن إعداد المتغيرات، وسنكمل في الجزء اللاحق عن <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-php-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%B9%D9%84%D9%89-ubuntu-r167/">إضافة المزيد من التطبيقات ونشرها إلى خادوم آخر</a>.</p><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-deploy-multiple-php-applications-using-ansible-on-ubuntu-14-04">How To Deploy Multiple PHP Applications using Ansible on Ubuntu 14.04</a> لصاحبه Stephen Rees-Carter.</p>
]]></description><guid isPermaLink="false">166</guid><pubDate>Fri, 08 Jan 2016 13:04:00 +0000</pubDate></item><item><title>&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x62C;&#x62F;&#x648;&#x644;&#x629; &#x627;&#x644;&#x645;&#x647;&#x627;&#x645; &#x639;&#x646;&#x62F; &#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; PHP &#x645;&#x62A;&#x639;&#x62F;&#x62F;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ansible</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AC%D8%AF%D9%88%D9%84%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D8%A7%D9%85-%D8%B9%D9%86%D8%AF-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-php-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r165/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_01/php-ansible-cron.png.08d61c1dc478033e46eab271192e6b1a.png" /></p>

<p>هذا الدّرس هو جزء من <a href="https://academy.hsoub.com/search/?tags=%D9%86%D8%B4%D8%B1+%D8%AA%D8%B7%D8%A8%D9%8A%D9%82+php+%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85+ansible">سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu</a>، تحدّثنا في أول أجزاء عن الخطوات الأساسيّة من أجل نشر تطبيق، وهي تشكل نقطة بداية من أجل الخطوات المذكورة في هذا الدّرس.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/php-ansible-cron.png.a9055cab3411d29ab91be2f67a39bb9f.png"><img data-fileid="10716" class="ipsImage ipsImage_thumbnailed" alt="php-ansible-cron.thumb.png.ac23c677f7a33" src="https://academy.hsoub.com/uploads/monthly_2016_01/php-ansible-cron.thumb.png.ac23c677f7a33aae65cccab37a49e3fe.png"></a></p><p>سنغطّي في هذا الدّرس إعداد جدولة المهام (crons) وعفاريت الطابور queue daemons، هدفنا في النهاية هو الحصول على خادوم يعمل عليه تطبيق PHP بشكل كامل مع الإعدادات المذكورة آنفًا.</p><p>سنستخدم <a rel="external nofollow" href="https://github.com/laravel/laravel">إطار عمل Laravel</a> كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك.</p><h2 id="الخطوة-الأولى-إعداد-مهام-cron">الخطوة الأولى – إعداد مهام cron</h2><p>سنقوم في هذه الخطوة بإعداد أي مهمّة cron نحتاج لإعدادها.</p><p>إنّ مهام cron هي عبارة عن أوامر تعمل وفق جدول schedule مُحدَّد ويمكن استخدامها لإنجاز أي عدد من المهام من أجل تطبيقنا، كالقيام بمهام الصيانة أو إرسال تحديثات نشاط البريد الإلكتروني – بشكل أساسي أي شيء نحتاج عمله بشكل دوري بدون تدخل المستخدم يدويًّا، يمكن تشغيل مهام cron بتواتر كل دقيقة أو بشكل غير منتظم كما نريد.</p><p>يأتي Laravel بشكل افتراضي مع أمر حرفي يُدعى <code>schedule:run</code>، وهو مُصمَّم ليعمل كل دقيقة وينفذ المهام المجدولة المُعرَّفة ضمن التطبيق، يعني هذا أنّنا نحتاج فقط لإضافة مهمّة cron واحدة إن كان تطبيقنا يستفيد من هذه الميّزة.</p><p>تمتلك Ansible وحدة <code>cron</code> مع العديد من الخيارات المختلفة والتي تُترجَم مباشرة إلى خيارات مختلفة نستطيع إعدادها عبر cron:</p><ul><li><strong><code>job</code>:</strong> الأمر الذي نريد تنفيذه، مطلوب إن كانت <code>state=present</code>.</li><li><strong><code>minute</code>، <code>hour</code>، <code>day</code>، <code>weekday</code>:</strong> الدقيقة، الساعة، اليوم، الشهر، أو اليوم من أيام الأسبوع الذي يجب فيه تشغيل الوظيفة، على الترتيب.</li><li><strong><code>special_time</code> </strong>أوقات خاصّة<strong> (<code>reboot</code>، <code>yearly</code>، <code>annually</code>، <code>monthly</code>، <code>weekly</code>، <code>daily</code>، <code>hourly</code>):</strong> وقت خاص مُحدَّد بكنية nickname.</li></ul><p>سيقوم افتراضيًّا بإنشاء مهمّة تعمل كل دقيقة، وهو ما نريده، وهذا يعني أنّ المهمّة التي نريدها تبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                New Ansible task

- name: Laravel Scheduler
  cron: &gt;
    job="run-one php /var/www/laravel/artisan schedule:run 1&gt;&gt; /dev/null 2&gt;&amp;1"
    state=present
    user=www-data
    name="php artisan schedule:run"
</pre><p>إنّ الأمر <code>run-one</code> هو مساعد صغير في Ubuntu يضمن أن يعمل الأمر فقط مرّة واحدة، وهذا يعني أنّه إن كان أمر <code>schedule:run</code> سابق لا يزال قيد التشغيل فلن يتم تشغيله مرّة أخرى، وهذا مفيد لتجنّب حالة تصبح فيها مهمّة cron مقفولة ضمن حلقة، ومع الوقت سيتم تشغيل المزيد من النُسَخ لنفس المهمّة حتى تنفذ موارد الخادوم.</p><p>نفتح الملف <code>php.yml</code> لتحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف المهمّة السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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: &gt;
      job="run-one php /var/www/laravel/artisan schedule:run 1&gt;&gt; /dev/null 2&gt;&amp;1"
      state=present
      user=www-data
      name="php artisan schedule:run"

  handlers:

. . .
</pre><p>نقوم بحفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>نحدّث الآن الصفحة في متصفحنا، وخلال دقيقة سيتم التحديث وستبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">            your_server_ip/'&gt;http://your_server_ip/

Queue: NO
Cron: YES
</pre><p>يعني هذا أنّ cron تعمل في الخلفية بشكل صحيح، وكجزء من تطبيق المثال هنالك وظيفة cron تعمل كل دقيقة وتقوم بتحديث مُدخَل الحالة في قاعدة البيانات كي يعلم التطبيق أنّها تعمل.</p><h2 id="الخطوة-الثانية-إعداد-عفريت-الطابور-queue-daemon">الخطوة الثانية – إعداد عفريت الطابور Queue Daemon</h2><p>وكما في حالة الأمر الحرفي <code>schedule:run</code> من الخطوة السابقة، يأتي Laravel مع عامل للطابور يُمكِن تشغيله بالأمر الحرفي <code>queue:work --daemon</code>، سنقوم في هذه الخطوة بإعداد عامل عفريت (بالإنجليزية Daemon وهو برنامج يعمل في خلفيّة النظام) الطابور queue daemon worker من أجل Laravel.</p><p>يتشابه عمّال الطابور مع وظائف cron في أنّها تقوم بتشغيل المهام في الخلفيّة، ويكمن الفرق في دفع التطبيق للوظائف إلى الطابور، إمّا عبر إجراءات يتم تنفيذها من قبل المستخدم أو من خلال مهام مُجدوَلة عبر وظائف cron، يتم تنفيذ مهام الطابور من قِبَل العامل في وقت واحد، ويتم معالجتها بحسب الطلب عندما يتم العثور عليها في الطابور، تُستخدَم مهام الطابور بشكل شائع من أجل العمل الذي يستغرق وقتًا لتنفيذه، كإرسال رسائل البريد الإلكتروني أو القيام باستدعاءات لواجهة <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> للخدمات الخارجيّة.</p><p>وعلى عكس الأمر <code>schedule:run</code> فإنّ هذا الأمر لا يحتاج أن يتم تشغيله كل دقيقة، بل يحتاج بدلًا من ذلك أن يعمل كعفريت daemon في الخلفيّة بشكل ثابت، ومن الطرق الشائعة لفعل هذا هي استخدام حزمة طرف ثالث third-party تُدعى supervisord، ولكن تتطلّب هذه الطريقة فهم كيفيّة إعداد وإدارة النظام المذكور، وهنالك طريقة أسهل لتنفيذها باستخدام cron والأمر <code>run-one</code>.</p><p>سنقوم بإنشاء مُدخَل cron لبدء عفريت عامل الطابور ونستخدم الأمر <code>run-one</code> لتشغيله، ويعني هذا أن يقوم cron بتشغيل العمليّة في أوّل مرة تعمل فيها، وسيتم تجاهل أي تشغيلات cron لاحقة للأمر عن طريق <code>run-one</code> أثناء تشغيل العامل، وحالما يتوقّف العامل سيسمح <code>run-one</code> للأمر بأن يعمل مرّة أخرى، وسيبدأ عامل الطابور عمله مرّة أخرى، وهي طريقة بسيطة وسهلة الاستخدام بشكل لا يصدّق توفّر علينا الحاجة لتعلّم كيفيّة إعداد واستخدام أداة أخرى.</p><p>وبأخذ كل ذلك بعين الاعتبار سنقوم بإنشاء مهمّة cron أخرى لتشغيل عامل الطابور لدينا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                New Ansible task

- name: Laravel Queue Worker
  cron: &gt;
    job="run-one php /var/www/laravel/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1&gt;&gt; /dev/null 2&gt;&amp;1"
    state=present
    user=www-data
    name="Laravel Queue Worker"
</pre><p>نفتح الملف <code>php.yml</code> من أجل تحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف المهمّة السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    Updated php.yml

. . .

  - name: Laravel Scheduler
    cron: &gt;
      job="run-one php /var/www/laravel/artisan schedule:run 1&gt;&gt; /dev/null 2&gt;&amp;1"
      state=present
      user=www-data
      name="php artisan schedule:run"

  - name: Laravel Queue Worker
    cron: &gt;
      job="run-one php /var/www/laravel/artisan queue:work --daemon --sleep=30 --delay=60 --tries=3 1&gt;&gt; /dev/null 2&gt;&amp;1"
      state=present
      user=www-data
      name="Laravel Queue Worker"

  handlers:
. . .
</pre><p>نقوم بحفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>نحدّث الصفحة في متصفحنا، وسيتم بعد دقيقة تحديثها لتبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">            your_server_ip/'&gt;<a rel="external nofollow" href="http://your">http://your_server_ip/</a>
Queue: YES
Cron: YES
</pre><p>يعني هذا أنّ عامل الطابور يعمل في الخلفيّة بشكل صحيح، تقوم وظيفة cron التي بدأنا بها في الخطوة السابقة بدفع الوظيفة إلى الطابور، تحدّث هذه الوظيفة قاعدة البيانات عند تشغيلها لتظهر بأنّها تعمل.</p><p>نمتلك الآن مثال يعمل لتطبيق Laravel يتضمّن وظائف cron وعمّال طوابير.</p><h2 id="الخاتمة">الخاتمة</h2><p>لقد قمنا في هذا الدّرس بتغطية بعض أكثر المواضيع تقدمًا عند استخدام Ansible من أجل نشر تطبيقات PHP، يمكن تعديل كافّة المهام المستخدمة بسهولة لتتلاءم مع معظم تطبيقات PHP (بحسب متطلباتها الخاصّة)، ويجب أن تشكّل لك نقطة انطلاق جيّدة لإعداد playbook الخاصّة بك من أجل تطبيقاتك.</p><p>لم نستخدم أي أمر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> كجزء من هذا الدّرس (باستثناء التحقّق من تسجيل دخول المستخدم <code>www-data</code>)، وتم إعداد كل شيء تلقائيًّا بما في ذلك كلمة سر مستخدم MySQL، بعد متابعتك لهذا الدّرس أصبح تطبيقك جاهزًا للانطلاق ودعم أدوات لدفع تحديثات الشيفرة.</p><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-deploy-an-advanced-php-application-using-ansible-on-ubuntu-14-04">How To Deploy an Advanced PHP Application Using Ansible on Ubuntu 14.04</a> لصاحبه Stephen Rees-Carter.</p>
]]></description><guid isPermaLink="false">165</guid><pubDate>Sun, 03 Jan 2016 22:08:00 +0000</pubDate></item><item><title>&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x642;&#x627;&#x639;&#x62F;&#x629; &#x627;&#x644;&#x628;&#x64A;&#x627;&#x646;&#x627;&#x62A; &#x639;&#x646;&#x62F; &#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; PHP &#x645;&#x62A;&#x639;&#x62F;&#x62F;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ansible</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%B9%D9%86%D8%AF-%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-php-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-r164/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_01/ansible-php-4.png.a5c3579c43a9eb9ebbfe523ac82fa13b.png" /></p>

<p>هذا الدّرس هو جزء من <a href="https://academy.hsoub.com/search/?tags=%D9%86%D8%B4%D8%B1+%D8%AA%D8%B7%D8%A8%D9%8A%D9%82+php+%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85+ansible">سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu</a>، تحدّثنا في أول أجزاء عن الخطوات الأساسيّة من أجل نشر تطبيق، وهي تشكل نقطة بداية من أجل الخطوات المذكورة في هذا الدّرس.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/ansible-php-4.png.fc03172c62e9ff6c1c4fe83ab3b2cee2.png"><img data-fileid="10607" class="ipsImage ipsImage_thumbnailed" alt="ansible-php-4.thumb.png.8be2dc8879f48b48" src="https://academy.hsoub.com/uploads/monthly_2016_01/ansible-php-4.thumb.png.8be2dc8879f48b48ffbbedaf573929fe.png"></a></p><p>سنغطّي في هذا الدّرس إعداد قاعدة البيانات (بما في ذلك كلمة السّر)، هدفنا في النهاية هو الحصول على خادوم يعمل عليه تطبيق PHP بشكل كامل مع الإعدادات المذكورة آنفًا.</p><p>سنستخدم <a rel="external nofollow" href="https://github.com/laravel/laravel">إطار عمل Laravel</a> كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك.</p><h2 id="الخطوة-الأولى-تثبيت-حزم-mysql">الخطوة الأولى – تثبيت حزم MySQL</h2><p>سنقوم في هذه الخطوة بإعداد قاعدة بيانات MySQL لكي يستخدمها تطبيقنا.</p><p>إنّ الخطوة الأولى لضمان وجود MySQL مُثبّتة على خادومنا هي ببساطة إضافة الحِزَم المطلوبة إلى مهمّة تثبيت الحِزَم في أعلى الـ playbook لدينا، الحزم التي نحتاجها هي <code>mysql-server</code>، <code>mysql-client</code>، و<code>php5-mysql</code>، سنحتاج أيضًا إلى <code>python-mysqldb</code> كي تستطيع Ansible التواصل مع MySQL.</p><p>وبما أنّنا نضيف حِزَم فنحتاج إلى إعادة تشغيل <code>nginx</code> و <span style="font-family:courier new,courier,monospace;"><code>php5-fpm</code></span> لضمان قابلية استخدام الحِزَم الجديدة من قبل التطبيق، نحتاج في هذه الحالة أن تكون MySQL متوفرة من أجل PHP لكي تستطيع الاتصال إلى قاعدة البيانات.</p><p>من الأشياء الرائعة حول Ansible هي أنّنا نستطيع تعديل أي مهمّة من المهام وإعادة تشغيل الـ playbook وسيتم حينها تطبيق التغييرات، يتضمّن هذا قوائم من الخيارات كما نملك مع مهمّة <code>apt</code>.</p><p>نفتح الملف <code>php.yml</code> من أجل تحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نبحث عن المهمّة <code>install packages</code> ونحدّثها لتضم الحِزَم السابقة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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

. . .
</pre><p>نقوم بحفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><h2 id="الخطوة-الثانية-إعداد-قاعدة-بيانات-mysql">الخطوة الثانية – إعداد قاعدة بيانات MySQL</h2><p>سنقوم في هذه الخطوة بإنشاء قاعدة بيانات MySQL من أجل تطبيقنا.</p><p>تستطيع Ansible التخاطب مباشرة مع MySQL باستخدام الوحدات المسبوقة بـ <code>mysql_</code> (مثل <code>mysql_db</code>، <code>mysql_user</code>)، تزودنا الوحدة <code>mysql_db</code> بطريقة لضمان وجود قاعدة بيانات ذات اسم مُحدّد بحيث نستطيع استخدام مهمّة مثل هذه لإنشاء قاعدة البيانات:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                New Ansible task

- name: Create MySQL DB
  mysql_db: name=laravel state=present
</pre><p>نحتاج أيضًا إلى حساب مستخدم صحيح مع كلمة سر معروفة للسماح لتطبيقنا بالاتصال إلى قاعدة البيانات، إحدى الوسائل لتحقيق هذا هي توليد كلمة السر محليًّا وحفظها في playbook الخاصّة بـ Ansible، ولكنّ هذه الطريقة غير آمنة وتوجد وسيلة أفضل منها.</p><p>سنقوم بتوليد كلمة السّر باستخدام Ansible على الخادوم ذاته واستخدامها مباشرة عند الحاجة، ولتوليد كلمة سر سنستخدم أداة الأوامر السطرية <code>makepasswd</code> ونطلب منها كلمة سر مكوّنة من 32 حرف، ولأنّ <code>makepasswd</code> لا تأتي بشكل افتراضي مع Ubuntu سنحتاج إلى إضافتها إلى قائمة الحِزَم أيضًا.</p><p>سنخبر أيضًا Ansible أن تتذكر خَرْج output هذا الأمر (أي تتذكر كلمة السّر) حتى نستطيع استخدامها لاحقًا في الـ playbook الخاصّة بنا، ومع ذلك ولأنّ Ansible لا تعلم إذا ما كان قد تم تنفيذ الأمر <code>shell</code> فسنقوم بإنشاء ملف عند تنفيذ هذا الأمر، ستتحقّق Ansible من وجود الملف وإن وجدته فستفترض أنّه تمّ تشغيل ذلك الأمر ولن يتم تشغيله مرّة أخرى.</p><p>تبدو المهمّة كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                New Ansible task

- name: Generate DB password
  shell: makepasswd --chars=32
  args:
    creates: /var/www/laravel/.dbpw
  register: dbpwd
</pre><p>نحتاج بعدها لإنشاء مستخدم قاعدة بيانات MySQL الفعلي مع كلمة السّر التي حدّدناها، يتم عمل ذلك باستخدام الوحدة <code>mysql_user</code> ونستطيع استخدام الخيار <code>stdout</code> على المتغيّر الذي عرّفناه خلال مهمّة توليد كلمة السّر للحصول على الخَرْج الخام لأمر الصدفة shell، مثل هذا: <code>dbpwd.stdout</code>.</p><p>يقبل الأمر <code>mysql_user</code> اسم المستخدم والصلاحيّات المطلوبة، نريد في حالتنا إنشاء مستخدم يُدعى <code>laravel</code> وإعطاء هذا المستخدم صلاحيّات كاملة على الجدول <code>laravel</code>، نحتاج أيضًا إلى إخبار المهمّة أن يتم تشغيلها فقط عندما يتم تغيير المتغيّر <code>dbpwd</code>، والذي سيحدث فقط عند تشغيل مهمّة توليد كلمة السّر.</p><p>يجب أن تبدو المهمّة كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    New Ansible task

- name: Create MySQL User
  mysql_user: name=laravel password={{ dbpwd.stdout }} priv=laravel.*:ALL state=present
  when: dbpwd.changed
</pre><p>وبوضع كل ذلك معًا نفتح الملف <code>php.yml</code> من أجل تحريره كي نستطيع إضافة المهمّة السابقة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نبحث في البداية عن المهمّة <code>install packages</code> ونقوم بتحديثها لتتضمّن الحزمة <code>makepasswd</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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

. . .
</pre><p>نضيف بعدها مهام توليد كلمة السّر، إنشاء قاعدة بيانات MySQL، وإنشاء مستخدم في نهاية الملف:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Updated php.yml

. . .

  - name: UFW limit &lt;abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"&gt;SSH&lt;/abbr&gt;
    ufw: rule=limit port=&lt;abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"&gt;ssh&lt;/abbr&gt;

  - 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:

. . .
</pre><p><strong>لا تقم بتشغيل الـ playbook الآن</strong>، ربّما تكون قد لاحظت أنّه بالرغم من أنّنا أنشأنا مستخدم وقاعدة بيانات MySQL فلم نفعل أي شيء مع كلمة السّر، سنغطّي هذا الموضوع في الخطوة القادمة، عند استخدام مهام <code>shell</code> ضمن Ansible فمن المهم دومًا أن نتذكّر متابعة سير العمل الذي يتعلّق بخَرْج ونتائج المهمّة بأكمله قبل تشغيلها لنتجنّب الاضطرار إلى تسجيل الدخول يدويًّا وإعادة تعيين الحالة.</p><h2 id="الخطوة-الثالثة-إعداد-تطبيق-php-من-أجل-قاعدة-البيانات">الخطوة الثالثة – إعداد تطبيق PHP من أجل قاعدة البيانات</h2><p>سنقوم في هذه الخطوة بحفظ كلمة سر قاعدة بيانات MySQL في الملف <code>.env</code> من أجل التطبيق.</p><p>سنحدّث الملف <code>.env</code> ليتضمن اعتمادات (credentials) قاعدة بياناتنا التي أنشأناها حديثًا، يحتوي ملف <code>.env</code> الخاص بـ Laravel الأسطر التالية بشكل افتراضي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                Laravel .env file

DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
</pre><p>نستطيع الإبقاء على السطر <code>DB_HOST</code> كما هو، ولكن سنحدّث الأسطر الثلاثة الأخرى باستخدام المهام التالية، وهي مشابهة جدًّا للمهام التي استخدمناها في الدّرس السابق من أجل تعيين <code>APP_ENV</code> و <code>APP_DEBUG</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
</pre><p>وكما فعلنا مع مهمّة إنشاء مستخدم MySQL فقد استخدمنا متغيّر كلمة السر التي تمّ توليدها (<code>dbpwd.stdout</code>) لنشر الملف مع كلمة السّر، وأضفنا الخيار <code>when</code> لضمان أن يتم تشغيلها فقط عند تغيير <code>dbpwd</code>.</p><p>وبما أنّ الملف <code>.env</code> موجود مسبقًا قبل إضافة مهمّة توليد كلمة السّر، فسنحتاج إلى حفظ كلمة السّر إلى ملف آخر، تبحث مهمّة توليد كلمة السّر عن وجود الملف (والذي أعددناه مسبقًا ضمن المهمّة)، سنستخدم أيضًا الخيارات <code>sudo</code> و<code>sudo_user</code> لإخبار Ansible أن يقوم بإنشاء الملف عن طريق المستخدم <code>www-data</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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
</pre><p>نفتح الملف <code>php.yml</code> من أجل تحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف المهام السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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:

. . .
</pre><p><strong>لا تقم بتشغيل الـ playbook الآن</strong>، فقد بقيت لدينا خطوة واحدة يجب إكمالها قبل أن نتمكّن من تشغيل الـ playbook.</p><h2 id="الخطوة-الرابعة-تهجير-قاعدة-البيانات-migrating-the-database">الخطوة الرابعة – تهجير قاعدة البيانات Migrating the Database</h2><p>سنقوم في هذه الخطوة بتنفيذ تهجير قاعدة البيانات database migrations من أجل إعداد جداول قاعدة البيانات.</p><p>يتم فعل هذا في Laravel عن طريق تنفيذ الأمر <code>migrate</code> (على سبيل المثال <code>php artisan migrate --force</code>) بداخل دليل Laravel، لاحظ أنّنا أضفنا العَلَم <code>force--</code> لأنّ بيئة <code>production</code> تحتاجه.</p><p>تبدو مهمّة Ansible للقيام بهذا كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                New Ansible task

  - name: Run artisan migrate
    shell: php /var/www/laravel/artisan migrate --force
    sudo: yes
    sudo_user: www-data
    when: dbpwd.changed
</pre><p>حان الوقت الآن لتحديث playbook الخاصّة بنا، نفتح الملف <code>php.yml</code> لتحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف المهام السابقة إلى الـ playbook، يجب أن تتطابق نهاية الملف مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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:

. . .
</pre><p>بإمكاننا أخيرًا حفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>عند الانتهاء من تنفيذ هذا نقوم بتحديث الصفحة في متصفحنا ويجب أن نرى عندها رسالة تقول:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                your_server_ip/'&gt;<a rel="external nofollow" href="http://your">http://your</a>_server_ip/

Queue: NO
Cron: NO
</pre><p>يعني هذا أنّ تم إعداد قاعدة البيانات بشكل صحيح وأنّها تعمل كما هو متوقع، ولكنّنا لم نقم حتى الآن بإعداد مهام cron أو عفريت الطابور queue daemon، والتي سنقوم بها في الدرس القادم.</p><h2 id="الخاتمة">الخاتمة</h2><p>تحدّثنا في هذا الدّرس عن طريقة إعداد قاعدة بيانات MySQL وإعداد تطبيق PHP من أجلها ومن ثمّ تهجير قاعدة البيانات من أجل نشر تطبيق PHP متقدّم باستخدام Ansible.</p><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-deploy-an-advanced-php-application-using-ansible-on-ubuntu-14-04">How To Deploy an Advanced PHP Application Using Ansible on Ubuntu 14.04</a> لصاحبه Stephen Rees-Carter.</p>
]]></description><guid isPermaLink="false">164</guid><pubDate>Fri, 01 Jan 2016 21:48:00 +0000</pubDate></item><item><title>&#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642; PHP &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ansible - &#x625;&#x639;&#x62F;&#x627;&#x62F; &#x645;&#x641;&#x627;&#x62A;&#x64A;&#x62D; SSH &#x648;&#x627;&#x644;&#x62C;&#x62F;&#x627;&#x631; &#x627;&#x644;&#x646;&#x627;&#x631;&#x64A;</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD-ssh-%D9%88%D8%A7%D9%84%D8%AC%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%A7%D8%B1%D9%8A-r163/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php-3.png.26a5a132609c72a06b9ce8562bdd462d.png" /></p>

<p>هذا الدّرس هو جزء من سلسلة دروس حول نشر تطبيقات PHP باستخدام Ansible على Ubuntu، تحدّثنا في الجزئين السّابقين عن <a href="https://academy.hsoub.com/devops/servers/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-1-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-ansible-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D9%87-r161/">تثبيت Ansible وإعداده</a> ومن ثم عن <a href="https://academy.hsoub.com/devops/servers/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-2-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-laravel-%D9%88nginx-r162/">إعداد Laravel وNginx</a>.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php-3.png.09150926b21d50b243c940b960e6630a.png"><img data-fileid="10504" class="ipsImage ipsImage_thumbnailed" alt="ansible-php-3.thumb.png.89754a43917115f9" src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php-3.thumb.png.89754a43917115f99bd6ac7374919fe7.png"></a></p><p>سنغطّي في هذا الدّرس إعداد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> لتدعم أدوات نشر وتوزيع الشيفرة، وإعداد الجدار الناري للنظام، هدفنا في النهاية هو الحصول على خادوم يعمل عليه تطبيق PHP بشكل كامل مع الإعدادات المذكورة آنفًا.</p><h2 id="المتطلبات-الأساسية">المتطلبات الأساسية</h2><p>يبدأ هذا الدّرس مباشرة من حيث انتهى <a href="https://academy.hsoub.com/devops/servers/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-2-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-laravel-%D9%88nginx-r162/">الجزء السّابق</a> من هذه السلسلة، ونحتاج كافّة الملفّات والإعدادات التي تم الحصول عليها في ذلك الجزء، إن لم تقم بإكمال أول قسمين من هذه السلسلة فنرجو أن تفعل ذلك قبل متابعة هذا الدّرس.</p><h2 id="الخطوة-الأولى-تبديل-مستودع-التطبيق">الخطوة الأولى – تبديل مستودع التطبيق</h2><p>سنقوم في هذه الخطوة بتحديث مستودع Git إلى مثال عن مستودع مُخصَّص قليلًا.</p><p>بما أنّ تثبيت Laravel الافتراضي لا يتطلّب الميّزات المتقدمة التي سنقوم بإعدادها في هذا الدّرس فسنقوم بتبديل المستودع الموجود حاليًّا إلى مثال عن مستودع مع إضافة شيفرة للتنقيح debugging code فقط من أجل أن نظهر متى يعمل كل شيء، يُوجد المستودع الذي سنستخدمه على الرابط <code><a rel="external nofollow" href="https://github.com/do-community/do-ansible-adv-php">https://github.com/do-community/do-ansible-adv-php</a></code>.</p><p>نقوم بتغيير الدليل إلى <code>ansible-php</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">cd ~/ansible-php/
</pre><p>نفتح playbook الموجودة حاليًّا من أجل تحريرها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نقوم بإيجاد وتحديث المهمّة “Clone git repository” بحيث تبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    Updated Ansible task

- name: Clone git repository
  git: &gt;
    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
</pre><p>نحفظ ونشغل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>وبعد أن يتم تشغيلها نزور خادومنا في متصفح الويب لدينا (على الرابط <code><a rel="external nofollow" href="http://your">http://your_server-ip</a></code> بعد وضع عنوان خادومك)، ينبغي أن نشاهد رسالة تقول لم يتم العثور على التعريف "<strong>could not find driver"</strong>.</p><p>يعني هذا أنّنا نجحنا في استبدال المستودع الافتراضي بمثال مستودعنا، ولكن لا يستطيع التطبيق الاتصال بقاعدة البيانات، وهو ما نتوقع مشاهدته هنا، وسنقوم بتثبيت وإعداد قاعدة البيانات لاحقًا في هذا الدّرس.</p><h2 id="الخطوة-الثانية-إعداد-مفاتيح-ssh-من-أجل-النشر">الخطوة الثانية – إعداد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من أجل النشر</h2><p>سنقوم في هذه الخطوة بإعداد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> والتي يُمكن استخدامها من أجل نشر شيفرة التطبيق.</p><p>ومع أنّ Ansible رائعة من أجل المحافظة على الإعدادات وإعداد الخواديم والتطبيقات، فيتم عادةً استخدام أدوات مثل <a rel="external nofollow" href="http://laravel.com/docs/5.0/envoy">Envoy</a> و <a rel="external nofollow" href="https://github.com/rocketeers/rocketeer">Rocketeer</a> من أجل دفع تغييرات الشيفرة إلى الخادوم وتنفيذ أوامر التطبيق عن بُعد، تتطلّب أغلب هذه الأدوات اتصال <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> يتمكن من النفاذ إلى تثبيت التطبيق بشكل مباشر، يعني هذا في حالتنا أنّنا نحتاج إلى إعداد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من أجل المستخدم <code>www-data</code>.</p><p>سنحتاج إلى ملف مفتاح عام من أجل المستخدم الذي نرغب بدفع الشيفرة منه، يُوجد هذا الملف بشكل نموذج في المسار <code><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/id_rsa.pub./~</code>، ننسخ هذا الملف إلى الدليل <code>ansible-php</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">cp ~/.ssh/id_rsa.pub ~/ansible-php/deploykey.pub</pre><p>بإمكاننا استخدام الوحدة <code>authorized_key</code> لـ Ansible من أجل تثبيت مفتاحنا العام داخل <span style="font-family:courier new,courier,monospace;"><code>var/www/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/authorized_keys/</code></span> والذي سيسمح لأدوات النشر بالاتصال والنفاذ إلى تطبيقنا، تحتاج الإعدادات فقط إلى معرفة مكان المفتاح، باستخدام lookup، وإلى معرفة المستخدم الذي سيتم تثبيت المفتاح لأجله (<code>www-data</code> في حالتنا).</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    New Ansible task

- name: Copy public key into /var/www
  authorized_key: user=www-data key="{{ lookup('file', 'deploykey.pub') }}"
</pre><p>نحتاج أيضًا لإعداد صدفة shell المستخدم <code>www-data</code> كي نستطيع فعليًّا تسجيل الدخول، وإلّا سيسمح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> بالاتصال ولكن لن يتم عرض صدفة shell للمستخدم، يُمكن عمل هذا باستخدام الوحدة <code>user</code> وتعيين الصدفة إلى <code>/bin/bash</code> (أو الصدفة المفضلة لديك):</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    New Ansible task

- name: Set www-data user shell
  user: name=www-data shell=/bin/bash
</pre><p>نفتح الآن الـ playbook لتحريرها من أجل إضافة المهام الجديدة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف المهام السابقة إلى الـ playbook التي تُدعى <code>php.yml</code>، يجب أن تبدو نهاية الملف متطابقة مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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:

. . .
</pre><p>نقوم بحفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>عندما تنتهي Ansible من ذلك ينبغي أن نكون قادرين على الدخول باستخدام <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> عن طريق المستخدم <code>www-data</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ssh www-data@your_server_ip
</pre><p>إن استطعنا تسجيل الدخول بنجاح فهي تعمل بشكل صحيح، بإمكاننا الآن تسجيل الخروج عن طريق إدخال <code>logout</code> أو ضغط <strong>CTRL+D</strong>.</p><p>لن نحتاج إلى استخدام هذا الاتصال في أي خطوات لاحقة، ولكن يبقى مفيدًا إن قمنا بإعداد أدوات أخرى، كما أشرنا سابقًا، أو من أجل التنقيح العام general debugging وصيانة التطبيق كما هو مطلوب.</p><h2 id="الخطوة-الثالثة-إعداد-الجدار-الناري">الخطوة الثالثة – إعداد الجدار الناري</h2><p>سنقوم في هذه الخطوة بإعداد الجدار الناري على الخادوم للسماح فقط بالاتصالات من أجل HTTP وSSH.</p><p>يأتي Ubuntu مع جدار ناري يُدعى UFW (الجدار الناري غير المعقد Uncomplicated Firewall) مُثبَّت عليه بشكل افتراضي، وتدعمه Ansible بالوحدة <code>ufw</code>، يمتلك عدد من الميزات القوية وتمّ تصميمه ليكون بسيطًا قدر الإمكان وهو ملائم بشكل مثالي لخواديم الويب المحتواة ذاتيًّا والتي تحتاج فقط إلى عدة منافذ مفتوحة، نرغب في حالتنا بأن يكون المنفذ 80 (من أجل HTTP) والمنفذ 22 (من أجل <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>) مفتوحًا، وربّما قد تريد المنفذ 443 مفتوحًا من أجل HTTPS.</p><p>تمتلك الوحدة <code>ufw</code> عددًا من الخيارات المختلفة تقوم بتنفيذ مهام مختلفة، وهذه المهام التي نريد تنفيذها هي:</p><ul><li>تمكين UFW ورفض كامل حركة مرور البيانات traffic القادمة افتراضيًّا.</li><li>فتح منفذ <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> ولكن مع تحديده لمنع هجمات القوة القاسية brute force attacks.</li><li>فتح منفذ HTTP.</li></ul><p>يُمكِن فعل هذا باستخدام المهام التالية على الترتيب:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                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
&lt;/code&gt;</pre><p>نفتح الملف <code>php.yml</code> من أجل تحريره:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">nano php.yml</pre><p>نضيف المهام السابقة إلى الـ playbook، ينبغي أن تتطابق نهاية الملف مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    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:

. . .
</pre><p>نقوم بحفظ وتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>بعد أن يتم هذا بنجاح يجب أن نكون قادرين على الاتصال عبر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> (باستخدام Ansible) أو HTTP إلى خادومنا، ستكون المنافذ الأخرى مقفلة الآن.</p><p>نستطيع التحقّق من حالة UFW في أي وقت عن طريق تنفيذ هذا الأمر:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible php --sudo --ask-sudo-pass -m shell -a "ufw status verbose"
</pre><p>وبتقسيم أمر Ansible السابق من أجل فهمه نجد:</p><ul><li><code>ansible</code>: تقوم بتنفيذ مهمّة Ansible خام بدون playbook.</li><li><code>php</code>: تقوم بتنفيذ المهمّة على المضيفين في هذه المجموعة.</li><li><code>--sudo</code>: تنفّذ الأمر كـ <code>sudo</code>.</li><li><code>--ask-sudo-pass</code>: تقوم بالحث prompt من أجل كلمة سر <code>sudo</code>.</li><li><code>-m shell</code>: تقوم بتشغيل وحدة الصدفة <code>shell</code>.</li><li><code>-a "ufw status verbose</code>“: الخيارات التي يجب تمريرها إلى الوحدة، وبما أنّها أمر <code>shell</code> نقوم بتمرير الأمر الخام raw (أي <code>ufw status verbose</code>) مباشرة بدون أي خيارات <code>key=value</code>.</li></ul><p>يجب أن يُعيد شيئًا مشابهًا لهذا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">                    UFW status output

your_server_ip | success | rc=0 &gt;&gt;
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)

</pre><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-deploy-an-advanced-php-application-using-ansible-on-ubuntu-14-04">How To Deploy an Advanced PHP Application Using Ansible on Ubuntu 14.04</a> لصاحبه Stephen Rees-Carter.</p>
]]></description><guid isPermaLink="false">163</guid><pubDate>Wed, 30 Dec 2015 21:00:27 +0000</pubDate></item><item><title>&#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642; PHP &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ansible - &#x625;&#x639;&#x62F;&#x627;&#x62F; Laravel &#x648;Nginx</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-laravel-%D9%88nginx-r162/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php-2.png.b02f5a149fc969a43653a927f61d0dde.png" /></p>

<p>سنواصل في هذا الدّرس حديثنا حول نشر تطبيق PHP باستخدام Ansible. هذا الدّرس هو الجزء الثّاني للسلسلة، إذا لم تقرأ الجزء الأول فمن الأفضل أن تشرع به أوّلا، حيث نُعالج فيه <a href="https://academy.hsoub.com/devops/servers/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-1-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-ansible-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D9%87-r161/">تثبيت Ansible وإعداده</a>. إذا لم تكن لديك أيّة خلفية مُسبقة حول Ansible فمن الأفضل أن تبدأ مع مقال <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-ansible-%D8%B9%D9%84%D9%89-ubuntu-r158/">كيفيّة تثبيت وإعداد Ansible على Ubuntu</a>.</p><p style="text-align: center;"><a href="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php-2.png.bf13e6c9fd8eb21476fcdeec2fce89ed.png" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="10505" src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php-2.thumb.png.7c882b03b8d21ba99771bbe1aee1d913.png" class="ipsImage ipsImage_thumbnailed" alt="ansible-php-2.thumb.png.7c882b03b8d21ba9"></a></p><p>سنتحدث في هذا القسم من الدّرس عن كيفية الحصول على إطار عمل Laravel وإعداده وإعداد خادوم Nginx لتخديم تطبيق PHP.</p><p>سنستخدم <a href="https://academy.hsoub.com/programming/php/laravel">إطار عمل Laravel</a> كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك.</p><h2 id="المتطلبات-الأساسية">المتطلبات الأساسية</h2><p style="line-height: 22.4px;">يبدأ هذا الدّرس مباشرة من حيث انتهى <a href="https://academy.hsoub.com/devops/servers/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-ansible-%D8%B9%D9%84%D9%89-ubuntu-%D9%88%D8%AA%D8%AC%D9%87%D9%8A%D8%B2%D9%87-%D9%84%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-php-r161/">الجزء الأول</a> من هذه السلسلة، ونحتاج كافّة الملفّات والإعدادات التي تم الحصول عليها في ذلك الجزء، إن لم تقم بإكمال أول درس من هذه السلسلة فنرجو أن تفعل ذلك قبل متابعة هذا الدّرس.</p><h2 id="الخطوة-الأولى-استنساخ-cloning-مستودع-git">الخطوة الأولى – استنساخ مستودع Git</h2><p>في هذا القسم سنقوم باستنساخ clone مستودع إطار عمل Laravel إلى الخادوم الخاص بنا باستخدام Git، سنشرح مثل الخطوة الثالثة كافّة الأقسام التي سنقوم بإضافتها إلى الـ playbook، ونضمّن بعدها كامل ملف <code>php.yml</code> من أجلك لتقوم بنسخه ولصقه.</p><p>وقبل أن نستنسخ مستودع Git الخاص بنا نحتاج إلى التأكّد من وجود الدليل <code>var/www</code><span style="font-family: monospace; line-height: 22.4px;">/</span>، نستطيع فعل هذا عن طريق إنشاء مهمّة مع وحدة الملف:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- name: create /var/www/ directory
  file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700
</pre><p>نحتاج كما أشرنا سابقًا إلى استخدام الوحدة Git لاستنساخ المستودع إلى الخادوم الخاص بنا، وهي عمليّة بسيطة لأنّ كل ما نحتاجه بشكل طبيعي من أجل الأمر <code>git clone</code> هو مستودع المصدر source repository، في هذه الحالة سنعرّف أيضًا الوجهة destination ونخبر Ansible بعدم تحديث المستودع في حال وجوده مسبقًا عن طريق تعيين <code>update=no</code>، وبما أنّنا نستخدم Laravel سنستعمل رابط مستودع git التالي: <code><a rel="external nofollow" href="https://github.com/laravel/laravel.git">https://github.com/laravel/laravel.git</a></code></p><p>نحتاج مع ذلك إلى تشغيل المهمّة عن طريق المستخدم <code>www-data</code> للتأكّد من أنّ الصلاحيّات صحيحة، ولعمل هذا نستطيع إخبار Ansible أن ينفّذ الأمر كمستخدم محدّد باستخدام <code>sudo</code>، ستبدو المهمّة النهائية كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- name: Clone git repository
  git: &gt;
    dest=/var/www/laravel
    repo=https://github.com/laravel/laravel.git
    update=no
  sudo: yes
  sudo_user: www-data
</pre><p><strong>ملاحظة:</strong> من أجل المستودعات المعتمدة على <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> نستطيع إضافة <code>accept_hostkey=yes</code> لمنع التحقّق من المضيف على <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من تعليق المهمّة.</p><p>نفتح الملف <code>php.yml</code> لتحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف المهام السابقة إلى الـ playbook، يجب أن يبدو الملف النهائي كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">...

  - 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: &gt;
      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
</pre><p>نحفظ الـ playbook ونغلقها، ثمّ نقوم بتشغيلها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><h2 id="الخطوة-الثانية-إنشاء-تطبيق-باستخدام-composer">الخطوة الثانية – إنشاء تطبيق باستخدام Composer</h2><p>سنستخدم في هذه الخطوة <a href="https://academy.hsoub.com/programming/php/%D9%85%D8%A7-%D9%87%D9%88-composer-%D9%88%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AC%D8%A8-%D8%B9%D9%84%D9%89-%D9%83%D9%8F%D9%84-%D9%85%D9%8F%D8%B7%D9%88%D8%B1-php-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87-r10/">Composer</a> لتثبيت تطبيق PHP واعتمادياته dependencies.</p><p>يمتلك Composer الأمر <span style="font-family:courier new,courier,monospace;"><code>create-project</code></span> الذي يقوم بتثبيت كافّة الاعتماديات المطلوبة ومن ثمّ يُشغِّل خطوات إنشاء المشروع المُعرَّفة في القسم <code>post-create-project-cmd</code> من الملف <code>composer.json</code>، وهي الطريق المفضّلة للتأكّد من إعداد التطبيق بشكل صحيح لاستخدامه لأول مرّة.</p><p>نستطيع استخدام مهمّة Ansible التالية لتنزيل وتثبيت Composer بشكل عمومي كـ <code>usr/local/bin/composer</code><span style="font-family: monospace; line-height: 22.4px;">/</span>، سيكون بعدها قابلًا للنفاذ من قبل أي شخص يستخدم الخادوم بما فيهم Ansible:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- name: install composer
  shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
  args:
    creates: /usr/local/bin/composer
</pre><p>ومع وجود Composer مُثبّتًا لدينا فهنالك وحدة لـ Composer يُمكننا استخدامها، في حالتنا نريد إخبار Composer عن مكان مشروعنا (باستخدام المُعامِل <code>working_dir</code>)، ونريد أيضًا تنفيذ الأمر <code>create-project</code>، نحتاج أيضًا لإضافة المُعامِل <code>optimize_autoloader=no</code> لأنّ هذا العَلَم غير مدعوم من قبل الأمر <code>create-project</code>، وكما في حالة الأمر <code>git</code> يجب علينا تنفيذ هذا عن طريق المستخدم <code>www-data</code> للتأكّد من صلاحيّة الأذونات permissions، وبوضع كل ذلك معًا نحصل على هذه المهمّة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- name: composer create-project
  composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no
  sudo: yes
  sudo_user: www-data
</pre><p><strong>ملاحظة:</strong> قد تستغرق المهمّة <code>create-project</code> قدرًا كبيرًا من الوقت على خادوم جديد، حيث يمتلك الـ Composer ذاكرة تخزين مؤقّت فارغة ويحتاج إلى تنزيل كل شيء من جديد.</p><p>نفتح الآن الملف <code>php.yml</code> لتحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف المهام السابقة في نهاية القسم <code>tasks</code> فوق <code>handlers</code> بحيث تتوافق نهاية الـ playbook مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">...

  - name: Clone git repository
    git: &gt;
      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
</pre><p>نقوم أخيرًا بتشغيل الـ playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>ما الذي سيحدث إن قمنا بتشغيل Ansible مرّة أخرى الآن؟ سيتم تشغيل <code>composer create-project</code> مرّة أخرى، وفي حالة Laravel يعني هذا <code>APP_KEY</code> جديد، لذا نريد بدلًا من ذلك تعيين المهمّة لتعمل فقط بعد استنساخ clone جديد، نستطيع ضمان أنّها تعمل فقط مرّة واحدة عن طريق تسجيل متغيّر يحتوي نتائج المهمّة git clone ومن ثمّ التحقّق من هذه النتائج داخل المهمّة <code>composer create-project</code>، إن تمّ تغيير المهمّة <code>git clone</code> فسيتم تنفيذ <code>composer create-project</code>، أمّا إن لم يحدث ذلك فسيتم تخطّيها.</p><p><strong>ملاحظة:</strong> يبدو أنّه يوجد خطأ برمجي في بعض إصدارات وحدة <code>composer</code> في Ansible، وربّما تعيد الخَرْج OK بدلًا من Changed، حيث تتجاهل أنّه تمّ تنفيذ scripts على الرغم من أنّه لم يتم تثبيت اعتماديات.</p><p>نفتح الملف <code>php.yml</code> من أجل تحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نبحث عن المهمّة <code>git clone</code>، نضيف الخيار <code>register</code> لحفظ نتائج المهمّة إلى المتغير <code>cloned</code> كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- name: Clone git repository
  git: &gt;
    dest=/var/www/laravel
    repo=https://github.com/laravel/laravel.git
    update=no
  sudo: yes
  sudo_user: www-data
  register: cloned
&lt;/code&gt;</pre><p>نبحث بعدها عن المهمّة <code>composer create-project</code>، نضيف الخيار <code>when</code> للتحقّق من المتغيّر <code>cloned</code> لنرى إن تغيّرت قيمته أم لا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- 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
</pre><p>نقوم بحفظ الـ playbook وتشغيلها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>سيوقف الـ Composer الآن تغيير <code>APP_KEY</code> في كل مرّة يتم تشغيله فيها.</p><h2 id="الخطوة-الثالثة-تحديث-متغيرات-البيئة">الخطوة الثالثة – تحديث متغيرات البيئة</h2><p>في هذه الخطوة سنقوم بتحديث متغيّرات البيئة Environment Variables من أجل تطبيقنا.</p><p>يأتي Laravel مع ملف <code>env.</code> بشكل افتراضي والذي يقوم بتعيين قيمة <code>APP_ENV</code> إلى <code>local</code> وقيمة <code>APP_DEBUG</code> إلى <code>true</code>، نحتاج إلى تبديل هذه القيم إلى <code>production</code> و <code>false</code> على الترتيب، يُمكِن فعل هذا ببساطة باستخدام الوحدة <code>lineinfile</code> مع المهام التالية:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- 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
</pre><p>نفتح الملف <code>php.yml</code> لتحريره:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف هذه المهمّة إلى الـ playbook، يجب أن تبدو نهاية الملف متطابقة مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">...

  - 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
</pre><p>نقوم بحفظ الـ playbook وتشغيلها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>إنّ الوحدة <code>lineinfile</code> مفيدة جدًا من أجل التطويعات tweaks السريعة لأي ملف نصّي، وهي رائعة للتأكّد من تعيين متغيّرات بيئة كهذه بشكل صحيح.</p><h2 id="الخطوة-الرابعة-إعداد-nginx">الخطوة الرابعة – إعداد Nginx</h2><p>سنقوم في هذا القسم بإعداد Nginx لتخديم تطبيق PHP.</p><p>إن زرت الآن الخادوم الخاص بك في متصفّح الإنترنت (على سبيل المثال <span style="font-family:courier new,courier,monospace;"><a rel="external nofollow" href="http://your">http://your_server_ip</a> </span>)، فسترى صفحة Nginx الافتراضيّة بدلاً من صفحة المشروع الجديد في Laravel، حدث هذا لأنّنا لا زلنا نحتاج إلى إعداد خادوم ويب Nginx لدينا لتخديم التطبيق من الدليل <code>var/www/laravel/public</code><span style="font-family: monospace; line-height: 22.4px;">/</span>، لفعل هذا نحتاج لتحديث إعدادات Nginx الافتراضيّة بهذا الدليل وإضافة دعم من أجل <code>php-fpm</code> بحيث يستطيع التعامل مع PHP scripts.</p><p>نقوم بإنشاء ملف جديد يُدعى <code>nginx.conf</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano nginx.conf
</pre><p>نحفظ كتلة الخادوم التالية بداخل هذا الملف، تستطيع متابعة الخطوة الرابعة من <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81-%D8%AA%D9%8F%D8%AB%D8%A8%D9%91%D9%90%D8%AA-%D8%AD%D9%90%D8%B2%D9%85-mysql%D8%8C-nginx%D8%8C-linux-lemp-%D9%88php-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r29/">هذا الدّرس</a> من أجل المزيد من التفاصيل حول إعدادات Nginx، تُحدِّد التعديلات التالية مكان دليل Laravel العام وتتحقّق من استخدام Nginx لاسم المضيف الذي عرّفناه في الملف <code>hosts</code> كـ <code>server_name</code> مع المتغيّر <code>inventory_hostname</code>.</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">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;
    }
}
</pre><p>نحفظ الملف <code>nginx.conf</code> ونغلقه.</p><p>بإمكاننا الآن استخدام وحدة القالب <code>template module</code> لدفع ملف الإعدادات الجديدة عبرها، تبدو وحدة <code>template</code> مشابهة جدًا للوحدة <code>copy</code>، ولكن يوجد فرق كبير بينهما، فالوحدة <code>copy</code> ستنسخ ملف أو عدّة ملفّات بدون القيام بأيّة تغييرات، بينما تنسخ الوحدة <code>template</code> ملفًّا واحدًا وتقوم بتحليل كافّة الملفّات الموجودة بداخله، ولأنّنا استخدمنا <code>{{ inventory_hostname }}</code> داخل ملف إعداداتنا سنستخدم الوحدة <code>template</code> بحيث يتم تحليلها بداخل عنوان IP الذي استخدمناه في الملف <code>hosts</code>، وبهذه الطريقة لا يتوجّب علينا كتابة شيفرة محدّدة لملفّات الإعدادات التي تستخدمها Ansible.</p><p>ومع ذلك فكما هو معتاد عند كتابة المهام نحتاج إلى أن نأخذ بعين الاعتبار ما سيحدث على الخادوم، ولأنّنا نقوم بتغيير إعدادات Nginx نحتاج لإعادة تشغيل Nginx و <code>php-fpm</code>، يتم هذا باستخدام الخيار <code>notify</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- name: Configure nginx
  template: src=nginx.conf dest=/etc/nginx/sites-available/default
  notify:
    - restart php5-fpm
    - restart nginx
</pre><p>نفتح ملف <code>php.yml</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">nano php.yml
</pre><p>نضيف مهمّة nginx هذه في نهاية قسم المهام، ينبغي أن يبدو الملف <code>php.yml</code> كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">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: &gt;
      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
</pre><p>نقوم بحفظ الـ playbook وتشغيلها مرّة أخرى:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>حالما تكتمل نعود إلى متصفحنا ونقوم بتحديثه، ينبغي أن نرى الآن صفحة المشروع الجديد في Laravel.</p><h2 id="الخاتمة">الخاتمة</h2><p>يُغطّي هذا الدرس نشر تطبيق PHP مع مستودع عام، وبينما يكون هذا مثاليًّا من أجل تعلّم كيفيّة عمل Ansible، فإنّك لن تعمل دائمًا على مشاريع مفتوحة المصدر بشكل كامل مع مستودعات مفتوحة، ويعني هذا أنّك ستحتاج إلى استيثاق <code>git clone</code> في الخطوة الثالثة مع مستودعك الخاص، يُمكِن فعل هذا بسهولة باستخدام مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>.</p><p>على سبيل المثال بعدما تقوم بإنشاء وإعداد مفاتيح نشر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> على مستودعك تستطيع استخدام Ansible لنسخها وإعدادها على خادومك قبل مهمّة <code>git clone</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">- name: create /var/www/.&lt;abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"&gt;ssh&lt;/abbr&gt;/ directory
  file: dest=/var/www/.&lt;abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"&gt;ssh&lt;/abbr&gt;/ state=directory owner=www-data group=www-data mode=0700

- name: copy private &lt;abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"&gt;ssh&lt;/abbr&gt; key
  copy: src=deploykey_rsa dest=/var/www/.&lt;abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"&gt;ssh&lt;/abbr&gt;/id_rsa owner=www-data group=www-data mode=0600</pre><p>يجب أن يسمح هذا للخادوم بالاستيثاق بشكل صحيح ونشر تطبيقك.</p><p>لقد قمنا للتو بنشر تطبيق PHP بسيط على خادوم ويب Nginx معتمد على Ubuntu باستخدام Composer لإدارة الاعتماديّات، وتمّ كل هذا بدون الحاجة للدخول مباشرة إلى الخادوم الخاصّ بنا وتنفيذ أي أمر بشكل يدوي.</p><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-basic-php-application-using-ansible-on-ubuntu-14-04">How To Deploy a Basic PHP Application Using Ansible on Ubuntu 14.04</a> لصاحبه Stephen Rees-Carter.</p>
]]></description><guid isPermaLink="false">162</guid><pubDate>Wed, 30 Dec 2015 20:56:00 +0000</pubDate></item><item><title>&#x62A;&#x62B;&#x628;&#x64A;&#x62A; Ansible &#x639;&#x644;&#x649; Ubuntu &#x648;&#x62A;&#x62C;&#x647;&#x64A;&#x632;&#x647; &#x644;&#x646;&#x634;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; PHP</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-ansible-%D8%B9%D9%84%D9%89-ubuntu-%D9%88%D8%AA%D8%AC%D9%87%D9%8A%D8%B2%D9%87-%D9%84%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-php-r161/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php.png.2bb807ca23b357bdafd358bf1f403eb9.png" /></p>

<p>ستغطّي هذه السّلسلة عمليّة نشر تطبيق PHP بسيط باستخدام Ansible، الهدف النّهائي سيكون الحصول على خادوم ويب جديد يُخدِّم تطبيق PHP بسيط بدون أي اتصال عبر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> أو تشغيل يدوي للأوامر على الخادوم الهدف، سنغطي في هذا القسم من الدرس تثبيت Ansible وإعداد البيئة بشكل عام.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php.png.811f89365138f497cb6c23e1185f001a.png"><img data-fileid="10243" class="ipsImage ipsImage_thumbnailed" alt="ansible-php.thumb.png.e0208782e520919a2f" src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-php.thumb.png.e0208782e520919a2f0744a6f2c1ec2a.png"></a></p><p>سنستخدم <a href="https://academy.hsoub.com/programming/php/laravel">إطار عمل Laravel</a> كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك.</p><h2 id="المتطلبات-الأساسية">المتطلبات الأساسية</h2><p>سنستخدم Ansible لتثبيت وإعداد Nginx، PHP، وخدمات أخرى على خادوم Ubuntu 14.04 ، يعتمد هذا الدّرس على معرفتك الأساسية بـ Ansible لذا إن كنت جديدًا عليها فبإمكانك قراءة <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-ansible-%D8%B9%D9%84%D9%89-ubuntu-r158/">درس Ansible الأساسي</a> أولًا.</p><p>ستحتاج لمتابعة هذا الدّرس إلى:</p><ul><li>خادوم Ubuntu 14.04 بأي حجم والذي سنستخدمه لإعداد ونشر تطبيق PHP الخاص بنا عليه، ستتم الإشارة إلى عنوان IP هذا الجهاز بـ <code>your_server_ip</code> خلال هذا الدّرس.</li><li>خادوم Ubuntu 14.04 والذي سنستخدمه من أجل Ansible، وهو الخادوم الذي سنبقى في وضعية تسجيل دخول عليه في كامل هذا الدّرس.</li><li>إعداد <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/">مستخدم غير جذري مع صلاحيّات sudo</a> لكل خادوم.</li><li>مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من أجل خادوم Ansible لتصريح تسجيل الدخول على خادوم نشر PHP، ويُمكِن إعدادها باتّباع <a href="https://academy.hsoub.com/search/?tags=%D9%85%D8%AF%D8%AE%D9%84+%D8%A5%D9%84%D9%89+ssh">هذه السلسلة</a> وتطبيقها على خادوم Ansible الخاص بنا.</li></ul><h2 id="الخطوة-الأولى-تثبيت-ansible">الخطوة الأولى – تثبيت Ansible</h2><p>يُمكِن إنجاز هذه الخطوة بسهولة عن طريق تثبيت PPA (أرشيف الحِزَم الشخصي Personal Package Archive) وتثبيت حزمة Ansible باستخدام <code>apt</code>.</p><p>نُضيف أوّلًا PPA باستخدام الأمر <code>apt-add-repository</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo apt-add-repository ppa:ansible/ansible</pre><p>وبعد انتهائه نقوم بتحديث ذاكرة التخزين المؤقّت cache لـ <code>apt</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo apt-get update
</pre><p>نقوم بتثبيت Ansible أخيرًا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo apt-get install ansible</pre><p>حالما يتم تثبيت Ansible نقوم بإنشاء دليل جديد للعمل بداخله وضبط الإعدادات الأساسيّة، تستخدم Ansible افتراضيًّا ملف مضيفين hosts موجود في المسار <code>etc/ansible/hosts</code><span style="font-family: monospace; line-height: 22.4px;">/</span>، وهو يحتوي كافّة الخواديم التي يُديرها، وبينما يكون هذا الملف مناسبًا لبعض حالات الاستخدام فهو عام global، وهو ما لا نريده هنا.</p><p>سنقوم من أجل هذا الدّرس بإنشاء ملف مضيفين محلّي local واستخدامه بدلًا من الملف السابق، نستطيع فعل هذا عن طريق إنشاء ملف إعدادات Ansible جديد بداخل دليل العمل لدينا، والذي بإمكاننا استخدامه لإخبار Ansible بأن تبحث عن ملف المضيفين داخل نفس الدليل.</p><p>نُنشِئ مُجلّدًا جديدًا (سنستخدمه لبقيّة هذا الدّرس):</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">mkdir ~/ansible-php
</pre><p>ننتقل إلى داخل المُجلّد الجديد:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">cd ~/ansible-php/</pre><p>نُنشِئ ملفًّا جديدًا يُدعى <code>ansible.cfg</code> ونفتحه من أجل تحريره باستخدام <code>nano</code> أو أي مُحرِّر نصوص تفضله:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">nano ansible.cfg</pre><p>نضيف خيار الإعدادات <code>hostfile</code> مع القيمة <code>hosts</code> في المجموعة <code>[defaults]</code> عن طريق نسخ ما يلي إلى الملف <code>ansible.cfg</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible.cfg

[defaults]
hostfile = hosts</pre><p>نحفظ الملف <code>ansible.cfg</code> ونغلقه، نقوم بعدها بإنشاء الملف <code>hosts</code> والذي يحتوي على عنوان IP لخادوم PHP حيث سيتم نشر تطبيقنا.</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">nano hosts</pre><p>ننسخ ما يلي لإضافة قسم من أجل <code>php</code> مع وضع عنوان IP الخاص بخادومك بدلًا من <code>your_server_ip</code> ووضع اسم المستخدم غير الجذري الذي قمت بإنشائه في المتطلبات الأساسيّة على خادوم PHP بدلًا من <code>sammy</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">hosts

[php]
your_server_ip ansible_ssh_user=sammy
</pre><p>نحفظ ونغلق الملف <code>hosts</code>، فلنقم بإجراء تحقّق أبسط للتأكد من قدرة Ansible على الاتصال بالمضيف كما هو متوقّع عن طريق استدعاء الوحدة <code>ping</code> على المجموعة <code>php</code> الجديدة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible php -m ping</pre><p>ربّما تحصل على تحقّق من استيثاق مُضيف <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> اعتمادًا على كونك قد سجلّت الدخول إلى هذا المُضيف من قبل، ينبغي أن تعود ping باستجابة ناجحة تبدو كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">Output

111.111.111.111 | success &gt;&gt; {
    "changed": false,
    "ping": "pong"
</pre><p>تمّ الآن تثبيت وإعداد Ansible بنجاح، نستطيع الانتقال إلى إعداد خادوم الويب لدينا.</p><h2 id="الخطوة-الثانية-تثبيت-الحزم-المطلوبة">الخطوة الثانية – تثبيت الحزم المطلوبة</h2><p>سنقوم في هذه الخطوة بتثبيت بعض حِزَم النظام المطلوبة باستخدام Ansible و <code>apt</code>، سنثبت تحديدًا <code>git</code>، <code>nginx</code>، <code>sqlite3</code>، <code>mcrypt</code>، وبعض حِزَم <code>php5-*</code>.</p><p>نحتاج قبل إضافة الوحدة <code>apt</code> لتثبيت الحِزَم التي نريدها إلى إنشاء playbook بسيط (وهو عبارة عن قواعد تُحدِّد إعدادات Ansible)، سنبني على هذا الـ playbook مع تقدّمنا في هذا الدّرس، نقوم بإنشاء playbook جديد يُدعى <code>php.yml</code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">nano php.yml
</pre><p>نلصق الإعدادات التالية، يُحدِّد أول سطرين مجموعة المضيفين التي نرغب باستخدامها (<code>php</code>) وتتحقّق من أنّها تنفّذ الأوامر باستخدام <code>sudo</code> افتراضيًّا، تُضيف باقي الأسطر وحدة بالحِزَم التي نحتاجها، تستطيع تخصيصها من أجل تطبيقاتك الخاصّة أو استخدام الإعدادات التالية إن كنت تتبع مثال تطبيق Laravel:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">---
- 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</pre><p>نحفظ الملف <code>php.yml</code>، ونقوم أخيرًا بتشغيل <code>ansible-playbook</code> لتثبيت الحِزَم على الخادوم، يجب ألّا ننسى استخدام الخيار <code>--ask-sudo-pass</code> إن كان يتطلّب مستخدم sudo على خادوم PHP كلمة سر:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible-playbook php.yml --ask-sudo-pass</pre><h2 id="الخطوة-الثالثة-تعديل-ملفات-إعدادات-النظام">الخطوة الثالثة – تعديل ملفات إعدادات النظام</h2><p>سنقوم في هذا القسم بتعديل بعض ملفّات إعدادات النظام على خادوم PHP، أهم خيار إعدادات يُمكِن تغييره (بغض النظر عن ملفّات Nginx، والتي سيتم تغطيتها في خطوة لاحقة) هو الخيار <code>cgi.fix_pathinfo</code> في <code>php5-fpm</code>، لأنّ القيمة الافتراضيّة له تُشكِّل خطرًا أمنيًّا.</p><p>سنوضّح أوّلًا جميع الأقسام التي سنضيفها إلى هذا الملف، ونضمّن بعدها كامل الملف <code>php.yml</code> من أجلك لكي تقوم بنسخه ولصقه.</p><p>يُمكِن استخدام الوحدة lineinfile للتأكّد من أنّ قيمة الإعدادات ضمن الملف مطابقة تمامًا لما نتوقعه، يُمكِن عمل هذا باستخدام <a href="https://academy.hsoub.com/devops/linux/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-regular-expressions-r63/">تعبير نمطي regular expression</a> عام بحيث تتمكّن Ansible من فهم معظم الصيغ التي من المحتمل أن يكون فيها المُعامِل، سنحتاج أيضًا لإعادة تشغيل <code>php5-fpm</code> و<code>nginx</code> لضمان تطبيق التغييرات، لذا نحتاج إلى إضافة مُداوِلَين handlers اثنين أيضًا في قسم جديد للمداولات <code>handlers</code>، تكون المداولات مثاليّة لهذا لأنّه يتم إطلاقها فقط عند تغيير المهمّة، ويتم أيضًا تشغيلها في نهاية الـ playbook، لذا يُمكن لمهام متعدّدة استدعاء نفس المُداوِل وسيعمل فقط مرّة واحدة.</p><p>يبدو القسم الذي يُنفِّذ ما سبق كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">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</pre><p><strong>ملاحظة: خطأ برمجي bug في إصدار Ansible 1.9.1</strong></p><p>يوجد خطا برمجي في إصدار Ansible 1.9.1 يمنع <code>php5-fpm</code> من إعادة تشغيلها مع الوحدة <code>service</code>، وقد استخدمنا هذا في مُداولاتنا.</p><p>وحتى يتم إصدار إصلاح له نستطيع الالتفاف على هذه المشكلة عن طريق تغيير المُداوِل <code>restart php5-fpm</code> من استخدام الأمر <code>service</code> إلى استخدام الأمر <code>shell</code> كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">    - name: restart php5-fpm
      shell: service php5-fpm restart</pre><p>سيتجاوز هذا المشكلة ويعيد تشغيل <code>php5-fpm</code> بشكل صحيح.</p><p>نحتاج بعد ذلك أيضًا إلى التأكّد من تمكين الوحدة <code>php5-mcrypt</code>، يُمكن فعل هذا عن طريق تنفيذ script يُدعى <code>php5enmod</code> باستخدام صدفة المهام shell task والتحقّق من وجود الملف <code>20-mcrypt.ini</code> في مكانه عند تمكينه، لاحظ أنّنا نخبر Ansible أنّ المهمّة تقوم بإنشاء ملف مُحدَّد، فإن كان هذا الملف موجودًا فلن يتم تشغيل المهمّة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">name: enable php5 mcrypt module
    shell: php5enmod mcrypt
    args:
      creates: /etc/php5/cli/conf.d/20-mcrypt.ini</pre><p>نفتح الآن الملف <code>php.yml</code> لتحريره مرّة أخرى:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">nano php.yml</pre><p>نضيف المهام والمداولات السابقة بحيث يتطابق الملف مع التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">---
- 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
</pre><p>نقوم أخيرًا بتشغيل playbook:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">ansible-playbook php.yml --ask-sudo-pass
</pre><p>يمتلك الآن الخادوم كافّة الحِزَم المطلوبة مُثبّتة عليه ومجموعة الإعدادات الأساسيّة جاهزة للانطلاق.</p><h2 id="الخاتمة">الخاتمة</h2><p>تحدثنا في القسم الأول من هذا الدّرس عن طريقة تثبيت Ansible وإعداد البيئة بشكل عام من أجل التحضير لعمليّة نشر تطبيق PHP بسيط باستخدام Ansible، وسنكمل في القسم الثاني <a href="https://academy.hsoub.com/devops/servers/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-php-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ansible-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-laravel-%D9%88nginx-r162/">الحصول على Laravel وإعداده وإعداد خادوم Nginx لتخديم تطبيق PHP</a>.</p><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-deploy-a-basic-php-application-using-ansible-on-ubuntu-14-04">How To Deploy a Basic PHP Application Using Ansible on Ubuntu 14.04</a> لصاحبه Stephen Rees-Carter.</p>
]]></description><guid isPermaLink="false">161</guid><pubDate>Tue, 29 Dec 2015 08:04:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x648;&#x625;&#x639;&#x62F;&#x627;&#x62F; Ansible &#x644;&#x623;&#x62A;&#x645;&#x62A;&#x629; &#x625;&#x62F;&#x627;&#x631;&#x629; &#x627;&#x644;&#x625;&#x639;&#x62F;&#x627;&#x62F;&#x627;&#x62A; &#x648;&#x646;&#x634;&#x631; &#x627;&#x644;&#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x639;&#x644;&#x649; &#x62E;&#x627;&#x62F;&#x648;&#x645; Ubuntu</title><link>https://academy.hsoub.com/devops/deployment/ansible/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-ansible-%D9%84%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-%D9%88%D9%86%D8%B4%D8%B1-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-ubuntu-r158/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-ubuntu.png.891ed7beb227366b63a51b000aebd8e5.png" /></p>

<p>تمّ تصميم أنظمة إدارة الإعدادات لتجعل التحكّم بعدد كبير من الخواديم أمرًا سهلًا لمديري الأنظمة وفرق العمليّات، فهي تسمح لنا بالتحكّم بالعديد من الأنظمة المختلفة بطريقة مؤتمتة من موقع مركزي واحد.</p><p>وبينما تتوافر العديد من أنظمة إدارة الإعدادات الشائعة من أجل أنظمة Linux، مثل Chef وPuppet، فهي غالبًا معقدة أكثر من حاجة الناس، تُشكّل <strong>Ansible</strong> بديلًا رائعًا لهذه الخيارات لأنّها تحتوي على عقبات أقل بكثير عند البدء معها.</p><p style="text-align: center;"><a href="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-ubuntu.png.14bb1cbd7da62aff0ea1c9915e8993d4.png" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="10247" src="https://academy.hsoub.com/uploads/monthly_2015_12/ansible-ubuntu.thumb.png.e188970474eba182d3b40050e10b470b.png" class="ipsImage ipsImage_thumbnailed" alt="ansible-ubuntu.thumb.png.e188970474eba18"></a></p><p>سنناقش في هذا الدّرس كيفيّة تثبيت Ansible على خادوم Ubuntu وسنمر على بعض الأساسيات حول كيفيّة استخدام هذه البرمجيّة.</p><h2 id="كيف-تعمل-ansible">كيف تعمل Ansible؟</h2><p>تعمل Ansible عن طريق إعداد أجهزة العملاء من خلال حاسوب يمتلك مكوّنات Ansible مثبّتة ومُعدّة عليه.</p><p>تتواصل عبر قنوات <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> الاعتياديّة من أجل استعادة المعلومات من الأجهزة عن بُعد remote، إصدار الأوامر، ونسخ الملفّات، ولهذا السبب لا يتطلّب نظام Ansible تثبيت أي برمجيّات إضافيّة على حواسيب العملاء.</p><p>هذه هي إحدى الطرق التي تُبسِّط فيها Ansible إدارة الخواديم، فيُمكِن إحضار أي خادوم يمتلك منفذ <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> مُعرَّض تحت مظلّة إعدادات Ansible بغض النظر عن الطور الذي يتواجد فيه ضمن دورة حياته.</p><p>أي حاسوب نستطيع إدارته عبر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> نستطيع أيضًا إدارته عبر Ansible.</p><p>تتخذ Ansible نهج الوحدات modules ممّا يجعل من السهل تمديدها كي تستخدم وظائف من النظام الأساسي للتعامل مع حالات محدّدة، يُمكِن كتابة الوحدات باستخدام أيّة لغة وهي تتخاطب بواسطة JSON المعياريّة.</p><p>إنّ ملفّات الإعدادات مكتوبة بشكل رئيسي بصيغة تسلسل البيانات YAML نظرًا لطبيعتها التعبيرية وتشابهها مع لغات الرقم markup الشائعة، تتمكن Ansible من التفاعل مع العملاء إمّا من خلال أداة سطر الأوامر أو عبر scripts للإعدادات تُدعى Playbooks.</p><h2 id="تثبيت-ansible-على-ubuntu">تثبيت Ansible على Ubuntu</h2><p>للبدء باستكشاف Ansible كوسيلة لإدارة خواديمنا المختلفة نحتاج إلى تثبيت برمجيّة Ansible على جهاز واحد على الأقل، سنستخدم خادوم Ubuntu من أجل هذا القسم.</p><p>إنّ أفضل طريقة للحصول على Ansible في Ubuntu هي إضافة PPA المشروع (أرشيف الحِزَم الشخصية personal package archive) إلى نظامنا.</p><p>للقيام بذلك على نحو فعال نحتاج لتثبيت الحزمة <code>python-software-properties</code> والتي ستعطينا القدرة على العمل مع PPA بسهولة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo apt-get update
sudo apt-get install python-software-properties</pre><p>بعد أن يتم تثبيت الحزمة نستطيع إضافة Ansible PPA بكتابة الأمر التالي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo add-apt-repository ppa:rquillo/ansible
</pre><p>نضغط ENTER لقبول إضافة الـ PPA.</p><p>نحتاج بعدها لتحديث دليل حِزَم نظامنا بحيث يكون على دراية بالحِزَم المتوفرة في PPA، نستطيع بعدها تثبيت برمجيّة Ansible:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo apt-get update
sudo apt-get install ansible
</pre><p>نمتلك الآن كافّة البرمجيّات المطلوبة لإدارة خواديمنا من خلال Ansible.</p><h2 id="إعداد-مفاتيح-ssh">إعداد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr></h2><p>تتخاطب Ansible بالدرجة الأولى كما أشرنا سابقًا مع حواسيب العملاء عبر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>، وعلى الرغم من أنّها تمتلك القدرة على التعامل مع استيثاق <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> authentication مُعتمِد على كلمة السر فتساعد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> على إبقاء الأمور أبسط.</p><p>بإمكاننا إعداد مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> بطريقتين مختلفتين اعتمادًا على إذا ما كنّا نمتلك مسبقًا المفتاح الذي نريد استخدامه.</p><h3 id="1-إنشاء-زوج-مفاتيح-ssh-جديد">1- إنشاء زوج مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> جديد</h3><p>إن لم تكن تمتلك مسبقًا زوج مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> ترغب في استخدامه من أجل إدارة Ansible فبإمكانك إنشاء واحد الآن على خادوم Ansible.</p><p>سنقوم بإنشاء زوج مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> على خادوم Ansible من أجل استيثاقه مع المضيفين الذين يديرهم.</p><p>نقوم بإنشاء زوج مفاتيح RSA key-pair بكتابة ما يلي عن طريق المستخدم الذي نتحكّم بـ Ansible من خلاله:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ssh-keygen
</pre><p>سيتم سؤالنا عن تحديد موقع الملف لزوج المفاتيح التي تم إنشاؤها، عبارة سر passphrase، وتأكيد عبارة السّر، نضغط Enter في جميع هذه المراحل لقبول القيم الافتراضيّة.</p><p>ستكون المفاتيح الجديدة متاحة في دليل <code>~/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr></code> الخاص بالمستخدم، يُدعى المفتاح العام (والذي يمكننا مشاركته) بـ <code>id_rsa.pub</code>، يُدعى المفتاح الخاص (والذي نبقيه بأمان) بـ <code>id_rsa</code>.</p><p>نستطيع إضافتها إلى لوحة تحكّم DigitalOcean على سبيل المثال (إن كنت على Digital Ocean) للسماح لنا بتضمين مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> الخاص بنا في الخواديم الجديدة التي أنشأناها، سيسمح هذا لخادوم Ansible بالدخول إلى الخواديم الجديدة عبر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> فورًا بدون الحاجة لأي استيثاق آخر.</p><p>لفعل هذا نضغط على الرابط “<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> Keys” الموجود في قائمة التصفح على اليسار، نضغط في الشاشة الجديدة على زر “Add <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> Key” الموجود في الزاوية العلوية اليمنى:</p><p style="text-align: center;"><img alt="add_ssh.png" title="" src="https://assets.digitalocean.com/articles/basic_ansible/add_ssh.png"></p><p>ندخل الاسم الذي نريد ربطه مع هذا المفتاح في الحقل العلوي، ونكتب على خادوم Ansible ما يلي للحصول على محتويات مفتاحنا العام:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">cat ~/.ssh/id_rsa.pub
</pre><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzmGgsqjSFuOBbjZB1sgquKpp3Ty+FgqoLrzjKbbk9VGOH6kM37aAhyxxmTQfe69lhYi/WCai+mrXOyY9IiQbUfZ4jsfPE9DS3zHhmnGiBWA7pedCTJ/Nhf06dmhAJIbExW3uDghbPbzbSA5Ihn1x0F5FXtSMDoFtyjcwUwJxc2z/kk9TKcFSl8qqf4IYBYE7c+EKaYRBjjDP4AQmiwjTPuipsmub7C0OGF0dTMatIa0lok6rwy91nmhCQV6polG0+Fsk4YrY8Yh5xz6wE0lOvc8BwP9nL0zsnw6Ey0MHV9BbMqtyD6x/fCurpIkMHJK4nv79rToSWA0AwoP/bJXh7 demo@ansible0
</pre><p>السلسلة النصية التي تعود لنا هي التي نحتاج لصقها في الحقل الثاني في لوحة تحكّم DigitalOcean:</p><p style="text-align: center;"><img alt="ansible_key.png" title="" src="https://assets.digitalocean.com/articles/basic_ansible/ansible_key.png"></p><p>نضغط على “Create <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> Key” لإضافة مفتاحنا إلى لوحة التحكم، نستطيع الآن تضمين مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> العام إلى الخواديم الجديدة التي نضيفها مما يسمح لنا بالتواصل مع خادوم Ansible، نحتاج فقط إلى اختيار المفتاح في القسم “Add optional <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> Keys” من عملية إنشاء خادوم جديد:</p><p style="text-align: center;"><img alt="embed_key.png" title="" src="https://assets.digitalocean.com/articles/basic_ansible/embed_key.png"></p><h3 id="2-نقل-زوج-مفاتيح-ssh-موجود-إلى-ansible">2- نقل زوج مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> موجود إلى Ansible</h3><p>إن كنت تمتلك مسبقًا زوج مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> تريد استخدامه من أجل الاستيثاق مع خواديمك فبإمكانك نقل الإعتمادات credentials إلى خادوم Ansible الجديد بدلًا من إنشاء زوج جديد، يمتلك هذا ميّزة بأن يجعلها تعمل تلقائيًّا مع أي خواديم قمت بإعدادها مسبقًا لتستخدم هذا المفتاح.</p><p>وعلى الحاسوب الآخر حيث قمنا بإعداد استيثاق مفتاح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من أجل الخواديم نحصل على المفتاح العام بكتابة ما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">cat ~/.ssh/id_rsa.pub
</pre><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzmGgsqjSFuOBbjZB1sgquKpp3Ty+FgqoLrzjKbbk9VGOH6kM37aAhyxxmTQfe69lhYi/WCai+mrXOyY9IiQbUfZ4jsfPE9DS3zHhmnGiBWA7pedCTJ/Nhf06dmhAJIbExW3uDghbPbzbSA5Ihn1x0F5FXtSMDoFtyjcwUwJxc2z/kk9TKcFSl8qqf4IYBYE7c+EKaYRBjjDP4AQmiwjTPuipsmub7C0OGF0dTMatIa0lok6rwy91nmhCQV6polG0+Fsk4YrY8Yh5xz6wE0lOvc8BwP9nL0zsnw6Ey0MHV9BbMqtyD6x/fCurpIkMHJK4nv79rToSWA0AwoP/bJXh7 demo@ansible0</pre><p>نحتاج على خادوم Ansible إلى إنشاء دليل مخفي لتخزين المفاتيح، نقوم بتسميته <code>.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr></code> كي يعلم برنامج <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> أين يجده:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">mkdir ~/.ssh
</pre><p>نقوم بقفل النفاذ إلى هذا الدليل لكي نتمكن نحن فقط من دخوله أو الكتابة إليه:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">chmod 700 ~/.ssh
</pre><p>ننتقل الآن إلى الدليل ونفتح ملفًّا يُدعى <code>id_rsa.pub</code> باستخدام محرّر النصوص:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">cd ~/.ssh
nano id_rsa.pub</pre><p>نلصق خَرْج مفتاحنا العام من حاسوبنا الرئيسي إلى هذا الملف:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDzmGgsqjSFuOBbjZB1sgquKpp3Ty+FgqoLrzjKbbk9VGOH6kM37aAhyxxmTQfe69lhYi/WCai+mrXOyY9IiQbUfZ4jsfPE9DS3zHhmnGiBWA7pedCTJ/Nhf06dmhAJIbExW3uDghbPbzbSA5Ihn1x0F5FXtSMDoFtyjcwUwJxc2z/kk9TKcFSl8qqf4IYBYE7c+EKaYRBjjDP4AQmiwjTPuipsmub7C0OGF0dTMatIa0lok6rwy91nmhCQV6polG0+Fsk4YrY8Yh5xz6wE0lOvc8BwP9nL0zsnw6Ey0MHV9BbMqtyD6x/fCurpIkMHJK4nv79rToSWA0AwoP/bJXh7 demo@ansible0
</pre><p>نقوم بحفظ وإغلاق الملف، ونتحقّق من امتلاكه للأذونات الصحيحة بكتابة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">chmod 644 id_rsa.pub
</pre><p>الآن وبالعودة إلى حاسوبنا المحلّي المضبوط من أجل نفاذ مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> نكتب:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">cat ~/.ssh/id_rsa</pre><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">    -----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-----
</pre><p>سيكون الخَرْج طويلًا جدًّا.</p><p>نعود الآن إلى خادوم Ansible، نحتاج إلى إنشاء ملف جديد في الدليل <code>~/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr></code>:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">nano id_rsa
</pre><p>نقوم بداخله بلصق نتائج الأمر السابق على حاسوبنا المحلّي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">-----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-----
</pre><p>نتأكّد من تضمين أسطر التحديد الموجودة في البداية والنهاية، فهي مطلوبة لكي يكون ملف المفتاح صالحًا، نحفظ الملف ونغلقه.</p><p>نحتاج لتغيير الأذونات لإبقاء هذا الملف بأمان:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">chmod 600 id_rsa
</pre><p>ستكون Ansible عند هذه النقطة قادرة على استخدام مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> هذه من أجل التواصل مع أي خادوم يمتلك المفتاح مُضمَّنًا عليه.</p><h2 id="إعداد-مضيفي-ansible">إعداد مضيفي Ansible</h2><p>تقوم Ansible بتتبّع جميع الخواديم التي يعلم عنها عن طريق ملف المضيفين “hosts”، نحتاج إلى إعداد هذا الملف أوّلًا قبل أن نتمكّن من بدء التواصل مع حواسيبنا الأخرى.</p><p>نفتح الملف مع صلاحيّات جذريّة root كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo nano /etc/ansible/hosts
</pre><p>سنرى ملفًّا يمتلك الكثير من أمثلة الإعدادات، وسيعمل أيّ منها لدينا فعليًّا، لذلك من أجل البدء نقوم بتعليق كافّة أسطر هذا الملف بإضافة “#” قبل كل سطر.</p><p>سنبقي هذه الأمثلة في هذا الملف لتساعدنا في الإعداد إن أردنا تنفيذ حالات أكثر تعقيدًا في المستقبل.<br>بعد أن يتم تعليق كافّة الأسطر نستطيع البدء بإضافة المضيفين الفعليين لدينا.</p><p>يكون ملف المضيفين مرنًا إلى حدٍّ ما ويمكن إعداده بعدّة طرق مختلفة، تبدو الصياغة التي سنستخدمها كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">[group_name]
alias ansible_ssh_host=server_ip_address
</pre><p>إنّ group_name هو وسم تنظيمي يسمح لنا بالإشارة لأي من الخواديم المدرجة بكلمة واحدة، الكنية هي مجرّد اسم للإشارة إلى ذلك الخادوم.</p><p>لذا نتخيل في حالتنا أننا نمتلك ثلاثة خواديم نريد إعدادها مع Ansible، تكون هذه الخواديم قابلة للوصول من خلال خادوم Ansible بكتابة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ssh root@server_ip_address
</pre><p>لن يتم سؤالنا عن كلمة سر إن أعددنا هذا بشكل صحيح، سنفترض أنّ عناوين IP لخواديمنا هي <code>192.0.2.1</code>، <code>192.0.2.2</code>، و<code>192.0.2.3</code>، سنقوم بإعداد هذا بحيث نستطيع الإشارة إليها بشكل مفرد كـ <code>host1</code>، <code>host2</code>، و<code>host3</code>، أو كمجموعة باسم <code>servers</code>.</p><p>هذه هي الكتلة التي ينبغي إضافتها إلى ملف المضيفين من أجل تحقيق هذا:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">[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
</pre><p>يمكن للمضيفين أن يكونوا ضمن مجموعات متعدّدة، وتستطيع المجموعات إعداد مُعامِلات parameters من أجل كل أعضائها، فلنجرّب هذا الآن.</p><p>إن حاولنا مع إعداداتنا الحاليّة الاتصال بأي من المضيفين عن طريق Ansible فسيفشل الأمر (بافتراض أنّك لا تعمل عن طريق المستخدم الجذري root)، يحدث هذا لأنّه تم تضمين مفاتيح <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr> من أجل المستخدم الجذري على الأنظمة البعيدة وستحاول Ansible الاتصال بشكل افتراضي بواسطة المستخدم الحالي، ستعطينا محاولة الاتصال هذا الخطأ:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">host1 | FAILED =&gt; 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
</pre><p>نستخدم على خادوم Ansible مستخدمًا يُدعى <code>demo</code>، ستحاول Ansible الاتصال إلى كل مضيف باستخدام <code><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> demo@server</code>، لن يعمل هذا إن كان المستخدم demo غير موجود على النظام البعيد.</p><p>نستطيع إنشاء ملف يُخبِر جميع الخواديم في المجموعة servers بالاتصال عن طريق المستخدم الجذري root.<br>لفعل هذا نقوم بإنشاء دليل في بنية إعدادات Ansible يُدعى <code>group_vars</code>، ونستطيع ضمن هذا المجلّد إنشاء ملفّات مُنسّقة عن طريق YAML لكل مجموعة نريد إعدادها:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">sudo mkdir /etc/ansible/group_vars
sudo nano /etc/ansible/group_vars/servers</pre><p>بإمكاننا وضع إعداداتنا هنا، تبدأ ملفّات YAML بـ “—” لذا تأكّد ألّا تنسى ذلك الجزء:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">---
ansible_ssh_user: root</pre><p>نحفظ الملف ونغلقه عند الانتهاء.</p><p>إن أردنا تحديد تفاصيل الإعدادات لكل خادوم بغض النظر عن مجموعته المرتبط بها فبإمكاننا وضع هذه التفاصيل في ملف في المسار <code>/etc/ansible/group_vars/all</code>، يمكن إعداد المضيفين بشكل مفرد بواسطة إنشاء ملفّات في دليل في المسار <code>/etc/ansible/host_vars</code>.</p><h2 id="استخدام-أوامر-ansible-بسيطة">استخدام أوامر Ansible بسيطة</h2><p>الآن بعد أن قمنا بإعداد المضيفين وضبطنا تفاصيل الإعدادات بشكلٍ كافٍ للسماح لنا بالاتصال بنجاح إلى مضيفينا، فبإمكاننا تجربة الأمر الأول لنا.</p><p>نقوم بعمل ping لكل الخواديم التي أعددناها عن طريق كتابة:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible -m ping all</pre><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">host1 | success &gt;&gt; {
    "changed": false,
    "ping": "pong"
}

host3 | success &gt;&gt; {
    "changed": false,
    "ping": "pong"
}

host2 | success &gt;&gt; {
    "changed": false,
    "ping": "pong"
}
</pre><p>وهو اختبار بسيط للتأكّد من امتلاك Ansible لاتصال مع كافّة مضيفيه.</p><p>تعني “all” كافّة المضيفين، وكان بإمكاننا بسهولة تحديد مجموعة كما يلي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible -m ping servers</pre><p>نستطيع أيضًا تحديد مضيف بشكل فردي:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible -m ping host1</pre><p>بإمكاننا تحديد عدّة مضيفين بفصلهم بواسطة نقطتين:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible -m ping host1:host2</pre><p>المقطع <code>-m ping</code> من الأمر هو تعليمة لـ Ansible كي تستخدم الوحدة “ping”، وهي بشكل مبسّط عبارة عن أوامر نستطيع تنفيذها على مضيفينا عن بُعد، تعمل الوحدة “ping” بعدّة طرق مثل أداة ping العاديّة في Linux، ولكن تقوم بدلًا من ذلك بالتحقّق من أجل اتصال Ansible.</p><p>لا تأخذ الوحدة ping فعليًّا أيّة مُعطيات arguments، ولكن بإمكاننا تجربة أمر آخر لنرى كيفيّة عمل ذلك، نقوم بتمرير المعطيات إلى script بكتابة <code>–a</code>.</p><p>تسمح لنا وحدة الصدفة “shell” بإرسال أمر طرفيّة terminal إلى المضيف البعيد واستعادة النتائج، على سبيل المثال لإيجاد استخدام الذاكرة على جهاز مضيفنا host1 نستطيع استخدام:</p><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html" style="text-align: left;">ansible -m shell -a 'free -m' host1
</pre><pre class="html ipsCode prettyprint" data-pbcktabsize="4" data-pbcklang="html">host1 | success | rc=0 &gt;&gt;
             total       used       free     shared    buffers     cached
Mem:          3954        227       3726          0         14         93
-/+ buffers/cache:        119       3834
Swap:            0          0          0

</pre><h2 id="الخاتمة">الخاتمة</h2><p>ينبغي أن تمتلك الآن خادوم Ansible مضبوطًا للتواصل مع الخواديم التي ترغب بالتحكم بها، تحقّقنا قدرة Ansible على التواصل مع كل مضيف واستخدمنا الأمر <code>ansible</code> لتنفيذ مهام بسيطة عن بُعد.</p><p>وعلى الرغم من أنّ هذا مفيد لنا، لم نقم بتغطية أقوى ميّزة في Ansible في هذا الدّرس وهي الـ Playbooks، لقد قمنا بإعداد أساس رائع من أجل العمل مع خواديمنا من خلال Ansible، ولكن الجزء الأكبر سيتم الحديث عنه في درس لاحق عند تغطية كيفيّة استخدام الـ Playbooks لأتمتة الإعدادات لحواسيبنا عن بُعد.</p><p>ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-ansible-on-an-ubuntu-12-04-vps">How to Install and Configure Ansible on an Ubuntu 12.04 VPS</a> لصاحبه Justin Ellingwood.</p>
]]></description><guid isPermaLink="false">158</guid><pubDate>Sun, 27 Dec 2015 22:45:29 +0000</pubDate></item></channel></rss>
