Розробка 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-test units | Юніт-тести модулів | Швидко | На кожен коміт |
| ansible-test sanity | Статичний аналіз | Швидко | Перед PR |
| ansible-test integration | Інтеграційні тести | Повільно | Перед релізом |
| Molecule | Тестування ролей | Середньо | Для ізольованих ролей |
Процес роботи
- Аналітика — визначаємо склад collection: які модулі, плагіни, залежності.
- Проектування — розробляємо структуру, інтерфейси модулів, тестові сценарії.
- Розробка — пишемо код модулів, плагінів, ролей.
- Тестування — unit, sanity, integration тести в CI.
- Деплой — публікація в приватний 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.







