Найти в Дзене
Infra as Code по-русски

Ansible переменные: простыми словами (Часть 2)

В этой части разбираем переменные в Ansible: как их регистрировать, где объявлять, как к ним обращаться, чем отличаются переменные в инвентаре от переменных в playbook, и что такое фильтры Jinja2 для преобразования значений. Статья подойдёт тем, кто уже запускал простые playbook-и и хочет перестать «гадать, откуда взялось это значение». Иногда задача не только «выполнить команду», но и запомнить её результат, чтобы использовать дальше. Для этого в Ansible есть ключевое слово register. Простой пример: запомним вывод команды uname -a в переменную os_info: Что произошло: У зарегистрированной переменной обычно есть поля: Можно использовать это в следующих задачах: Важно запомнить: В Ansible есть не только «простые» переменные вроде env_name, но и вложенные структуры: словари и списки.
Например, когда вы вызываете: ansible all -m setup Ansible собирает «факты» о системе: сеть, процессор, память и многое другое.
Одно из таких полей — адрес по умолчанию ansible_default_ipv4.address. В play
Оглавление

Аннотация

В этой части разбираем переменные в Ansible: как их регистрировать, где объявлять, как к ним обращаться, чем отличаются переменные в инвентаре от переменных в playbook, и что такое фильтры Jinja2 для преобразования значений. Статья подойдёт тем, кто уже запускал простые playbook-и и хочет перестать «гадать, откуда взялось это значение».

Регистрация переменных (register): что это и зачем нужно

Иногда задача не только «выполнить команду», но и запомнить её результат, чтобы использовать дальше. Для этого в Ansible есть ключевое слово register.

Простой пример: запомним вывод команды uname -a в переменную os_info:

-2

Что произошло:

  • Ansible выполнил команду на удалённой машине.
  • Результат положил в память (ни в какой файл на диске это не записывается).
  • Теперь в этом playbook-е для этого хоста у нас есть переменная os_info.

У зарегистрированной переменной обычно есть поля:

  • os_info.stdout — строка с основным выводом;
  • os_info.stderr — ошибки;
  • os_info.rc — код возврата (0 — всё хорошо);
  • os_info.changed — изменил ли шаг систему (true/false).

Можно использовать это в следующих задачах:

-3

Важно запомнить:

  • Зарегистрированные переменные живут только в памяти во время выполнения playbook-а.
  • Они относятся к конкретному хосту. Если playbook идет по нескольким серверам, у каждого своя os_info.
  • После завершения запуска эти значения не сохраняются.

Ссылки на вложенные переменные и факты (пример с IPv4)

В Ansible есть не только «простые» переменные вроде env_name, но и вложенные структуры: словари и списки.

Например, когда вы вызываете:

ansible all -m setup

Ansible собирает «факты» о системе: сеть, процессор, память и многое другое.

Одно из таких полей — адрес по умолчанию ansible_default_ipv4.address.

В playbook-е к нему можно обратиться так:

-4

То же самое, но через «вложенный словарь»:

-5

Здесь:

  • ansible_facts — большой словарь с фактами;
  • default_ipv4 — вложенный словарь;
  • address — поле внутри него.

Запомнить просто: точки (ansible_default_ipv4.address) и квадратные скобки (['default_ipv4']['address']) — два способа обратиться к одному и тому же значению.

Скобки удобны, когда ключ содержит символы, с которыми точечная запись не дружит.

Преобразование переменных с помощью фильтров Jinja2

Иногда нужно не просто вывести переменную, а чуть её изменить: перевести в число, сделать заглавные буквы, взять элемент по порядку и так далее.

Для этого используются
фильтры (в шаблонах Jinja2 они записываются через | — «пайп»).

Примеры:

-6

Часто используемые фильтры:

