Переменные и их приоритет

Урок 11 - выносим значения в переменные и разбираемся с их приоритетом.

«Один и тот же playbook, но порт nginx разный на проде и стейдже - решается переменными, а не копипастой».

Захардкоженные значения в playbook - путь к дублированию. Переменные позволяют вынести то, что меняется: версии, порты, пути, имена пользователей. Тогда один playbook обслуживает разные хосты и окружения.

Где объявлять переменные

МестоДля чего
В плее, секция varsЛокально для этого плея
group_vars/<группа>.ymlДля всех хостов группы
host_vars/<хост>.ymlДля конкретного хоста
defaults/main.yml ролиЗначения по умолчанию роли (низкий приоритет)
Командная строка --extra-varsСамый высокий приоритет
# group_vars/web.yml
nginx_port: 80
nginx_worker_processes: 4

# host_vars/web2.example.com.yml - переопределение для одного хоста
nginx_port: 8080

Приоритет переменных

Одна и та же переменная может быть задана в нескольких местах. Ansible выбирает значение по приоритету: грубо от низкого к высокому - defaults роли, затем group_vars, затем host_vars, затем vars плея, и на самом верху - --extra-vars из командной строки. Чем «ближе к хосту» и чем «явнее» задано - тем выше приоритет.

   НИЗКИЙ приоритет
   role defaults
        |
   group_vars (all -> конкретная группа)
        |
   host_vars (конкретный хост)
        |
   play vars
        |
   --extra-vars (командная строка)
   ВЫСОКИЙ приоритет (перебивает всё)

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

Перед выполнением Ansible собирает все источники переменных для каждого хоста и «накладывает» их слоями: каждый следующий слой по приоритету перекрывает предыдущий, если ключ совпадает. В итоге у каждого хоста формируется свой финальный словарь переменных.

# Модель приоритета: слои перекрывают друг друга по возрастанию
layers = [
    ("role_defaults", {"nginx_port": 80, "workers": 2}),
    ("group_vars",    {"workers": 4}),
    ("host_vars",     {"nginx_port": 8080}),
    ("extra_vars",    {}),  # пусто в этот раз
]

final = {}
for name, layer in layers:           # от низкого приоритета к высокому
    final.update(layer)              # верхний слой перекрывает совпадения

print("Итоговые переменные хоста:", final)
# nginx_port из host_vars (8080), workers из group_vars (4)

Попробуй сам ▶ Итог: nginx_port=8080 (host_vars перебил defaults), workers=4 (group_vars перебил defaults). Так Ansible и разрешает конфликты значений.

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

  • Не понимать, почему «не та» переменная. Скорее всего, её переопределили на более высоком уровне. Проверь все слои.
  • Класть всё в vars плея. Окруженческие значения - в group_vars/host_vars, дефолты - в defaults роли.
  • Путать defaults и vars в роли. defaults/main.yml - низкий приоритет (легко переопределить), vars/main.yml - высокий.

Best practices

  • Дефолты роли - в defaults/main.yml: их должно быть легко переопределить.
  • Различия окружений - в group_vars (например, group_vars/production.yml).
  • Точечные исключения - в host_vars, но не злоупотребляй: много host_vars - запах архитектурной проблемы.

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

Понимание приоритета переменных экономит часы отладки. Классический сценарий: «я задал порт 8080, а сервис слушает 80 - почему?». Ответ почти всегда в приоритете: где-то выше по цепочке (в host_vars или extra-vars) значение переопределено. Команда ansible-inventory --host имя_хоста показывает финальный набор переменных конкретного хоста со всеми наложениями - это первый инструмент диагностики. Зрелые проекты держат жёсткую дисциплину: дефолты только в defaults роли, различия окружений только в group_vars, а точечные исключения в host_vars - и никогда не размазывают одну и ту же переменную по пяти местам, иначе разобраться, какое значение победит, становится почти невозможно.

Итоги

Переменные выносят изменяемые значения из playbook и задаются на разных уровнях с чётким приоритетом: от defaults роли до --extra-vars. Ansible накладывает слои, и побеждает самый приоритетный. Дальше - факты, которые Ansible собирает о хостах сам.

Проверьте себя
1. Какой источник переменных имеет наивысший приоритет?
Arole defaults
Bgroup_vars
C--extra-vars из командной строки
Dhost_vars
2. В чём разница между defaults/main.yml и vars/main.yml в роли?
AНикакой
Bdefaults имеет низкий приоритет (легко переопределить), vars - высокий
Cvars работает быстрее
Ddefaults только для строк, vars только для чисел