Зачем нужны роли
Урок 14 - переходим от длинных playbook к ролям: переиспользуемым модулям автоматизации.
«Когда playbook перевалил за две сотни строк и ты копируешь из него куски в другой проект - пора делать роль».
Один playbook на всё - это удобно, пока он маленький. Но настройка реального сервера - это десятки задач: пакеты, пользователи, конфиги, сервисы, фаервол. Playbook разрастается, в нём трудно ориентироваться, а главное - переиспользовать «настройку nginx» в другом проекте невозможно без копипасты. Роль решает обе проблемы.
Что такое роль
Роль - это самодостаточная, конфигурируемая через переменные единица автоматизации, упакованная по стандартной структуре каталогов. «Роль nginx», «роль postgres», «роль common» (базовая настройка). Роль делает одно дело и хорошо - это её главное правило. Не бывает роли webserver_and_database_and_cache; вместо неё - три отдельные роли.
БЫЛО: один огромный playbook
site.yml (300 строк: nginx + postgres + users + firewall...)
СТАЛО: тонкий playbook + роли
site.yml ----+--> role: common
+--> role: nginx
+--> role: postgres
+--> role: firewall
(каждая роль переиспользуема в других проектах)
Подключение роли
- name: Настроить веб-серверы
hosts: web
become: true
roles:
- common
- nginx
- name: Настроить базы
hosts: db
become: true
roles:
- common
- postgres
Видишь, как common переиспользуется в обоих плеях? Это и есть выгода ролей.
Как работает под капотом
Когда плей подключает роли, Ansible для каждой роли автоматически загружает её задачи, переменные по умолчанию, handlers и файлы из стандартных подкаталогов. Роли выполняются в порядке перечисления, до основных tasks плея. По сути роль - это «инклуд по соглашению»: тебе не нужно прописывать пути, Ansible знает структуру.
Смоделируем композицию: сборку плана выполнения из набора ролей.
# Композиция: разворачиваем роли в общий план задач
role_tasks = {
"common": ["set timezone", "create deploy user", "install base pkgs"],
"nginx": ["install nginx", "deploy nginx.conf", "start nginx"],
"postgres": ["install postgres", "init db", "start postgres"],
}
def build_plan(roles):
plan = []
for r in roles:
for t in role_tasks[r]:
plan.append(f"[{r}] {t}")
return plan
print("План для web:")
for step in build_plan(["common", "nginx"]):
print(" ", step)
Попробуй сам ▶ Роль common добавляет свои задачи в начало, потом идёт nginx. Тот же common можно подставить и для db - переиспользование без дублирования кода.
Частые ошибки
- Роль-монстр. Если роль настраивает три несвязанных сервиса - разбей её. Одна роль - одна ответственность.
- Преждевременная ролификация. Не выноси в роль то, что используется в одном месте и не растёт. Роли - для переиспользуемого.
- Жёсткие значения внутри роли. Роль должна настраиваться переменными, а не хардкодом, иначе её не переиспользовать.
Best practices
- Одна роль - одна ответственность (single responsibility): nginx, postgres, common - по отдельности.
- Базовую настройку (юзеры, таймзона, базовые пакеты) выноси в роль
commonи подключай везде. - Делай роль конфигурируемой через переменные, чтобы она работала в разных проектах.
В реальной работе
Роли - это граница между «скриптами для своего проекта» и «переиспользуемыми компонентами инфраструктуры». Хорошо написанная роль nginx работает в любом проекте: достаточно подключить её и передать переменные. Именно поэтому вокруг ролей выросла целая экосистема - тысячи готовых ролей в Galaxy, которые можно брать как зависимости. Внутри компании роли тоже становятся общим достоянием: команда платформы пишет роль common с корпоративными стандартами безопасности (пользователи, ssh-конфиг, аудит), а продуктовые команды просто подключают её, не дублируя security-логику. Так роли превращаются в язык, на котором инженеры договариваются о том, как устроена инфраструктура.
Итоги
Роль - переиспользуемая единица автоматизации, делающая одно дело и настраиваемая переменными. Роли превращают раздутый playbook в тонкий список подключений и позволяют переиспользовать настройку между проектами. Дальше разберём их внутреннюю структуру каталогов.