Аннотация
В этой части разбираем переменные в Ansible: как их регистрировать, где объявлять, как к ним обращаться, чем отличаются переменные в инвентаре от переменных в playbook, и что такое фильтры Jinja2 для преобразования значений. Статья подойдёт тем, кто уже запускал простые playbook-и и хочет перестать «гадать, откуда взялось это значение».
Регистрация переменных (register): что это и зачем нужно
Иногда задача не только «выполнить команду», но и запомнить её результат, чтобы использовать дальше. Для этого в Ansible есть ключевое слово register.
Простой пример: запомним вывод команды uname -a в переменную os_info:
Что произошло:
- Ansible выполнил команду на удалённой машине.
- Результат положил в память (ни в какой файл на диске это не записывается).
- Теперь в этом playbook-е для этого хоста у нас есть переменная os_info.
У зарегистрированной переменной обычно есть поля:
- os_info.stdout — строка с основным выводом;
- os_info.stderr — ошибки;
- os_info.rc — код возврата (0 — всё хорошо);
- os_info.changed — изменил ли шаг систему (true/false).
Можно использовать это в следующих задачах:
Важно запомнить:
- Зарегистрированные переменные живут только в памяти во время выполнения playbook-а.
- Они относятся к конкретному хосту. Если playbook идет по нескольким серверам, у каждого своя os_info.
- После завершения запуска эти значения не сохраняются.
Ссылки на вложенные переменные и факты (пример с IPv4)
В Ansible есть не только «простые» переменные вроде env_name, но и вложенные структуры: словари и списки.
Например, когда вы вызываете:
ansible all -m setup
Ansible собирает «факты» о системе: сеть, процессор, память и многое другое.
Одно из таких полей — адрес по умолчанию ansible_default_ipv4.address.
В playbook-е к нему можно обратиться так:
То же самое, но через «вложенный словарь»:
Здесь:
- ansible_facts — большой словарь с фактами;
- default_ipv4 — вложенный словарь;
- address — поле внутри него.
Запомнить просто: точки (ansible_default_ipv4.address) и квадратные скобки (['default_ipv4']['address']) — два способа обратиться к одному и тому же значению.
Скобки удобны, когда ключ содержит символы, с которыми точечная запись не дружит.
Преобразование переменных с помощью фильтров Jinja2
Иногда нужно не просто вывести переменную, а чуть её изменить: перевести в число, сделать заглавные буквы, взять элемент по порядку и так далее.
Для этого используются фильтры (в шаблонах Jinja2 они записываются через | — «пайп»).
Примеры:
Часто используемые фильтры:
{{ my_list | unique | length }}
- | int — превратить строку в число;
- | upper / | lower — сделать все буквы большими или маленькими;
- | default('...') — подставить запасное значение, если переменной нет;
- | length — узнать длину строки или списка.
Фильтры можно цепочкой:
Где вообще можно задавать переменные
У Ansible много мест, откуда он берёт переменные. В реальных проектах обычно используются все сразу. Основные варианты:
- Инвентарь (inventory): переменные для групп хостов или отдельных машин.
- Playbook: блок vars, подключаемые файлы vars_files.
- Роли: defaults/main.yml, vars/main.yml внутри роли.
- Зарегистрированные переменные (register) и set_fact — во время выполнения.
- Переменные из командной строки (-e или --extra-vars).
- Факты (ansible_facts), которые Ansible собирает сам.
В следующих разделах разберём эти варианты по очереди.
Определение переменных в инвентаре: зачем и как
Инвентарь (inventory) — это список ваших серверов. В нём удобно хранить переменные, завязанные на окружение: например, домены, порты, режимы.
Пример файла инвентаря в формате YAML (обычный текстовый файл с отступами):
Что здесь происходит:
- Группа web — это «боевые» сервера:
app_env: "prod"
app_port: 8080 - Группа dev — тестовый сервер:
app_env: "dev"
app_port: 8081
В playbook-е мы можем писать один и тот же код:
И Ansible подставит правильные значения для каждого хоста, взяв их из инвентаря.
Почему это удобно в работе:
- Переменные, привязанные к окружению, лежат рядом с описанием хостов.
- Проще поддерживать разные окружения: dev, stage, prod.
- Легко глазами увидеть, чем окружения отличаются.
Переменные в playbook и чем они отличаются от register
В самом playbook-е переменные можно определить в блоке vars:
Здесь:
- vars — статические переменные, которые мы сами задали.
- Они известны ещё до начала выполнения задач.
register — другая история:
- register появляется после выполнения задачи.
- Значение зависит от результата команды или модуля.
- Используется, когда нужно «реактивное» поведение: если файл изменился — сделай одно, если нет — другое.
Можно думать так:
- vars — «заранее известные настройки».
- register — «то, что мы узнали по дороге».
Переменные в инклюд-файлах и ролях
Когда проект разрастается, playbook-ы разбивают на части: инклюды и роли.
Переменные в инклюд-файлах
Инклюд — это подключение отдельного файла с задачами:
Варианты:
- vars_files — список файлов с переменными (обычно в формате YAML).
- include_vars — отдельная задача, которая подгружает переменные:
Это удобно, когда настройки зависят, например, от region, country и т.п.
Переменные в ролях
У роли есть два стандартных места для переменных:
- defaults/main.yml — значения по умолчанию.
- vars/main.yml — переменные роли, которые переписать сложнее.
Пример roles/app/defaults/main.yml:
Если вы напишете в playbook-е:
То порт станет 9090, потому что значения из defaults можно переопределять.
Пример roles/app/vars/main.yml:
Эта переменная сильнее, чем defaults, и переопределить её труднее. Обычно туда кладут значения, которые не планируют менять в каждом проекте.
Переменные во время выполнения: extra-vars
Иногда нужно передать переменную прямо из команды, без изменения файлов.
Для этого есть --extra-vars (коротко -e).
Формат «ключ=значение»
ansible-playbook site.yml -e "app_env=prod app_port=8080"
Внутри playbook-а можно использовать app_env и app_port как обычно.
Формат строки JSON
JSON — это текст в виде {"ключ": "значение"}.
ansible-playbook site.yml -e '{"app_env": "prod", "app_port": 8080}'
Полезно, когда нужно передать сложную структуру, а не только строку.
Переменные из файла JSON или YAML
Можно передать файл:
ansible-playbook site.yml -e "@vars/prod.yml"
Файл prod.yml — обычный YAML:
Так удобно хранить разные наборы переменных, например:
- vars/dev.yml
- vars/stage.yml
- vars/prod.yml
И просто выбирать нужный при запуске.
Приоритет переменных: где лучше разместить значение
У Ansible есть целая «лестница приоритетов»: если одна и та же переменная объявлена в разных местах, какая победит?
Полная таблица большая, но для повседневной работы достаточно упрощённого правила:
От самого сильного к самому слабому:
- Переменные из командной строки (-e, --extra-vars).
- Переменные из set_fact и register в текущем запуске.
- Переменные в playbook-е и переменные роли (vars, vars_files).
- Переменные в инвентаре (group_vars, host_vars).
- Значения по умолчанию роли (defaults/main.yml).
Отсюда простой ответ на вопрос «где объявить переменную?»:
- Если это глобальная настройка проекта, которая меняется от окружения к окружению — разместить в инвентаре или group_vars.
- Если это настройка конкретной роли, которую иногда переопределяют — положить в defaults/main.yml.
- Если это разовое значение только для этого запуска — передать через -e или через отдельный файл с extra-vars.
- Если это то, что мы узнаём на ходу, — использовать register или set_fact.
Почему это всё работает
Ansible на каждом запуске:
- Собирает информацию из разных мест: инвентарь, роли, playbook, extra-vars, факты.
- Складывает всё в одну «карту переменных».
- Если имена совпадают, побеждает то, что выше в «лестнице приоритетов».
- Во время выполнения шагов подставляет значения в шаблоны Jinja2 ({{ ... }}).
То есть для Ansible переменные — это не магия, а просто собранные вместе настройки и результаты выполнения задач, из которых он выбирает самое актуальное значение.
Что мы сделали
В этой части мы:
- Разобрали, как работает register и чем он отличается от обычных переменных.
- Посмотрели, как обращаться к вложенным переменным и фактам, например, к IPv4-адресу.
- Показали, как фильтры Jinja2 помогают преобразовывать значения «на лету».
- Разобрали, где объявлять переменные: инвентарь, playbook, роли, extra-vars.
- Объяснили, что такое приоритет переменных и где логичнее всего хранить каждую из них.
Сделать прямо сейчас
Небольшой практический чек-лист:
- Возьмите свой текущий playbook и добавьте одну задачу с register, а потом выведите результат через debug.
- Посмотрите ansible all -m setup и попробуйте вывести ansible_default_ipv4.address в простом playbook-е.
- Добавьте хотя бы одну переменную в инвентарь (например, порт приложения) и используйте её в задаче.
- Перенесите «жёстко пришитые» значения в defaults/main.yml вашей роли.
- Попробуйте запустить playbook с -e "app_env=dev" и посмотрите, как меняется поведение.
CTA
Если тема Ansible переменных оказалась полезной — подпишитесь на продолжение серии: дальше разберём шаблоны, условия и циклы на живых примерах.
Если остались вопросы по конкретным ситуациям в вашем проекте — напишите в комментариях пару строк о своей задаче, разберём и превратим это в понятный пример для следующих материалов.