Организация инвентаря: group_vars, host_vars и вложенные группы

Рейтинг: 68.5% · 14 голосов
Подробный курс по Ansible с прицелом на экзамен RHCE EX294: установка и инвентарь, плейбуки, переменные и факты, Vault, циклы и условия, шаблоны Jinja2, роли и коллекции, Execution Environments и ansible-navigator, управление системами (диски, LVM, cron, SELinux, firewalld). Примеры на RHEL/Fedora. Актуально на 2026.
Ответить
Аватара пользователя
Maksim_DevOps
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Организация инвентаря: group_vars, host_vars и вложенные группы

Сообщение Maksim_DevOps »

Оглавление курса (47)
  1. Что такое Ansible и зачем он нужен: автоматизация без агентов
  2. Сертификация RHCE и экзамен EX294: что внутри и как готовиться
  3. Архитектура Ansible: control node, узлы, модули и плагины
  4. Установка Ansible на control node: dnf, pip и версии ansible-core
  5. Подготовка управляемых узлов: SSH, пользователь и sudo
  6. Инвентарь Ansible: hosts, группы и переменные
  7. Настройка Ansible: файл ansible.cfg и приоритеты конфигурации
  8. Host patterns и инструменты командной строки Ansible
  9. Ad hoc команды Ansible: быстрые задачи без плейбука
  10. Ansible playbook: что это такое и как устроен
  11. Структура плейбука: play, task, модули и переменные
  12. Запуск плейбуков: проверка, теги, ограничения и отладка
  13. Параллелизм и порядок выполнения: forks, serial, strategy
  14. Факты Ansible: сбор информации об узлах
  15. Переменные Ansible: типы, объявление и приоритет
  16. Регистрация результатов и специальные переменные
  17. Ansible Vault: шифрование паролей и секретов
  18. Организация инвентаря: group_vars, host_vars и вложенные группы (вы здесь)
  19. Динамический инвентарь и инвентарные плагины
  20. Циклы в Ansible: loop, списки и словари
  21. Повтор задачи до условия: until, retries и delay
  22. Условия в Ansible: директива when и логика
  23. Jinja2 в Ansible: выражения, фильтры и подстановки
  24. Обработчики Ansible: handlers, notify и flush_handlers
  25. Обработка ошибок: failed_when, changed_when и ignore_errors
  26. Блоки в Ansible: block, rescue и always
  27. Управление файлами: модули file, copy, fetch и stat
  28. Архивы и сборка файлов: archive, unarchive, assemble
  29. Точечное редактирование файлов: lineinfile и blockinfile
  30. Шаблоны Jinja2: модуль template и динамические конфиги
  31. Jinja2 продвинуто: фильтры, циклы, макросы и lookup
  32. Модули Ansible: ansible-doc и поиск нужного модуля
  33. Разработка собственного модуля Ansible на Python
  34. Роли Ansible и Ansible Galaxy: переиспользование
  35. Разработка роли Ansible: создание с нуля
  36. Зависимости ролей и requirements.yml
  37. Коллекции Ansible: ansible.posix, community и своя коллекция
  38. Execution Environments: контейнеры для запуска Ansible
  39. Сборка Execution Environment с ansible-builder
  40. ansible-navigator: запуск плейбуков в Execution Environment
  41. Управление SSH-ключами через Ansible: authorized_key
  42. Управление дисками: filesystem, mount и parted
  43. LVM через Ansible: тома, группы и расширение
  44. Планировщик задач: cron и systemd timers через Ansible
  45. Безопасность: hardening SSH и репозитории dnf/yum
  46. SELinux через Ansible: булевы, контексты и порты
  47. Сквозной проект и подготовка к экзамену EX294
Когда у тебя три хоста и пять переменных, можно всё свалить в один INI-файл инвентаря и не париться. Но как только серверов становится двадцать, появляются окружения prod и staging, у веба свои настройки, у базы свои, а пароль к мониторингу должен лежать отдельно - инлайновые переменные в инвентаре превращаются в нечитаемую кашу. Ты начинаешь копипастить одно и то же по десять раз, а потом ловишь баг "почему на одном хосте старый порт". Лекарство простое и оно же стандарт индустрии: каталоги group_vars и host_vars. В этом уроке разберём, как организация инвентаря в ansible делается по-взрослому, чтобы переменные жили там, где их логично искать, и наследовались по понятным правилам.

group_vars и host_vars: где это лежит и как работает

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

Каталог group_vars/ - переменные для групп. Файл group_vars/webservers применяется ко всем хостам группы webservers. Особый файл group_vars/all - переменные для всех хостов вообще, без исключений. Каталог host_vars/ - переменные для конкретного хоста: host_vars/web1.example.com применяется только к этому хосту.

Расширение можно не писать, но на практике все ставят .yml - так редактор подсвечивает синтаксис. Минимальный проект выглядит так:

Код: Выделить всё

project/
  inventory          # сам файл инвентаря
  group_vars/
    all.yml          # переменные для ВСЕХ хостов
    webservers.yml   # для группы webservers
    dbservers.yml    # для группы dbservers
  host_vars/
    web1.example.com.yml   # лично для web1
  site.yml           # плейбук
