عند حجم معيّن، يصبح الـ playbook المسطّح غير قابل للإدارة. ملف site.yml واحد يُنشر طبقة الويب ويُهيّئ عنقود قاعدة البيانات ويُعدّ وكلاء المراقبة ويُدير شهادات TLS ليس infrastructure-as-code — بل هو مخاطرة صيانة. يحلّ Ansible هذه المشكلة بـالأدوار (roles): تخطيط مجلد معياري يحوّل وحدة تهيئة منطقية (خادم ويب، نسخة Postgres، وكيل Vault) إلى قطعة مستقلة وقابلة لإعادة الاستخدام والاختبار. وعلى نطاق أوسع، تحزم المجموعات (collections) الأدوار والوحدات والإضافات معاً حتى تتمكّن الفرق من توزيع حزم القدرات الكاملة بشكل إصدارات عبر Ansible Galaxy أو Automation Hub خاص.
يُغطّي هذا الدرس كيفية بناء الأدوار بشكل صحيح، واستهلاك المجموعات ونشرها، ومعايير إعادة الاستخدام التي تُميّز الكود الذي يصمد عبر تغييرات الفريق من الكود الذي لا يفهمه إلا مؤلفه.
هيكل مجلد الدور
كل دور يتبع اصطلاحاً يفرضه Ansible بنفسه. تنفيذ ansible-galaxy role init myrole يُنشئ الهيكل التلقائي:
# إنشاء هيكل دور جديد
ansible-galaxy role init nginx_vhost
# الهيكل الناتج:
nginx_vhost/
├── defaults/
│ └── main.yml # متغيرات افتراضية منخفضة الأولوية (قابلة للتجاوز)
├── vars/
│ └── main.yml # متغيرات عالية الأولوية (غير مقصود تجاوزها)
├── tasks/
│ └── main.yml # نقطة دخول المهام — استخدم include_tasks للملفات الفرعية
├── handlers/
│ └── main.yml # معالجات تُفعَّل بـ notify:
├── templates/
│ └── vhost.conf.j2 # قوالب Jinja2
├── files/
│ └── mime.types # ملفات ثابتة تُنسخ كما هي
├── meta/
│ └── main.yml # بيانات وصفية: المؤلف، الرخصة، galaxy_info، الاعتماديات
├── tests/
│ ├── inventory # بيانات اختبار مبسّطة
│ └── test.yml # playbook للاختبار
└── README.md
defaults/ مقابل vars/ — الفرق الأكثر سوء فهماً في Ansible. المتغيرات في defaults/main.yml ذات أدنى أولوية وتهدف إلى التجاوز من متغيرات inventory أو group_vars أو host_vars أو vars في الـ playbook. أما متغيرات vars/main.yml فلها أولوية عالية جداً — لا يمكن تجاوزها إلا من سطر الأوامر عبر -e أو set_fact. استخدم defaults/ للمعاملات القابلة للضبط (المنافذ، إصدارات الحزم، المسارات). استخدم vars/ للثوابت الداخلية للدور التي لا ينبغي للمستدعي الاقتراب منها.
دور احترافي جاهز للإنتاج: nginx_vhost
فيما يلي مثال على ملف مهام دور مكتمل جاهز للإنتاج، يُوضّح include_tasks للملفات الفرعية، وnotify للمعالجات، والإشارة إلى الملفات بمسارات نسبية داخل الدور:
يُستدعى الأدوار بمفتاح roles: أو مهمة ansible.builtin.include_role. الأخير مفضّل حين تحتاج إلى تضمين الدور بشرط أو تمرير متغيرات ديناميكياً:
# site.yml — فصل واضح للمسؤوليات
---
- name: تهيئة طبقة الويب
hosts: web_servers
become: true
roles:
- role: common # يُطبَّق أولاً — تقوية نظام التشغيل الأساسي
- role: nginx_vhost # دور بمتغيراته الافتراضية
vars: # تجاوز الافتراضيات لهذا الـ play
nginx_tls_enabled: true
nginx_vhosts:
- server_name: api.example.com
upstream: "127.0.0.1:8080"
- role: datadog_agent # المراقبة
# تضمين دور ديناميكي بـ include_role
- name: إضافة Redis بشرط
ansible.builtin.include_role:
name: redis
when: "'cache_servers' in group_names"
vars:
redis_maxmemory: "{{ ansible_memtotal_mb // 2 }}mb"
اعتماديات الأدوار وملف meta/main.yml
يمكن للدور الإعلان عن أدوار أخرى كاعتماديات في meta/main.yml. يضمن Ansible تطبيق الاعتماديات قبل الدور المعتمد عليها. هذا هو الأسلوب الصحيح لنمذجة "يتطلّب دور التطبيق دور التقوية المشترك":
# nginx_vhost/meta/main.yml
---
galaxy_info:
role_name: nginx_vhost
author: platform-eng
description: إدارة vhosts لـ Nginx مع TLS
license: Apache-2.0
min_ansible_version: "2.14"
platforms:
- name: Ubuntu
versions: ["22.04", "24.04"]
- name: EL
versions: ["9"]
galaxy_tags:
- nginx
- web
- tls
dependencies:
- role: common
vars:
common_firewall_ports:
- 80
- 443
تحزم مجموعة Ansible الأدوار والوحدات المخصّصة والإضافات والـ playbooks معاً في وحدة توزيع واحدة ذات إصدار.
مجموعات Ansible
المجموعة (Collection) هي وحدة التوزيع لمحتوى Ansible. حيث يحلّ الدور مشكلة تشغيلية واحدة، تحلّ المجموعة مجالاً كاملاً — كل الأدوار والوحدات المخصّصة وإضافات inventory وإضافات lookup والـ playbooks التي يحتاجها الفريق لإدارة حزمة تقنية. يُوزّع مجتمع Ansible مجموعات لـ AWS (amazon.aws) وKubernetes (kubernetes.core) وHashiCorp Vault (community.hashi_vault) والمئات غيرها. يُوزّع فريق Platform الداخلي مجموعته الخاصة (myorg.platform) من Automation Hub خاص أو من مستودع Git.
# تثبيت مجموعة من Ansible Galaxy
ansible-galaxy collection install community.hashi_vault
# تثبيت إصدار محدد
ansible-galaxy collection install amazon.aws:==7.3.0
# تثبيت من Automation Hub خاص
ansible-galaxy collection install myorg.platform:==2.1.0 \
--server https://hub.internal.example.com \
--api-key "${AUTOMATION_HUB_TOKEN}"
# تثبيت من مستودع Git مباشرة (مفيد أثناء التطوير)
ansible-galaxy collection install \
git+https://github.com/myorg/ansible-collection-platform.git,main
# استخدام requirements.yml لتثبيت قابل للتكرار في CI/CD
ansible-galaxy collection install -r requirements.yml
# requirements.yml
---
collections:
- name: amazon.aws
version: "7.3.0"
- name: community.hashi_vault
version: "6.2.0"
- name: community.general
version: ">=9.0.0,<10.0.0"
- name: myorg.platform
source: https://hub.internal.example.com
version: "2.1.0"
roles:
- name: geerlingguy.docker
version: "7.4.0"
بناء مجموعة خاصة
بناء مجموعتك الخاصة يتبع هيكل namespace صارم. الـ namespace دائماً org_name.collection_name:
بعد التثبيت، أشر إلى محتوى المجموعة بالاسم المؤهل الكامل (FQCN). استخدام FQCNs في كل مكان — ليس فقط أسماء الوحدات المختصرة — ضرورة صارمة على النطاق الكبير لأنه يُزيل الغموض حين توفّر مجموعات متعددة وحدات بأسماء متطابقة:
# استخدم دائماً FQCN في playbooks الإنتاج
- name: إنشاء S3 bucket
amazon.aws.s3_bucket:
name: myorg-artifacts
region: us-east-1
versioning: true
- name: قراءة سرّ من Vault
community.hashi_vault.hashi_vault_kv2_get:
path: secret/data/app/db_password
url: "{{ vault_addr }}"
auth_method: aws_iam
role_id: "{{ vault_role_id }}"
register: db_creds
- name: تطبيق دور من المجموعة الداخلية
ansible.builtin.include_role:
name: myorg.platform.nginx_vhost # FQCN للأدوار أيضاً
vars:
nginx_tls_enabled: true
# ansible.cfg — ضبط مسار المجموعات لعزل المشروع
[defaults]
collections_path = ./collections:~/.ansible/collections
roles_path = ./roles:~/.ansible/roles
معيار إعادة الاستخدام في كبرى التقنية: أثبّت كل مجموعة خارجية على إصدار محدد في requirements.yml. استخدم بوتاً (Renovate أو Dependabot) لفتح PRs عند توفّر إصدارات جديدة، تماماً كما تفعل مع حزم Python أو Helm charts. لا تستخدم latest أو نطاقات غير مثبّتة في أي بيئة سوى النماذج الأوليّة السريعة — تسبّب تغيير مُكسِر في amazon.aws في تعطّل pipelines الإنتاج في عدة مؤسسات كبيرة.
اختبار الأدوار بـ Molecule
Molecule هو الأداة المعيارية لاختبار أدوار Ansible. تُشغّل حاوية أو آلة افتراضية، وتُطبّق دورك عليها، وتُنفّذ أدوات التحقق (Testinfra أو Ansible asserts) لإثبات أن الدور فعل ما يدّعي. كل دور في مجموعة إنتاجية يجب أن يكون له سيناريو Molecule:
# تثبيت Molecule مع مشغّل Docker
pip install molecule molecule-plugins[docker] ansible-lint
# تهيئة سيناريو Molecule لدور موجود
cd nginx_vhost/
molecule init scenario --driver-name docker
# molecule/default/molecule.yml
---
driver:
name: docker
platforms:
- name: instance
image: "geerlingguy/docker-ubuntu2404-ansible:latest"
pre_build_image: true
command: ""
privileged: false
provisioner:
name: ansible
playbooks:
converge: converge.yml
inventory:
host_vars:
instance:
nginx_tls_enabled: false
nginx_vhosts:
- server_name: test.example.com
upstream: "127.0.0.1:8080"
verifier:
name: ansible
# molecule/default/verify.yml — تأكيدات Ansible الأصيلة
---
- name: التحقق
hosts: all
gather_facts: false
tasks:
- name: التحقق من تشغيل Nginx
ansible.builtin.service_facts:
- name: التأكد من تفعيل Nginx
ansible.builtin.assert:
that: ansible_facts.services['nginx.service'].state == 'running'
- name: التحقق من وجود إعدادات vhost
ansible.builtin.stat:
path: /etc/nginx/conf.d/test.example.com.conf
register: vhost_file
- name: التأكد من وجود ملف الإعدادات
ansible.builtin.assert:
that: vhost_file.stat.exists
# تشغيل دورة اختبار Molecule الكاملة
molecule test # create → converge → idempotence → verify → destroy
molecule converge # تطبيق الدور فقط (تكرار سريع)
molecule verify # تشغيل التأكيدات فقط
مخاطرة إنتاجية — فحص الـ idempotence: يُشغّل Molecule دورك مرتين افتراضياً ويقارن المخرجات. إن أبلغت المرة الثانية عن أي مهام changed، يُفشل Molecule السيناريو. يكشف هذا أكثر أخطاء تأليف الأدوار شيوعاً: مهام تدّعي دائماً إجراء تغيير حتى حين يكون النظام في الحالة المطلوبة. أصلح أخطاء الـ idempotence بإضافة creates: على مهام command، أو استخدام changed_when: false حين لا تُعدّل المهمة الحالة فعلاً، أو إعادة كتابتها باستخدام وحدة Ansible idempotent بدلاً من أمر shell خام.
معايير إعادة استخدام الأدوار على نطاق واسع
الاصطلاحات التالية مُطبَّقة في فرق Platform في كبرى التقنية التي تُدير مجموعات تخدم مئات المهندسين:
دور واحد، مسؤولية واحدة. الدور يُهيّئ تقنية أو مسؤولية تشغيلية واحدة. الدور المسمى app_server الذي يُثبّت Nginx وينشر كود التطبيق ويُهيّئ Redis ويُعدّ مهام cron هو أربعة أدوار لم تُفصَل قط. حين يحتاج فريق Redis تغيير إعدادات Redis، لا يجب أن يلمس دوراً يملك Nginx.
جميع المتغيرات العامة موثّقة في defaults/main.yml بتعليقات داخلية. كل متغير يمكن للمستدعي ضبطه يجب أن يظهر في defaults/ مع تعليق يشرح غرضه ونوعه والقيم المسموح بها. المتغيرات غير الموثّقة أخطاء بالانتظار.
المهام تستخدم أسماء وحدات FQCN.ansible.builtin.copy، ليس copy. يجعل هذا واضحاً أي مجموعة توفّر الوحدة ويمنع الأعطال الصامتة حين تُظلّل وحدة مخصّصة وحدة مدمجة.
الأدوار تدعم الـ tags. أضف tags: ذات معنى لمجموعات المهام كي يستطيع المستدعون تشغيل المجموعة الفرعية التي يحتاجونها فقط: ansible-playbook site.yml --tags tls. ضع tag باسم الدور كـ tag أساسي لكل مهام الدور.
إصدار دلالي للمجموعات. زِد إصدار patch للإصلاحات، وإصدار minor للميزات الجديدة المتوافقة للخلف (دور جديد، متغير جديد)، وإصدار major للتغييرات المُكسِرة (متغير مُعاد تسميته، دور محذوف). عامِل changelog المجموعة مثل واجهة برمجية عامة.
إتقان الأدوار والمجموعات هو النقطة التي يتحوّل فيها Ansible من أداة scripting إلى قدرة منصّة. الدرس التالي يُغطّي Ansible Vault — كيفية تشفير المتغيرات الحساسة وإدارة الأسرار حتى لا تظهر بيانات الاعتماد كنص عادي في مستودعك.
نستخدم ملفات تعريف الارتباط لتشغيل هذا الموقع وتحليل الزيارات وعرض إعلانات مخصّصة. يمكنك قبول كل ملفات تعريف الارتباط أو رفض غير الأساسية منها.
سياسة الخصوصية