Розробка Ansible Collections для модулів, що перевикористовуються

Коли стандартні модулі Ansible не справляються з нестандартними завданнями, ми розробляємо Ansible Collections — перевикористовувані пакети автоматизації. Наша команда створює кастомні модулі, inventory-плагіни та колекції під ключ, публікуючи їх в Ansible Galaxy або automation hub. Результат — надійні рішення, які версіонуються, тестуються та масштабуються разом з вашим бізнесом.
Часті запитання

Розробка Ansible Collections для модулів, що перевикористовуються

Ми часто стикаємося з ситуацією, коли стандартні модулі Ansible не покривають потреби проєкту: потрібно інтегруватися з внутрішнім API, додати нестандартне джерело інвентарю або поширити набір автоматизації між командами. У таких випадках ми розробляємо Ansible Collections — пакети, які можна версіонувати, тестувати та публікувати незалежно від Ansible Core. За роки практики ми реалізували понад 50 проєктів з кастомними колекціями — від простих модулів до повноцінних inventory-плагінів для внутрішніх CMDB.

Collections з'явилися в Ansible 2.9 як відповідь на хаос з просторами імен та версіонуванням. До collections все було в одному репозиторії: модулі для AWS, GCP, VMware жили поруч з базовими та оновлювалися разом з Core. Collection — це пакет, що містить ролі, плагіни, модулі та фільтри, з незалежним циклом релізу. Зараз це стандарт де-факто для поширення Ansible-контенту.

Які проблеми вирішуємо

  • Кастомні модулі. Стандартного модуля для API вашого сервісу немає? Пишемо модуль, який взаємодіє з REST API, обробляє помилки, підтримує check mode. Приклад: модуль реєстрації хоста в NetBox (див. нижче) замінює 50+ рядків bash-скрипта, працює в 10 разів швидше та безпечніше (токен не світиться в логах).
  • Inventory-плагіни. Джерело даних (AD, OpenStack, власний CMDB) не підтримується community.general? Розробляємо плагін, який підвантажує інвентар динамічно — без скриптів-обгорток і костилів.
  • Уніфікація контенту. Ролі, модулі та фільтри розкидані по git-репозиторіях? Збираємо їх в collection з єдиним versioning та залежностями — спрощуємо on-boarding нових інженерів.

Як влаштована структура Ansible Collection?

ansible-galaxy collection init mycompany.infrastructure 

Створюється структура:

mycompany/infrastructure/
├── galaxy.yml # метадані, версія, залежності
├── README.md
├── plugins/
│   ├── modules/ # кастомні модулі
│   ├── inventory/ # inventory-плагіни
│   ├── filter/ # Jinja2 фільтри
│   └── lookup/ # lookup-плагіни
├── roles/
│   ├── hardening/
│   └── monitoring/
└── playbooks/

galaxy.yml:

---
namespace: mycompany
name: infrastructure
version: 1.2.0
description: Internal infrastructure automation collection
authors:
  - DevOps Team <[email protected]>
dependencies:
  community.general: ">=7.0.0"
  ansible.posix: ">=1.5.0"
---

Чому варто використовувати кастомні модулі замість скриптів?

Кастомний модуль — це Python-скрипт з AnsibleModule. На відміну від shell- або command-задач, модуль:

  • підтримує check mode (idempotent preview);
  • повертає структуровані дані (result) для використання в наступних задачах;
  • логує чутливі параметри (no_log) безпечно;
  • інтегрується з Ansible-тестуванням.

Приклад модуля для реєстрації хоста в NetBox:

# plugins/modules/netbox_register.py
from ansible.module_utils.basic import AnsibleModule
import requests

DOCUMENTATION = r'''
module: netbox_register
short_description: Register host in NetBox CMDB
options:
    hostname:
        description: Hostname to register
        required: true
    ip_prefix:
        description: IP prefix to allocate from (e.g. 10.20.30.0/24)
        required: true
    netbox_url:
        description: NetBox URL
        required: true
    netbox_token:
        description: NetBox API token
        required: true
        no_log: true
'''

