Разработка роли Ansible: создание с нуля

Рейтинг: 45.3% · 9 голосов
Подробный курс по Ansible с прицелом на экзамен RHCE EX294: установка и инвентарь, плейбуки, переменные и факты, Vault, циклы и условия, шаблоны Jinja2, роли и коллекции, Execution Environments и ansible-navigator, управление системами (диски, LVM, cron, SELinux, firewalld). Примеры на RHEL/Fedora. Актуально на 2026.
Ответить
Аватара пользователя
Maksim_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Разработка роли Ansible: создание с нуля

Сообщение Maksim_DevOps »

Оглавление курса (47)
  1. Что такое Ansible и зачем он нужен: автоматизация без агентов
  2. Сертификация RHCE и экзамен EX294: что внутри и как готовиться
  3. Архитектура Ansible: control node, узлы, модули и плагины
  4. Установка Ansible на control node: dnf, pip и версии ansible-core
  5. Подготовка управляемых узлов: SSH, пользователь и sudo
  6. Инвентарь Ansible: hosts, группы и переменные
  7. Настройка Ansible: файл ansible.cfg и приоритеты конфигурации
  8. Host patterns и инструменты командной строки Ansible
  9. Ad hoc команды Ansible: быстрые задачи без плейбука
  10. Ansible playbook: что это такое и как устроен
  11. Структура плейбука: play, task, модули и переменные
  12. Запуск плейбуков: проверка, теги, ограничения и отладка
  13. Параллелизм и порядок выполнения: forks, serial, strategy
  14. Факты Ansible: сбор информации об узлах
  15. Переменные Ansible: типы, объявление и приоритет
  16. Регистрация результатов и специальные переменные
  17. Ansible Vault: шифрование паролей и секретов
  18. Организация инвентаря: group_vars, host_vars и вложенные группы
  19. Динамический инвентарь и инвентарные плагины
  20. Циклы в Ansible: loop, списки и словари
  21. Повтор задачи до условия: until, retries и delay
  22. Условия в Ansible: директива when и логика
  23. Jinja2 в Ansible: выражения, фильтры и подстановки
  24. Обработчики Ansible: handlers, notify и flush_handlers
  25. Обработка ошибок: failed_when, changed_when и ignore_errors
  26. Блоки в Ansible: block, rescue и always
  27. Управление файлами: модули file, copy, fetch и stat
  28. Архивы и сборка файлов: archive, unarchive, assemble
  29. Точечное редактирование файлов: lineinfile и blockinfile
  30. Шаблоны Jinja2: модуль template и динамические конфиги
  31. Jinja2 продвинуто: фильтры, циклы, макросы и lookup
  32. Модули Ansible: ansible-doc и поиск нужного модуля
  33. Разработка собственного модуля Ansible на Python
  34. Роли Ansible и Ansible Galaxy: переиспользование
  35. Разработка роли Ansible: создание с нуля (вы здесь)
  36. Зависимости ролей и requirements.yml
  37. Коллекции Ansible: ansible.posix, community и своя коллекция
  38. Execution Environments: контейнеры для запуска Ansible
  39. Сборка Execution Environment с ansible-builder
  40. ansible-navigator: запуск плейбуков в Execution Environment
  41. Управление SSH-ключами через Ansible: authorized_key
  42. Управление дисками: filesystem, mount и parted
  43. LVM через Ansible: тома, группы и расширение
  44. Планировщик задач: cron и systemd timers через Ansible
  45. Безопасность: hardening SSH и репозитории dnf/yum
  46. SELinux через Ansible: булевы, контексты и порты
  47. Сквозной проект и подготовка к экзамену EX294
Рано или поздно один плейбук на 300 строк превращается в болото. Установка пакета, шаблон конфига, открытие порта, запуск сервиса - и так для каждого приложения, всё свалено в одну простыню. Скопировал блок в другой проект - и поехали расхождения: тут отступ поправил, там переменную переименовал. Роль решает ровно эту боль. Это переносимый, параметризуемый кусок автоматизации с понятной структурой, который ты подключаешь одной строкой и переиспользуешь хоть на пяти проектах. В этом уроке разберём, как идёт разработка роли Ansible с нуля: от скелета до рабочей роли, которая ставит и настраивает веб-сервер.

Скелет роли: ansible galaxy init

Руками каталоги создавать не надо. Есть штатная команда, которая раскладывает структуру роли Ansible по канону:

Код: Выделить всё

ansible-galaxy role init webserver
Короткая форма ansible galaxy init тоже работает (role - подкоманда по умолчанию). Получаешь дерево:

Код: Выделить всё

webserver/
├── defaults/
│   └── main.yml
├── files/
├── handlers/
│   └── main.yml
├── meta/
│   └── main.yml
├── README.md
├── tasks/
│   └── main.yml
├── templates/
├── tests/
│   ├── inventory
│   └── test.yml
└── vars/
    └── main.yml
