Структура роли: каталоги по соглашению
Урок 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 подхватывает их по соглашению, поэтому пути внутри роли короткие. Дальше научимся передавать роли параметры и связывать роли зависимостями.