Структура роли: каталоги по соглашению

Урок 15 - изучаем стандартную структуру каталогов роли.

«Роль - это не магия, а соглашение о том, где что лежит. Ansible знает структуру и сам всё подхватит».

Роль - это каталог с предопределённой структурой. Ansible автоматически подхватывает содержимое стандартных подкаталогов: ему не нужно указывать пути, достаточно положить файлы в правильные места.

Структура роли

   roles/nginx/
   +-- tasks/main.yml       <- основные задачи роли
   +-- handlers/main.yml    <- обработчики (restart nginx и т.п.)
   +-- templates/           <- Jinja2-шаблоны (.j2)
   +-- files/               <- статические файлы для copy
   +-- defaults/main.yml    <- переменные по умолчанию (низкий приоритет)
   +-- vars/main.yml        <- внутренние переменные (высокий приоритет)
   +-- meta/main.yml        <- метаданные, зависимости от других ролей
КаталогНазначение
tasks/main.ymlГлавная точка входа: список задач роли
handlers/main.ymlОбработчики, вызываемые через notify
templates/Jinja2-шаблоны; template ищет файлы здесь
files/Статические файлы; copy ищет здесь
defaults/main.ymlДефолтные переменные роли (легко переопределить)
vars/main.ymlВнутренние переменные роли (высокий приоритет)
meta/main.ymlЗависимости, автор, поддерживаемые платформы

Пример tasks/main.yml роли nginx

---
- name: Установить nginx
  ansible.builtin.apt:
    name: nginx
    state: present

- name: Развернуть конфиг
  ansible.builtin.template:
    src: nginx.conf.j2          # ищется в templates/
    dest: /etc/nginx/nginx.conf
  notify: Перезапустить nginx    # handler из handlers/main.yml

- name: Запустить сервис
  ansible.builtin.service:
    name: nginx
    state: started
    enabled: true

Как работает под капотом

При подключении роли Ansible смотрит её каталоги и автоматически: выполняет tasks/main.yml, делает доступными handlers из handlers/main.yml, загружает переменные из defaults/main.yml (низкий приоритет) и vars/main.yml (высокий). Когда внутри роли template просит src: nginx.conf.j2, Ansible ищет его в templates/ этой роли. Поэтому пути в задачах роли короткие - имя файла без каталога.

Смоделируем разрешение пути к файлу шаблона по соглашению роли.

# Разрешение пути к файлу внутри роли по соглашению каталогов
import os

def resolve_in_role(role_dir, kind, filename):
    subdir = {"template": "templates", "copy": "files",
              "tasks": "tasks"}[kind]
    return os.path.join(role_dir, subdir, filename)

print(resolve_in_role("roles/nginx", "template", "nginx.conf.j2"))
print(resolve_in_role("roles/nginx", "copy", "favicon.ico"))
print(resolve_in_role("roles/nginx", "tasks", "main.yml"))

Попробуй сам ▶ Шаблон ищется в templates/, статический файл - в files/, задачи - в tasks/. Именно поэтому в задаче роли пишут просто src: nginx.conf.j2 без полного пути.

Частые ошибки

  • Класть шаблон не в templates/. Тогда template его не найдёт - он ищет строго в этом каталоге роли.
  • Путать defaults и vars. Настраиваемое снаружи - в defaults; внутреннее, не для переопределения - в vars.
  • Прописывать полные пути. Внутри роли указывай только имя файла - каталог Ansible подставит сам.

Best practices

  • Сгенерируй скелет роли командой ansible-galaxy init roles/nginx - получишь правильную структуру сразу.
  • Все настраиваемые переменные клади в defaults/main.yml с понятными именами и комментариями.
  • Держи tasks/main.yml читаемым; крупную логику разбивай на отдельные файлы и подключай через import_tasks.

В реальной работе

Стандартная структура - это не бюрократия, а контракт, благодаря которому любая роль выглядит знакомо. Открыв чужую роль, ты сразу знаешь: точка входа в tasks/main.yml, настраиваемые переменные в defaults/main.yml, шаблоны в templates/. Это резко снижает порог входа в чужой код. Когда задач в роли становится много, их разбивают на тематические файлы (install.yml, configure.yml, service.yml) и подключают из main.yml через import_tasks - так роль остаётся читаемой. А каталог molecule/ рядом с ролью - признак зрелости: это тесты роли, которые в изолированном контейнере проверяют, что она действительно настраивает то, что обещает, и делает это идемпотентно.

Итоги

Роль - это каталог с предопределённой структурой: tasks, handlers, templates, files, defaults, vars, meta. Ansible подхватывает их по соглашению, поэтому пути внутри роли короткие. Дальше научимся передавать роли параметры и связывать роли зависимостями.

Проверьте себя
1. Где модуль template внутри роли ищет файл, указанный в src?
AВ корне проекта
BВ каталоге templates/ этой роли
CВ files/
DВ /etc/ansible/
2. Чем удобна команда ansible-galaxy init roles/nginx?
AСкачивает nginx из интернета
BСоздаёт скелет роли со всеми стандартными каталогами сразу
CЗапускает роль на сервере
DУдаляет старую роль