Если у тебя в проекте принято класть роли в отдельную папку - указывай путь явно:

Код: Выделить всё

ansible-galaxy role init --init-path roles/ webserver
. Чтобы Ansible нашёл роль автоматически, она должна лежать в roles/ рядом с плейбуком либо в одном из путей roles_path (смотри ansible.cfg).

Что за что отвечает, по делу:
  • tasks/main.yml - точка входа. Сюда Ansible идёт первым делом, когда подключаешь роль. Тут список задач.
  • defaults/main.yml - переменные по умолчанию с самым низким приоритетом. Их легко переопределить откуда угодно.
  • vars/main.yml - переменные роли с высоким приоритетом. Перебить их снаружи почти нечем.
  • templates/ - шаблоны Jinja2 (.j2). Модуль template ищет файлы тут.
  • files/ - статические файлы для copy. Имя файла указываешь без путей, Ansible подхватит из этой папки.
  • handlers/main.yml - обработчики, которые срабатывают по notify (перезапуск сервиса и т.п.).
  • meta/main.yml - метаданные: автор, лицензия, зависимости от других ролей, поддерживаемые платформы.
Пустые каталоги files/ и templates/ можно удалить, если не используешь - Galaxy создаёт их про запас.

Изображение

defaults против vars: где лежат переменные роли ansible

Это место, где спотыкаются почти все новички, и на экзамене за это тоже срезаются. Внешне defaults/main.yml и vars/main.yml одинаковые - оба задают переменные. Разница в приоритете.

ansible role defaults - это значения по умолчанию. Самый низкий приоритет во всей иерархии переменных. Их смысл: дать роли разумные настройки из коробки, которые пользователь роли спокойно переопределит - в инвентаре, в group_vars, в самом плейбуке при подключении роли. Сюда кладёшь всё, что хочешь дать менять снаружи: порт, имя пакета, корень сайта, версию.

vars/main.yml наоборот - переменные с высоким приоритетом. Их трудно перебить снаружи (только через -e в командной строке или include_vars). Сюда идёт то, что менять не положено: внутренние константы роли, маппинг "имя дистрибутива - имя пакета", служебные значения, от которых зависит логика самой роли.

Простое правило: если переменную предполагается настраивать снаружи - это defaults. Если это внутренняя кухня роли - это vars. Перепутаешь местами - и пользователь не сможет переопределить порт, потому что ты зашил его в vars с высоким приоритетом. Классические грабли.

Код: Выделить всё

# defaults/main.yml - пользователь это переопределит
web_package: httpd
web_service: httpd
web_port: 80
web_doc_root: /var/www/html
web_index_message: "Развёрнуто через Ansible"
Практика: роль установки и настройки веб-сервера

Собираем рабочую роль целиком. Задачи в tasks/main.yml - установка пакета, доставка шаблона конфига, открытие порта в firewalld, запуск сервиса. Обрати внимание: имена пакета/сервиса/порта берём из переменных - так роль параметризуется и переиспользуется.

Код: Выделить всё

# tasks/main.yml
- name: Установить веб-сервер
  ansible.builtin.dnf:
    name: "{{ web_package }}"
    state: present

- name: Развернуть главную страницу из шаблона
  ansible.builtin.template:
    src: index.html.j2
    dest: "{{ web_doc_root }}/index.html"
    owner: root
    group: root
    mode: "0644"
  notify: Перезапустить веб-сервер

- name: Открыть HTTP в firewalld
  ansible.posix.firewalld:
    service: http
    state: enabled
    permanent: true
    immediate: true

- name: Запустить и включить сервис
  ansible.builtin.service:
    name: "{{ web_service }}"
    state: started
    enabled: true
Шаблон templates/index.html.j2 - обычный HTML с подстановками Jinja2:

Код: Выделить всё

<html>
  <head><title>{{ ansible_facts['hostname'] }}</title></head>
  <body>
    <h1>{{ web_index_message }}</h1>
    <p>Хост: {{ ansible_facts['fqdn'] }}, порт {{ web_port }}</p>
  </body>
</html>
Handlers внутри роли. Обработчик в handlers/main.yml перезапускает сервис только если конфиг реально поменялся. Имя в notify должно совпадать с name хендлера символ в символ:

Код: Выделить всё

# handlers/main.yml
- name: Перезапустить веб-сервер
  ansible.builtin.service:
    name: "{{ web_service }}"
    state: restarted
Подключение роли с разными параметрами. Самое вкусное - одну и ту же роль гоняем с разными настройками, передавая vars при подключении. Эти значения перебивают defaults роли:

Код: Выделить всё

# site.yml
- name: Поднять веб-серверы
  hosts: web
  become: true
  roles:
    - role: webserver
      vars:
        web_port: 8080
        web_index_message: "Стенд QA"
      tags: web

    - role: webserver
      tags: web
