Ansible взял не ту переменную: разбираем inventory, group_vars и host_vars

В group_vars/web.yml стоит app_port: 8080, однако приложение слушает 9090. Файл существует, YAML выглядит правильным, playbook проходит. В такой ситуации полезно разделить два вопроса: какое значение собрал inventory для хоста и какое значение получила задача после применения остальных источников переменных.

Имя app_port может встречаться в нескольких местах. Это позволяет задавать общий порт для группы и исключение для одного сервера. Но если исключение осталось после старого эксперимента, правка общего файла перестаёт влиять на этот сервер. Разберём маленькое дерево, в котором каждое значение имеет объяснимое назначение.

Создадим три уровня настроек

В отдельном каталоге создайте inventory/hosts.yml и рядом с ним подкаталоги group_vars и host_vars. Файл group_vars/all.yml задаёт общую настройку, group_vars/web.yml уточняет её для веб-серверов, а host_vars/web1.yml содержит исключение. Имена файлов соответствуют именам групп и inventory-хостов, а не адресу подключения.

demo/
  inventory/
    hosts.yml
    group_vars/
      all.yml
      web.yml
    host_vars/
      web1.yml
  show.yml

Содержимое inventory/hosts.yml:

all:
  children:
    web:
      hosts:
        web1:
          ansible_connection: local

В inventory/group_vars/all.yml запишите app_port: 8000, в inventory/group_vars/web.yml — app_port: 8080, в inventory/host_vars/web1.yml — app_port: 9090. Каждый файл состоит из одной YAML-строки. show.yml только выводит значение; подключение local выбрано для безопасного локального воспроизведения.

- name: Show effective application port
  hosts: web
  gather_facts: false
  tasks:
    - name: Display value at task execution
      ansible.builtin.debug:
        var: app_port
ansible-inventory -i inventory/hosts.yml --graph
ansible-inventory -i inventory/hosts.yml --host web1
ansible-playbook -i inventory/hosts.yml show.yml
ansible-playbook -i inventory/hosts.yml show.yml -e '{"app_port": 7070}'

В графе web1 должен входить в web. Для --host ожидается app_port со значением 9090: настройка хоста перекрывает групповую. Обычный запуск show.yml должен показать то же значение. Последняя команда передаёт extra variable и должна показать 7070. JSON-форма -e сохраняет числовой тип порта; запись app_port=7070 передаёт строку.

Что доказывает ansible-inventory

Эта команда позволяет проверить состав хостов и результат загрузки inventory-переменных без выполнения конфигурации сервера. Если там уже 9090, проблема возникла до задач playbook. Если там 8080, а debug внутри задачи показывает другое, ищите определения в play vars, vars_files, include_vars, set_fact, role vars и аргументах запуска.

Inventory не исполняет будущие задачи, поэтому не может заранее показать значение после set_fact. По той же причине вывод --host не является полным объяснением каждого значения на всех этапах play. Добавьте временный debug непосредственно перед шаблоном, где наблюдается ошибка. Для секрета вместо самого значения выведите безопасный признак или используйте no_log там, где есть риск утечки.

Проверьте, откуда читаются файлы

Укажите -i явно и запускайте сравниваемые команды из одного каталога. Отдельные group_vars и host_vars могут загружаться относительно inventory, а для ansible-playbook — ещё и относительно каталога playbook. Если inventory-команда должна учитывать playbook-каталог, задайте --playbook-dir. Иначе сравниваются разные наборы входов и получается ложный вывод о приоритете.

Нужное имя host_vars берётся из inventory alias. Если хост назван web1, а ansible_host равен IP-адресу, файл web1.yml относится к этому хосту. Файл с именем IP не станет его настройкой автоматически. Для динамического inventory сначала посмотрите фактическое имя в --graph, затем сопоставьте путь.

Вложенные группы добавляют ещё один уровень: дочерняя группа переопределяет родительскую. Если хост состоит в нескольких группах одного уровня, конфликт имён требует отдельного внимания к порядку объединения и ansible_group_priority. Лучше выбрать одного владельца настройки, чем рассчитывать на алфавитный порядок имён. Практические правила структуры приведены в руководстве inventory.

Исправим источник, а не симптом

Если 9090 было временным исключением, удалите его из host_vars и повторите --host: ожидается 8080. Если исключение нужно, оставьте его с понятным назначением. Перед релизом проверьте CI-команду запуска: сохранённый -e app_port=7070 имеет высокий приоритет и продолжит перекрывать файлы. Extra vars и другие категории приоритета объясняют, почему такая правка файлов не сработает.

Для настроек роли, которые пользователь должен менять через inventory, обычно подходят defaults. Жёстко заданное одноимённое значение в vars роли может перекрыть ожидаемую настройку. После устранения конфликта проверьте значение в месте использования и фактически сгенерированный файл. Совпадение этих двух результатов завершает разбор: известно и откуда пришёл порт, и куда он попал.

Ещё по теме

Продолжить изучение

Хотите собрать настройку серверов в повторяемый процесс? Inventory, роли, шаблоны и обновление сервисов входят в программу «Ansible: автоматизация инфраструктуры».

Продолжить на практике

  • Ansible: автоматизация инфраструктуры ↗

    Настраивайте серверы воспроизводимо: inventory, playbooks, роли, шаблоны и секреты. Соберите автоматизацию для нескольких окружений, проверьте повторный запуск и обновляйте сервисы управляемо.