{{ 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-е мы можем писать один и тот же код:

-7

И Ansible подставит правильные значения для каждого хоста, взяв их из инвентаря.

Почему это удобно в работе:

  • Переменные, привязанные к окружению, лежат рядом с описанием хостов.
  • Проще поддерживать разные окружения: dev, stage, prod.
  • Легко глазами увидеть, чем окружения отличаются.

Переменные в playbook и чем они отличаются от register

В самом playbook-е переменные можно определить в блоке vars:

-8

Здесь:

  • vars — статические переменные, которые мы сами задали.
  • Они известны ещё до начала выполнения задач.

register — другая история:

  • register появляется после выполнения задачи.
  • Значение зависит от результата команды или модуля.
  • Используется, когда нужно «реактивное» поведение: если файл изменился — сделай одно, если нет — другое.

Можно думать так:

  • vars — «заранее известные настройки».
  • register — «то, что мы узнали по дороге».

Переменные в инклюд-файлах и ролях

Когда проект разрастается, playbook-ы разбивают на части: инклюды и роли.

Переменные в инклюд-файлах

Инклюд — это подключение отдельного файла с задачами:

-9

Варианты:

  • vars_files — список файлов с переменными (обычно в формате YAML).
  • include_vars — отдельная задача, которая подгружает переменные:
-10

Это удобно, когда настройки зависят, например, от region, country и т.п.

Переменные в ролях

У роли есть два стандартных места для переменных:

  1. defaults/main.yml — значения по умолчанию.
  2. vars/main.yml — переменные роли, которые переписать сложнее.

Пример roles/app/defaults/main.yml:

-11

Если вы напишете в playbook-е:

-12

То порт станет 9090, потому что значения из defaults можно переопределять.

Пример roles/app/vars/main.yml:

-13

Эта переменная сильнее, чем 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:

-14

Так удобно хранить разные наборы переменных, например:

  • vars/dev.yml
  • vars/stage.yml
  • vars/prod.yml

И просто выбирать нужный при запуске.

Приоритет переменных: где лучше разместить значение

У Ansible есть целая «лестница приоритетов»: если одна и та же переменная объявлена в разных местах, какая победит?

Полная таблица большая, но для повседневной работы достаточно упрощённого правила:

От самого сильного к самому слабому:

  1. Переменные из командной строки (-e, --extra-vars).
  2. Переменные из set_fact и register в текущем запуске.
  3. Переменные в playbook-е и переменные роли (vars, vars_files).
  4. Переменные в инвентаре (group_vars, host_vars).
  5. Значения по умолчанию роли (defaults/main.yml).

Отсюда простой ответ на вопрос «где объявить переменную?»:

  • Если это глобальная настройка проекта, которая меняется от окружения к окружению — разместить в инвентаре или group_vars.
  • Если это настройка конкретной роли, которую иногда переопределяют — положить в defaults/main.yml.
  • Если это разовое значение только для этого запуска — передать через -e или через отдельный файл с extra-vars.
  • Если это то, что мы узнаём на ходу, — использовать register или set_fact.

Почему это всё работает

Ansible на каждом запуске:

  1. Собирает информацию из разных мест: инвентарь, роли, playbook, extra-vars, факты.
  2. Складывает всё в одну «карту переменных».
  3. Если имена совпадают, побеждает то, что выше в «лестнице приоритетов».
  4. Во время выполнения шагов подставляет значения в шаблоны Jinja2 ({{ ... }}).

То есть для Ansible переменные — это не магия, а просто собранные вместе настройки и результаты выполнения задач, из которых он выбирает самое актуальное значение.

Что мы сделали

В этой части мы:

  • Разобрали, как работает register и чем он отличается от обычных переменных.
  • Посмотрели, как обращаться к вложенным переменным и фактам, например, к IPv4-адресу.
  • Показали, как фильтры Jinja2 помогают преобразовывать значения «на лету».
  • Разобрали, где объявлять переменные: инвентарь, playbook, роли, extra-vars.
  • Объяснили, что такое приоритет переменных и где логичнее всего хранить каждую из них.

Сделать прямо сейчас

Небольшой практический чек-лист:

  1. Возьмите свой текущий playbook и добавьте одну задачу с register, а потом выведите результат через debug.
  2. Посмотрите ansible all -m setup и попробуйте вывести ansible_default_ipv4.address в простом playbook-е.
  3. Добавьте хотя бы одну переменную в инвентарь (например, порт приложения) и используйте её в задаче.
  4. Перенесите «жёстко пришитые» значения в defaults/main.yml вашей роли.
  5. Попробуйте запустить playbook с -e "app_env=dev" и посмотрите, как меняется поведение.

CTA

Если тема Ansible переменных оказалась полезной — подпишитесь на продолжение серии: дальше разберём шаблоны, условия и циклы на живых примерах.

Если остались вопросы по конкретным ситуациям в вашем проекте — напишите в комментариях пару строк о своей задаче, разберём и превратим это в понятный пример для следующих материалов.