Содержимое - обычный YAML со словарём переменных:

Код: Выделить всё

# group_vars/webservers.yml
---
http_port: 8080
max_clients: 200
app_user: deploy

Код: Выделить всё

# host_vars/web1.example.com.yml
---
http_port: 8443   # этот хост слушает нестандартный порт
Тонкий момент, на котором спотыкаются: где должны лежать эти каталоги? Есть два валидных места - рядом с файлом инвентаря и рядом с плейбуком. Ansible читает оба. Если переменная определена и там, и там, выигрывает та, что лежит рядом с плейбуком. Поэтому хорошее правило - держи их рядом с инвентарём, чтобы поведение зависело от того, какой инвентарь ты выбрал (prod или staging), а не от того, из какого каталога запустил плейбук.

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

Код: Выделить всё

group_vars/
  webservers/
    main.yml     # обычные настройки
    vault.yml    # зашифрованный ansible-vault
Изображение

Группы групп: children и наследование переменных

Реальная инфраструктура не плоская. У тебя есть веб-серверы в Москве и в Питере, базы там же, и иногда хочется сказать "примени ко всему, что в Москве" или "ко всем продакшен-машинам". Для этого в ansible inventory группы умеют вкладываться друг в друга через ключевое слово children. Группа-родитель не содержит хостов напрямую - она объединяет другие группы.

Вот инвентарь в YAML-формате, где children ansible показан наглядно:

Код: Выделить всё

# inventory.yml
all:
  children:
    moscow:
      children:
        web_msk:
          hosts:
            web1.example.com:
            web2.example.com:
        db_msk:
          hosts:
            db1.example.com:
    spb:
      children:
        web_spb:
          hosts:
            web3.example.com:
    webservers:
      children:
        web_msk:
        web_spb:
Обрати внимание: один и тот же хост может попадать в несколько групп одновременно. web1 входит и в web_msk, и в moscow (как родителя), и в webservers. Это нормально и именно ради этого children и затевается.

Теперь наследование. Хост получает переменные из ВСЕХ своих групп, и они сливаются. Файл group_vars/moscow.yml применится к web1, db1 и любому хосту внутри moscow, потому что они её потомки:

Код: Выделить всё

# group_vars/moscow.yml
---
ntp_server: ntp.msk.example.com
timezone: Europe/Moscow
То же в INI-синтаксисе, если тебе ближе старый формат:

Код: Выделить всё

[web_msk]
web1.example.com
web2.example.com

[moscow:children]
web_msk
db_msk
Когда что переопределяет: precedence для групп

Самый частый вопрос новичка: "у меня переменная задана в двух группах, какая победит?". Запомни правила, на экзамене и в проде они одинаковые.
  • host_vars сильнее group_vars. Если порт задан и в group_vars/webservers, и в host_vars/web1 - на web1 победит host_vars. Хост всегда конкретнее группы.
  • Дочерняя группа сильнее родительской. Переменная из group_vars/web_msk перебьёт ту же переменную из group_vars/moscow, потому что web_msk - потомок (ребёнок) moscow и он ближе к хосту.
  • group_vars/all - самый слабый из групповых. Это база, поверх которой ложится всё остальное.
  • Группы одного уровня сливаются по алфавиту. Если хост в двух несвязанных группах с одинаковой переменной, побеждает та, чьё имя позже по алфавиту (последняя загруженная перетирает предыдущие). Звучит хрупко - так и есть.
Чтобы не зависеть от алфавита, есть спецпеременная группы ansible_group_priority. Ставишь её в group_vars нужной группы, и при равном уровне вложенности группа с большим приоритетом выигрывает (по умолчанию приоритет 1):

Код: Выделить всё

# group_vars/critical_overrides.yml
---
ansible_group_priority: 10
http_port: 9999
Полная картина precedence шире (туда входят vars плейбука, registered-переменные, и на самом верху - extra-vars через -e, которые бьют вообще всё). Но в рамках инвентаря держи в голове цепочку: all -> родитель -> ребёнок -> host_vars. Это та самая экономия времени, ради которой на RHCE/EX294 ценят аккуратный инвентарь: правильно разложенные ansible group_vars и ansible host_vars позволяют не лазить в каждую задачу и не дублировать значения.

Несколько файлов инвентаря и спецгруппы

Можно скормить Ansible не один файл, а целый каталог: -i inventory/. Тогда движок прочитает все файлы внутри и объединит их в один инвентарь. Удобно бить по смыслу - hosts.yml отдельно, динамические источники отдельно.

Две группы существуют всегда, даже если ты их не объявлял. all - вообще все хосты инвентаря. ungrouped - хосты, которые не попали ни в одну пользовательскую группу. Поэтому group_vars/all.yml и работает магически: группа all встроенная.

Про диапазоны хостов и шаблоны имён. Когда у тебя пятьдесят однотипных веб-нод, не пиши их в столбик - используй числовой диапазон [01:50]. Ведущий ноль важен: он включает дополнение нулями, и хосты будут web01, web02, ..., web50:

Код: Выделить всё