Тегирование. Тег на подключении роли вешается на все её задачи. Дальше гоняешь точечно:

Код: Выделить всё

ansible-playbook site.yml --tags web
или

Код: Выделить всё

ansible-playbook site.yml --skip-tags web
. Удобно, когда плейбук толстый, а починить надо только веб-часть.

Не забудь meta/main.yml - там хотя бы автор, лицензия и galaxy_info с platforms. Если роль зависит от другой роли, перечисли её в dependencies - Ansible прогонит зависимости перед твоей ролью.

На Ubuntu/Debian модуль dnf заменишь на ansible.builtin.apt, пакет будет apache2, сервис apache2, а вместо firewalld обычно ufw (community.general.ufw). В RED OS и Astra - тот же apt либо dnf по семейству, логика роли не меняется, отличается только маппинг имён, и его как раз держат в vars/main.yml через переменные по дистрибутиву.

Типичные грабли
  • Порт зашит в vars вместо defaults - пользователь не может его переопределить. Настраиваемое - в defaults.
  • notify не срабатывает: имя в notify не совпадает с name хендлера. Проверяй посимвольно, регистр важен.
  • Хендлеры выполняются в конце плея, а не сразу после задачи. Если нужно прямо сейчас - meta: flush_handlers.
  • template ищет .j2 в templates/, copy ищет файлы в files/. Полные пути писать не надо, иначе сломается переносимость.
  • Роль не находится: лежит не в roles/ и не в roles_path. Проверь ansible.cfg.
  • meta/main.yml с битым YAML или пустым dependencies валит запуск ещё до задач. Держи его валидным.
Мини-лаба
  • Создай роль:

    Код: Выделить всё

    ansible-galaxy role init roles/webserver
    . Разбери дерево руками.
  • Заполни defaults/main.yml (package, service, port, doc_root, message), tasks, templates/index.html.j2, handlers.
  • Напиши site.yml, подключи роль дважды - со своими vars и с дефолтами.
  • Прогони

    Код: Выделить всё

    ansible-playbook site.yml --syntax-check
    , затем , затем боевой запуск.
  • Запусти второй раз и убедись, что задачи стали ok/green (идемпотентность), хендлер не дёрнулся.
  • Поменяй web_index_message и проверь, что на этот раз хендлер перезапустил сервис.
  • Погоняй

    Код: Выделить всё

    --tags web
    и

    Код: Выделить всё

    --skip-tags web
    .
Контрольные вопросы
  • Чем defaults/main.yml отличается от vars/main.yml по приоритету и для чего каждый предназначен?
  • Какая команда создаёт скелет роли и какие каталоги получаются?
  • Как передать роли параметры при подключении в плейбуке, чтобы перебить её значения по умолчанию?
  • Почему хендлер может не сработать и где Ansible ищет файлы для template и copy?
Итог

Роль - это аккуратно упакованная автоматизация: скелет от ansible-galaxy role init, настраиваемые значения в defaults, внутренние константы в vars, задачи в tasks, перезапуски через handlers, переносимость через templates и files. Параметризуешь переменными - и одна роль ставит веб-сервер хоть на стенде, хоть в проде. На RHCE (EX294) собрать рабочую роль - типовое задание, и оценивают там ровно это: правильная структура, defaults для настраиваемого, идемпотентность и работающий хендлер.
👍4 ❤️2 🔥 😄 🤔1
Аватара пользователя
lafollette
Сообщения: 1
Зарегистрирован: 22 май 2026, 20:58

Re: Разработка роли Ansible: создание с нуля

Сообщение lafollette »

Спасибо, наконец дошло про defaults и vars. У меня как раз порт в vars лежал и я неделю не мог понять почему в group_vars его не переопределить.
👍2 ❤️1 🔥 😄 🤔1
Аватара пользователя
jwenni
Сообщения: 1
Зарегистрирован: 11 май 2026, 21:14

Re: Разработка роли Ansible: создание с нуля

Сообщение jwenni »

А handlers/main.yml обязательно делать отдельным файлом или можно хендлеры прямо в плейбуке держать? И flush_handlers внутри роли нормально вызывать или это уже плохой тон?
👍3 ❤️1 🔥 😄 🤔
Ответить
← Предыдущая глава
Роли Ansible и Ansible Galaxy: переиспользование
Следующая глава →
Зависимости ролей и requirements.yml

Все главы курса «Ansible: автоматизация и подготовка к RHCE (EX294)»

Поделиться темой: ✈ Telegram VK
Похожие запросы: что такое ansible простыми словамиansible для начинающих с чего начатьустановка ansible на linuxчто такое playbook в ansibleструктура ansible playbook из чего состоитпеременные ansible приоритет какая важнее

Вернуться в «Ansible: автоматизация и подготовка к RHCE (EX294)»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость