Зависимости ролей: dependencies в meta/main.yml
Внутри каждой роли есть файл meta/main.yml. Помимо метаданных автора и лицензии там живёт ключ dependencies - список ролей, которые должны отработать ДО запуска текущей. Это и есть ansible role dependencies в чистом виде.
Допустим, у тебя есть роль myapp, и она бессмысленна без nginx. Описываем зависимость:
Код: Выделить всё
# roles/myapp/meta/main.yml
---
galaxy_info:
author: cyberlake
description: Деплой нашего приложения
license: MIT
min_ansible_version: "2.14"
platforms:
- name: EL
versions:
- "9"
dependencies:
- role: nginx
- role: postgresql
vars:
pg_version: 16
Код: Выделить всё
# site.yml
---
- name: Развернуть приложение
hosts: app_servers
become: true
roles:
- role: myapp

allow_duplicates: когда роль нужна несколько раз
По умолчанию роль, уже отработавшая как чья-то зависимость, повторно в том же play не запускается. Это спасает от бесконтрольного дублирования: если десять ролей зависят от common, common прогонится один раз. Логика идемпотентности: один и тот же набор задач не должен молотиться вхолостую.
Но иногда повтор нужен по делу. Классика - роль, которая создаёт виртуальный хост или раскатывает один инстанс сервиса, и ты хочешь вызвать её несколько раз с разными параметрами. Тогда в meta/main.yml самой переиспользуемой роли ставим:
Код: Выделить всё
# roles/vhost/meta/main.yml
---
allow_duplicates: true
dependencies: []
requirements.yml: внешние роли и коллекции
Зависимости в meta/main.yml хороши, но они описывают связи МЕЖДУ ролями. А откуда взять сами роли и коллекции, если их нет в репозитории? Здесь на сцену выходит ansible requirements.yml - манифест внешних зависимостей проекта. Это не часть Ansible-движка, это вход для утилиты ansible-galaxy. Файл обычно кладут в корень проекта или в каталог collections/.
Формат у файла два раздела: roles и collections. Минимальный пример:
Код: Выделить всё
# requirements.yml
---
roles:
- name: geerlingguy.nginx
version: "3.1.4"
- name: internal-app
src: https://git.cyberlake.ru/devops/role-internal-app.git
scm: git
version: v2.0.1
collections:
- name: community.general
version: ">=8.0.0"
- name: ansible.posix
version: "1.5.4"
- name + version для роли из Galaxy - тянется по имени namespace.role с указанной версией. Это и есть базовый ansible galaxy requirements.
- src + scm: git + version - роль берётся напрямую из git-репозитория. version здесь это тег, ветка или коммит. На проде всегда пинуй тег или хеш коммита, а не ветку main, иначе сборка перестанет быть воспроизводимой.
- collections - современные модули типа ansible.posix.firewalld и community.general.parted живут именно в коллекциях, поэтому без этого раздела ты далеко не уедешь. version поддерживает диапазоны (>=, <, ==).
Установка: ansible-galaxy install -r requirements.yml
Дальше всё ставится одной командой. Современный ansible-core понимает оба раздела сразу:
Код: Выделить всё
ansible-galaxy install -r requirements.yml
Код: Выделить всё
# Роли - в каталог roles/
ansible-galaxy role install -r requirements.yml -p roles/
# Коллекции - в каталог collections/
ansible-galaxy collection install -r requirements.yml -p collections/
Код: Выделить всё
# ansible.cfg
[defaults]
roles_path = ./roles:/etc/ansible/roles
collections_path = ./collections
Связь с экзаменом. На RHCE (EX294, версия под RHEL 9) умение взять готовый requirements.yml и развернуть по нему роли и коллекции - реальный практический навык. Тебе вполне могут дать заранее подготовленный файл и попросить установить из него роль, а потом применить её к группе хостов. Знать, что collections тоже описываются в этом файле и что install -r ставит и то и другое - ровно тот минимум, на котором не стоит срезаться.
Типичные грабли
- Забыл коллекцию в requirements.yml. Плейбук падает на "couldn't resolve module ansible.posix.firewalld". Модуль живёт в коллекции ansible.posix - значит, коллекция должна быть в манифесте и установлена.
- Пин на ветку вместо тега. version: main для git-роли = лотерея при каждой установке. Тег или хеш коммита.
- Дубликат роли не отрабатывает. Вызвал роль второй раз, а она молчит - не забыл ли allow_duplicates: true.
- roles_path не настроен. Поставил роли через -p roles/, а Ansible ищет в /etc/ansible/roles. Пропиши roles_path в ansible.cfg рядом с проектом.
- meta/main.yml невалиден. Если в зависимостях опечатка или роль не найдена - play не стартует вовсе, ошибка вылезает на этапе разбора зависимостей, до первой задачи.
Когда роль вылизана и идемпотентна, её не грех опубликовать. Через свой аккаунт Galaxy импортируешь git-репозиторий роли, и она становится доступна как namespace.role в чужих requirements.yml. Правила хорошего тона: осмысленный meta/main.yml с лицензией и platforms, README с переменными, семантические теги версий в git.
И две мысли про роли в целом. Первое - дроби роль, когда у неё появляется второй смысл. Роль должна делать одну понятную вещь (поставить и настроить nginx), а не "развернуть весь стек". Второе - роль обязана быть идемпотентной целиком: повторный запуск на настроенной машине не меняет ничего и весь вывод зелёный (ok), а не жёлтый (changed). Если при втором прогоне роль что-то "чинит" каждый раз - значит, где-то command вместо нормального модуля или забытый creates/changed_when.
Мини-лаба
- Создай роль myapp, в её meta/main.yml пропиши dependencies на роль common. Убедись, что common отрабатывает первой.
- Напиши requirements.yml с одной ролью из Galaxy (с пином version) и двумя коллекциями (community.general, ansible.posix).
- Установи всё: ansible-galaxy install -r requirements.yml. Затем разнеси установку на role install и collection install с -p.
- Возьми переиспользуемую роль, поставь allow_duplicates: true и вызови её дважды с разными vars - проверь, что отработали оба вызова.
- Прогони итоговый плейбук дважды подряд и убедись, что второй прогон полностью идемпотентен (changed=0).
- В каком файле роли описываются её внутренние зависимости и в каком порядке они выполняются относительно основной роли?
- Чем отличается раздел roles от collections в requirements.yml и почему коллекции вообще нужны?
- Что делает allow_duplicates: true и в какой ситуации без него роль не отработает повторно?
- Какой командой установить разом роли и коллекции из манифеста и как разнести их по разным каталогам?
Зависимости ролей через meta/main.yml связывают роли между собой и задают порядок их выполнения, allow_duplicates разрешает осознанный повтор. requirements.yml - это манифест внешних зависимостей для ansible-galaxy: roles тянут роли из Galaxy и git, collections подтягивают современные модули. Команда ansible-galaxy install -r requirements.yml ставит всё одним движением и делает проект воспроизводимым на любой машине. Пинуй версии, держи роли маленькими и идемпотентными - и сборка не развалится ни у коллеги, ни на экзамене.