إدارة الإعدادات مع Ansible

الأدوار والمجموعات في Ansible

18 دقيقة الدرس 7 من 30

الأدوار والمجموعات في Ansible

عند حجم معيّن، يصبح الـ 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 للمعالجات، والإشارة إلى الملفات بمسارات نسبية داخل الدور:

# nginx_vhost/tasks/main.yml --- - name: تثبيت Nginx ansible.builtin.package: name: "{{ nginx_package_name }}" state: present notify: Reload nginx - name: التأكد من وجود مجلد إعدادات vhost ansible.builtin.file: path: "{{ nginx_vhost_dir }}" state: directory mode: "0755" - name: نشر إعدادات vhost ansible.builtin.template: src: vhost.conf.j2 # مسار نسبي داخل templates/ للدور dest: "{{ nginx_vhost_dir }}/{{ item.server_name }}.conf" owner: root group: root mode: "0644" validate: "nginx -t -c %s" # التحقق من الإعدادات قبل وضعها loop: "{{ nginx_vhosts }}" notify: Reload nginx - name: إدارة شهادات TLS ansible.builtin.include_tasks: tls.yml when: nginx_tls_enabled | bool # nginx_vhost/defaults/main.yml --- nginx_package_name: nginx nginx_vhost_dir: /etc/nginx/conf.d nginx_vhosts: [] nginx_tls_enabled: false # nginx_vhost/handlers/main.yml --- - name: Reload nginx ansible.builtin.service: name: nginx state: reloaded

استدعاء دور من playbook

يُستدعى الأدوار بمفتاح 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 roles and collections dependency diagram Ansible Collection: myorg.platform Roles common OS hardening nginx_vhost depends on common postgres HA replica setup datadog_agent monitoring vault_agent secrets sidecar Modules & Plugins myorg_deploy custom module vault_lookup lookup plugin inventory_aws inventory plugin filter_semver filter plugin Playbooks site.yml, teardown.yml
تحزم مجموعة 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:

# إنشاء هيكل مجموعة جديدة ansible-galaxy collection init myorg.platform # الهيكل الناتج: myorg/ └── platform/ ├── galaxy.yml # بيان المجموعة (الاسم، الإصدار، الاعتماديات) ├── README.md ├── roles/ # الأدوار هنا — نفس هيكل الأدوار المستقلة │ ├── common/ │ ├── nginx_vhost/ │ └── postgres/ ├── plugins/ │ ├── modules/ # وحدات Python مخصّصة │ ├── lookup/ # إضافات lookup │ ├── filter/ # إضافات filter │ └── inventory/ # إضافات inventory ديناميكية ├── playbooks/ │ └── site.yml └── tests/ └── integration/ # galaxy.yml — بيان المجموعة namespace: myorg name: platform version: 2.1.0 readme: README.md description: "مجموعة Ansible لهندسة Platform" license: - Apache-2.0 authors: - Platform Engineering <platform@example.com> dependencies: amazon.aws: ">=7.0.0" community.hashi_vault: ">=6.0.0" # بناء ونشر المجموعة ansible-galaxy collection build # ينشئ myorg-platform-2.1.0.tar.gz ansible-galaxy collection publish myorg-platform-2.1.0.tar.gz \ --server https://hub.internal.example.com \ --api-key "${AUTOMATION_HUB_TOKEN}"

استخدام محتوى المجموعة في الـ Playbooks

بعد التثبيت، أشر إلى محتوى المجموعة بالاسم المؤهل الكامل (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 — كيفية تشفير المتغيرات الحساسة وإدارة الأسرار حتى لا تظهر بيانات الاعتماد كنص عادي في مستودعك.