Зачем нужны роли

Урок 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 в тонкий список подключений и позволяют переиспользовать настройку между проектами. Дальше разберём их внутреннюю структуру каталогов.

Проверьте себя
1. Какое главное правило проектирования роли?
AРоль должна делать как можно больше за раз
BОдна роль - одна ответственность: настраивает что-то одно (nginx, postgres) и настраивается переменными
CРоль не должна иметь переменных
DРоль обязательно содержит все сервисы проекта
2. В чём главная выгода вынесения настройки в роль?
APlaybook работает быстрее
BРоль переиспользуется в разных плеях и проектах без копипасты, плюс playbook становится тоньше
CРоли не требуют инвентаря
DРоли отключают идемпотентность