def run_module():
    module_args = dict(
        hostname=dict(type='str', required=True),
        ip_prefix=dict(type='str', required=True),
        netbox_url=dict(type='str', required=True),
        netbox_token=dict(type='str', required=True, no_log=True),
    )

    result = dict(changed=False, ip_address=None)
    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    headers = {'Authorization': f"Token {module.params['netbox_token']}"}
    nb_url = module.params['netbox_url']

    # Перевіряємо, чи не зареєстрований вже
    resp = requests.get(
        f"{nb_url}/api/ipam/ip-addresses/",
        params={'dns_name': module.params['hostname']},
        headers=headers
    )
    if resp.json()['count'] > 0:
        result['ip_address'] = resp.json()['results'][0]['address']
        module.exit_json(**result)

    if module.check_mode:
        result['changed'] = True
        module.exit_json(**result)

    # Виділяємо IP з prefix
    prefix_resp = requests.get(
        f"{nb_url}/api/ipam/prefixes/",
        params={'prefix': module.params['ip_prefix']},
        headers=headers
    )
    prefix_id = prefix_resp.json()['results'][0]['id']

    ip_resp = requests.post(
        f"{nb_url}/api/ipam/prefixes/{prefix_id}/available-ips/",
        json={'dns_name': module.params['hostname'], 'status': 'active'},
        headers=headers
    )
    result['changed'] = True
    result['ip_address'] = ip_resp.json()['address']
    module.exit_json(**result)

def main():
    run_module()

if __name__ == '__main__':
    main()

Використання в playbook:

---
- name: Register server in NetBox
  mycompany.infrastructure.netbox_register:
    hostname: "{{ inventory_hostname }}"
    ip_prefix: "10.20.30.0/24"
    netbox_url: "https://netbox.internal"
    netbox_token: "{{ vault_netbox_token }}"
  register: netbox_result
- name: Set IP address fact
  set_fact:
    server_ip: "{{ netbox_result.ip_address | ansible.utils.ipaddr('address') }}"

Порівняння: Collection vs Role

Критерій Role Collection
Область застосування Конфігурація одного сервісу Пакет модулів, плагінів, ролей
Кастомні модулі Ні Так, в plugins/modules
Inventory-плагіни Ні Так
Фільтри та lookup Ні Так
Версіонування Залежить від repo Незалежне, через galaxy.yml
Поширення Git clone Galaxy / Automation Hub

Як тестувати Ansible Collection?

Тестування — ключовий етап. Використовуємо три рівні:

  • Unit-тести (pytest з ansible-test units) — перевіряють логіку модулів та фільтрів на mock-даних.
  • Sanity-тести (ansible-test sanity) — валідують сумісність з Ansible API, PEP8, відсутність deprecated викликів.
  • Integration-тести (ansible-test integration) — розгортають тестову інфраструктуру (Docker або Vagrant) і перевіряють роботу модулів у реальному середовищі.

Приклад конфігурації CI в GitHub Actions:

---
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install ansible-core
      - run: ansible-test sanity --docker -v
      - run: ansible-test units --python 3.11 -v
      - run: ansible-test integration --docker -v

Ansible Testing Guide

Порівняння засобів тестування

Інструмент Призначення Швидкість Коли використовувати
ansible-test units Юніт-тести модулів Швидко На кожен коміт
ansible-test sanity Статичний аналіз Швидко Перед PR
ansible-test integration Інтеграційні тести Повільно Перед релізом
Molecule Тестування ролей Середньо Для ізольованих ролей

Процес роботи

  1. Аналітика — визначаємо склад collection: які модулі, плагіни, залежності.
  2. Проектування — розробляємо структуру, інтерфейси модулів, тестові сценарії.
  3. Розробка — пишемо код модулів, плагінів, ролей.
  4. Тестування — unit, sanity, integration тести в CI.
  5. Деплой — публікація в приватний Galaxy або Automation Hub, документування.

Що входить в роботу

  • Розробка 2-3 кастомних модулів (або плагінів) з документацією.
  • Створення galaxy.yml з залежностями та метаданими.
  • Налаштування CI (GitLab CI / GitHub Actions) з запуском тестів при кожному PR.
  • Публікація в приватний Galaxy-сервер або Automation Hub.
  • Передача вихідного коду та README.
  • Навчання команди використанню collection (1 година).
  • Гарантія сумісності з актуальними версіями Ansible (на момент здачі).

Строки орієнтовно

  • Collection з 2–3 модулями та базовими тестами — 3–5 днів.
  • Inventory-плагін для специфічного джерела — 2–3 дні.
  • Налаштування CI з публікацією — 1–2 дні.

Вартість розраховується індивідуально після аналізу ваших вимог. Зв'яжіться з нами — оцінимо проект за 1 робочий день.

Типові помилки при розробці Collections
  • Не включати check mode — порушує idempotency.
  • Зберігати чутливі параметри без no_log.
  • Забути про sanity-тести перед публікацією (Ansible Galaxy вимагає їх проходження).
  • Версіонувати колекцію не семантично (дотримуйтесь SemVer).
  • Не вказувати залежності в galaxy.yml — collection не збереться на чистому середовищі.

Розробка Ansible Collections — це спосіб стандартизувати та прискорити автоматизацію, знижуючи operational costs на 30-50%. Замовте розробку колекції під ваші завдання — отримайте готовий пакет з тестами та CI.

Наші компетенції:

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1142