Ansible 2.0 preview: роли, блоки и почему мы наконец перестали бояться 40 хостов
Ansible 2.0 preview переработал систему ролей и добавил блоки задач. Рассказываем как перешли с bash-скриптов на Ansible и что это изменило в работе команды.
Ansible 2.0 preview выпущен с переработанными roles, блоками задач и улучшенным callback API
На прошлой неделе вышел preview Ansible 2.0. Не финальный релиз, но достаточно функциональный чтобы пощупать что поменялось. А поменялось немало: переработанная система ролей, блоки задач с обработкой ошибок, новый callback API. Это хороший повод написать про то, куда мы вообще пришли с Ansible за последние полгода.
Откуда взялось 40 хостов в одном месте
В начале года написали как перевели провизионинг одного сервера в playbook. С тех пор этот подход распространился на весь парк клиентов на сопровождении. Сейчас под управлением Ansible - под сорок хостов: web-серверы, базы данных, мониторинг, инфраструктура.
До этого жили так: bash-скрипт на сервере, вики-страница с чеклистом, и живая память конкретного инженера. Когда серверов было десять - кое-как работало. Когда стало двадцать, тридцать - начались проблемы. Один хост настроен чуть иначе, потому что полгода назад Вася делал его руками и немного схитрил. Другой хост обновлён, а третий - нет, потому что чеклист обновили в вики, но руками прошлись не везде.
Ansible решил это не магией, а скукой: один инвентарь, один набор плейбуков, ansible-playbook -l all и смотришь что изменится прежде чем применить. Дрейф конфигурации стал видим.
Что изменилось с ролями в 2.0
В Ansible 1.9 роли уже существовали, но были довольно примитивными. В 2.0 preview переработали несколько вещей.
Зависимости ролей стали работать предсказуемее. Раньше если две роли зависели от одной общей роли, та выполнялась дважды. В 2.0 это починили: дублирования нет, общая роль применяется один раз. Звучит как мелочь - на практике это была реальная боль когда роль common делала что-то нежелательное при повторном запуске.
Блоки задач (block:) - это новинка 2.0, которой не было вообще. Теперь можно сгруппировать несколько тасков в блок, навесить на него общий when: и - самое важное - rescue: для обработки ошибок:
- block:
- name: установить nginx
yum: name=nginx state=present
- name: запустить nginx
service: name=nginx state=started
rescue:
- name: откат - удалить nginx
yum: name=nginx state=absent
when: ansible_distribution == "CentOS"
Это меняет как пишется логика с откатом. Раньше приходилось городить условия через ignore_errors и register, и в итоге получалась лапша. Блоки делают намерение читаемым.
Callback API переписан, но это больше для тех кто пишет плагины под Ansible. Нас это пока не касается.
Разделение ответственности: кто пишет что
Вот что реально изменилось в работе команды после перехода на роли.
Раньше плейбуки писал один человек - кто разбирался в Ansible лучше других. Остальные или не трогали, или ломали. Роли позволили разделить это по зонам ответственности.
Сетевые настройки - отдельная роль. Там живут конфиги интерфейсов, маршруты, firewall-правила. Человек который занимается сетью, знает эту роль и правит её. Он не лезет в роль postgresql и не должен.
Системная часть - другая роль. NTP, SSH-харденинг, пользователи, Zabbix-агент. Системный администратор отвечает за эту зону.
Приложения - отдельные роли под каждый стек. nginx, PHP, базы данных - каждое в своей роли с переменными под конкретного клиента через group_vars.
На практике это выглядит так: сетевик делает git pull, правит свою роль, запускает --check чтобы посмотреть что изменится, потом применяет. Системщик об этом не знает и его работу это не трогает. До ролей такого разграничения не было - всё было в одном большом плейбуке и любое изменение требовало координации.
Про CentOS 7 и роли
Пару недель назад писали про переход на CentOS 7.1 и про то что systemd ломает старые таски. С ролями это стало чище: в каждой роли есть tasks/main.yml который включает нужный файл в зависимости от дистрибутива:
- include: centos6.yml
when: ansible_distribution_major_version == "6"
- include: centos7.yml
when: ansible_distribution_major_version == "7"
Раньше эти ветвления были размазаны по одному большому файлу, и читать его было неприятно. Сейчас каждая версия ОС - отдельный файл внутри роли. Понятнее и проще поддерживать.
Где ещё спотыкаемся
2.0 - preview, и это чувствуется. Несколько модулей поменяли поведение, и плейбуки написанные под 1.9 надо проверять прежде чем переходить. Мы пока держим production на 1.9, 2.0 гоняем на тестовых стендах.
Есть вещи которые в ролях всё ещё неудобны: если роль хочет использовать файл из другой роли - начинаются пути-лабиринты. Ansible не даёт нормального способа сослаться на ресурсы соседней роли. Решается через общие переменные, но это костыль.
Ansible Galaxy с публичными ролями мы смотрим с осторожностью. Большинство ролей написано под авторские представления о структуре системы, и интегрировать их в свой инвентарь - отдельная работа. Проще написать свою на 80 строк чем адаптировать чужую на 400.
Итого
Сорок хостов конфигурируются из одного репозитория. Дрейф конфигурации виден, а не угадывается. Разные части команды работают независимо в своих зонах.
Ansible 2.0 добавляет блоки и чинит зависимости ролей - это приятные улучшения, а не революция. Финального релиза пока нет, ждём. Но направление правильное.