[webfarm]
web[01:50].example.com
Диапазон бывает и буквенным, [a:f], и с шагом. Это раскрывается в момент чтения инвентаря в полный список хостов.

Промышленная структура каталога проекта, к которой стоит стремиться, разделяет окружения и держит для каждого свой инвентарь и свои group_vars:

Код: Выделить всё

project/
  inventories/
    production/
      hosts.yml
      group_vars/
        all.yml
        webservers.yml
      host_vars/
        web1.prod.example.com.yml
    staging/
      hosts.yml
      group_vars/
        all.yml
        webservers.yml
  roles/
  site.yml
Запуск: ansible-playbook -i inventories/production site.yml. Хочешь то же на стейдже - меняешь один путь, плейбук и роли не трогаешь. В этом весь смысл организации инвентаря.

Маленькая пометка про дистрибутивы: всё сказанное от дистрибутива не зависит, group_vars и children одинаковы хоть на RHEL/Fedora с dnf и firewalld, хоть на Ubuntu/Debian с apt, хоть на RED OS или Astra. Различия начинаются внутри задач (имена пакетов, сервисов), а структура инвентаря универсальна.

Типичные грабли
  • Имя файла не совпадает с именем группы. group_vars/webserver.yml (без s) для группы webservers просто молча не применится. Ошибки не будет - переменные тихо проигнорируются.
  • Каталог не там, где запускаешь. Если group_vars лежит рядом с инвентарём, а ты дал -i на отдельный файл из другого места - проверь, что каталог действительно соседствует с инвентарём.
  • Точка в имени хоста. Файл host_vars/web1.example.com.yml должен содержать полное имя ровно как в инвентаре. Если в инвентаре web1, а файл web1.example.com.yml - не совпадёт.
  • Надежда на алфавитный порядок. Если две равноуровневые группы спорят за переменную, не угадывай - задай ansible_group_priority явно.
  • Секреты в открытом виде. Пароли в group_vars шифруй через ansible-vault, не коммить пароли в git как есть.
Мини-лаба

Собери руками каталог проекта с инвентарём в YAML. Создай группы web_msk и web_spb, объедини их в webservers через children, а web_msk и db_msk - в moscow. Задай http_port=80 в group_vars/all.yml, http_port=8080 в group_vars/webservers.yml и http_port=8443 в host_vars для одного конкретного веб-хоста. Проверь, кто победит, командой:

Код: Выделить всё

ansible -i inventory.yml web1.example.com -m ansible.builtin.debug -a "var=http_port"
ansible-inventory -i inventory.yml --graph
ansible-inventory -i inventory.yml --host web1.example.com
Команда ansible-inventory --graph покажет дерево групп - это лучший способ убедиться, что children собрались правильно. Поиграй с диапазоном [01:05] в отдельной группе и посмотри, как он раскроется в --graph.

Контрольные вопросы
  • Где должны лежать каталоги group_vars и host_vars и какой из двух валидных вариантов выигрывает при конфликте?
  • Хост входит в группу moscow и в её дочернюю web_msk, переменная задана в обеих - какая применится и почему?
  • Что делает ключевое слово children и может ли группа-родитель содержать хосты напрямую?
  • Как сделать так, чтобы при споре двух равноуровневых групп переменная бралась из нужной, а не по алфавиту?
Итог

group_vars и host_vars - это не "ещё один способ", а стандарт оформления инвентаря, который экономит время и нервы. Раскладывай переменные по файлам с именами групп и хостов, объединяй группы через children, помни цепочку precedence all -> родитель -> ребёнок -> host_vars, а спорные случаи закрывай ansible_group_priority. Делай отдельные каталоги инвентаря под prod и staging - и один и тот же плейбук поедет в любое окружение без правок. На EX294 это та база, которая разгружает голову под остальные задачи.
👍3 ❤️1 🔥2 😄 🤔
Аватара пользователя
ulphen
Сообщения: 1
Зарегистрирован: 14 май 2026, 14:52

Re: Организация инвентаря: group_vars, host_vars и вложенные группы

Сообщение ulphen »

Наконец дошло почему мой group_vars/webserver не подхватывался - буква s в имени группы пропущена, файл и группа не совпали. Спасибо, неделю мучился.
👍 ❤️1 🔥1 😄 🤔
Аватара пользователя
cpp98
Сообщения: 1
Зарегистрирован: 27 май 2026, 23:03

Re: Организация инвентаря: group_vars, host_vars и вложенные группы

Сообщение cpp98 »

А можно поподробнее про ansible_group_priority? Поставил 10 на одну группу, но переменная всё равно берётся из другой. Это работает только для групп одного уровня вложенности или я что-то путаю?
👍 ❤️ 🔥1 😄 🤔
Ответить
← Предыдущая глава
Ansible Vault: шифрование паролей и секретов
Следующая глава →
Динамический инвентарь и инвентарные плагины

Все главы курса «Ansible: автоматизация и подготовка к RHCE (EX294)»

Поделиться темой: ✈ Telegram VK
Похожие запросы: ansible inventory и hosts файл

Вернуться в «Ansible: автоматизация и подготовка к RHCE (EX294)»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость