Jinja2 в Ansible: выражения, фильтры и подстановки

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

Jinja2 в Ansible: выражения, фильтры и подстановки

Сообщение 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
Рано или поздно ты упрёшься в стену: переменная иногда не задана, и плейбук падает с "is undefined". Или нужно собрать строку из нескольких значений, перевести имя хоста в нижний регистр, посчитать длину списка, отдать пароль в base64. Хардкодить это бессмысленно, а городить отдельные таски ради одной строки - дорого. Решение одно и то же во всех этих случаях - Jinja2. Это движок шаблонов и выражений, который вшит в Ansible намертво. Если ты разберёшься с ansible jinja2 по-настоящему, половина "магии" в чужих плейбуках перестанет быть магией.

Что такое Jinja2 и где он живёт

Jinja2 - это язык шаблонов на Python, и Ansible использует его буквально везде, где ты видишь фигурные скобки. Связка jinja2 ansible работает по простому правилу из двух конструкций:
  • {{ ... }} - подстановка выражения. То, что внутри, вычисляется и подставляется как значение. Это самое частое.
  • {% ... %} - управляющая логика: циклы for, условия if, присваивания. В плейбуках встречается реже, зато в шаблонах файлов (.j2) - постоянно.
Важно понять одну вещь, на которой спотыкаются новички. Jinja2 в Ansible вычисляется НЕ только внутри файлов-шаблонов. Он работает в значениях практически любых параметров: в vars, в условии when, в ansible.builtin.set_fact, в аргументах модулей, в loop. По сути любое строковое значение в YAML проходит через шаблонизатор. Поэтому ansible шаблоны jinja - это не отдельная фича про конфиги, а сквозной механизм всего движка.

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

- name: Подстановка и логика в разных местах
  hosts: web
  vars:
    app_port: 8080
    base_url: "http://{{ ansible_facts['fqdn'] }}:{{ app_port }}"
  tasks:
    - name: Показать собранный URL
      ansible.builtin.debug:
        msg: "Приложение будет доступно по {{ base_url }}"

    - name: Условие на основе факта (when - это уже Jinja2-выражение)
      ansible.builtin.debug:
        msg: "Памяти меньше 2 ГБ, ставим лёгкую сборку"
      when: ansible_facts['memtotal_mb'] < 2048
Обрати внимание: в when фигурные скобки НЕ нужны. Значение when само по себе является Jinja2-выражением, оборачивать его в {{ }} - ошибка, и Ansible предупредит тебя об этом. Зато внутри msg скобки обязательны, иначе подстановки не будет.

Изображение

Фильтры: основной рабочий инструмент

Фильтры (ansible filters) - это функции, которые применяются к значению через вертикальную черту, как в Unix-конвейере. Слева значение, справа фильтр: {{ value | filter }}. Их можно сцеплять. Это центральная тема урока, потому что на экзамене RHCE (EX294) фильтры нужны и в плейбуках, и в шаблонах - без них не собрать ни одного нетривиального конфига.

Самый важный из всех - default. Ansible default filter подставляет запасное значение, если переменная не определена. Это спасает плейбуки от падений и делает роли переносимыми.

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

- name: Демонстрация ключевых фильтров
  hosts: localhost
  gather_facts: false
  vars:
    names: ["alice", "BOB", "carol"]
  tasks:
    - name: default - запасное значение, если переменная не задана
      ansible.builtin.debug:
        msg: "Воркеров: {{ workers | default(4) }}"

    - name: length, upper, join
      ansible.builtin.debug:
        msg: >-
          Всего имён: {{ names | length }},
          первое в верхнем регистре: {{ names[0] | upper }},
          списком: {{ names | join(', ') }}

    - name: lower и конкатенация через ~
      ansible.builtin.debug:
        msg: "{{ 'HOST-' ~ inventory_hostname | lower }}"

    - name: base64 - частый кейс для секретов и cloud-init
      ansible.builtin.debug:
        msg: "{{ 'super-secret' | b64encode }}"

    - name: to_json / to_yaml - сериализация структур
      ansible.builtin.debug:
        msg: "{{ {'name': 'web', 'port': 8080} | to_json }}"
Разберём, что тут полезного на практике:
  • default(значение) - запасной вариант. Особый случай: default(omit) - не передавать параметр модулю вовсе, как будто его не задавали. Незаменимо, когда у модуля есть свои дефолты и ты не хочешь их затирать.
  • length - длина списка, словаря или строки. Часто идёт в паре с when.
  • upper / lower - регистр. Полезно для нормализации имён хостов, тегов, ключей.
  • join('разделитель') - склеить список в строку. Зеркальный к нему - split.
  • b64encode / b64decode - base64. Нужно для cloud-init, для Secret в Kubernetes, для значений, которые не любят спецсимволы.
  • to_json / to_yaml - превратить словарь или список в текст нужного формата. Обратные - from_json и from_yaml, когда читаешь чужой вывод.
  • mandatory - наоборот, жёстко требует, чтобы переменная была задана: {{ db_password | mandatory }}. Если её нет - плейбук сразу падает с понятной ошибкой, а не позже и непонятно где.
Условия, тесты и арифметика в jinja2 ansible

Кроме фильтров есть тесты - проверки, которые пишутся через ключевое слово is и возвращают true или false. Самый ходовой - проверка на определённость:

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

    - name: Запустить только если переменная задана
      ansible.builtin.service:
        name: "{{ app_service }}"
        state: started
      when: app_service is defined

    - name: Проверка совпадения по шаблону (is match)
      ansible.builtin.debug:
        msg: "Это RHEL-семейство"
      when: ansible_facts['distribution'] is match("RedHat|CentOS|Rocky|AlmaLinux")
Полезные тесты: is defined и is undefined, is none, is match("regex") и is search(...) для регулярок, is in для вхождения. Арифметика и логика тоже работают как в обычном Python: + - * / %, сравнения, and / or / not. Например, {{ ansible_facts['processor_vcpus'] * 2 }} спокойно посчитает число воркеров от количества ядер.

Логику {% %} в плейбуках напрямую почти не пишут - там для этого есть loop и when. Зато в шаблонах файлов она раскрывается полностью. Это прямая связь с уроком про шаблоны файлов (модуль ansible.builtin.template): тот же самый Jinja2, только в .j2-файле, где {% for %} и {% if %} генерируют целые куски конфига.

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

# Фрагмент шаблона nginx.conf.j2
upstream backend {
{% for host in groups['app'] %}
    server {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port | default(8080) }};
{% endfor %}
}
Экранирование: когда фигурные скобки не должны срабатывать

Иногда нужно, чтобы Ansible НЕ трогал двойные скобки - например, в шаблоне конфига, где сам сервис использует синтаксис {{ }} (Prometheus, Grafana, Helm). Для этого есть блок {% raw %} ... {% endraw %}:

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

# В .j2-шаблоне: пусть {{ $labels.instance }} достанется Prometheus как есть
{% raw %}
alert: HighLoad
expr: node_load1 > 4
annotations:
  summary: "Нагрузка на {{ $labels.instance }} высокая"
{% endraw %}
Без raw Ansible попытается вычислить {{ $labels.instance }} как свою переменную и упадёт. Это типичная и очень коварная ловушка.

Типичные грабли
  • Скобки в when. when: "{{ x }}" - неправильно. Пиши when: x is defined. Ansible ругается warning-ом, но многие его игнорируют.
  • Голый default не спасает от пустой строки. default("x") срабатывает только когда переменная undefined. Если она задана, но пустая, нужен второй аргумент: {{ var | default("x", true) }} - тогда дефолт подставится и для пустого, и для false-значения.
  • Сцепление фильтров после default(omit). Нельзя писать | default(omit) | upper - omit это не строка. Если дальше идут фильтры, используй | default(None) или omit в конце.
  • Число превращается в строку. После to_json или join результат - текст. Если дальше нужна арифметика, верни тип через int или float.
  • Пробелы и ~. Для склейки строк надёжнее оператор ~, чем +: плюс попытается сложить как числа и может упасть на типах.
Маленькая пометка по дистрибутивам: сам Jinja2 от ОС не зависит, он одинаков на RHEL/Fedora, на Ubuntu/Debian и на RED OS или Astra. Различия вылезают в данных, которые ты в него подаёшь - например, ansible_facts['pkg_mgr'] вернёт dnf на RHEL и apt на Debian, и дальше ты уже фильтрами и условиями разводишь логику.

Мини-лаба

Прогони руками, лучше через ansible localhost -m debug или маленький плейбук:
  • Создай переменную-список из 5 элементов и выведи: длину (length), элементы через запятую (join), первый элемент в верхнем регистре.
  • Возьми незаданную переменную и выведи её с default("резерв"). Потом задай её пустой строкой и убедись, что нужен default("резерв", true).
  • Сделай set_fact, который собирает строку подключения вида user@host:port через оператор ~ и фильтр lower.
  • В .j2-шаблоне с ansible.builtin.template оберни кусок с чужими {{ }} в {% raw %} и проверь, что они не вычислились.
  • Поставь на критичную переменную | mandatory и убедись, что без неё плейбук падает сразу.
Контрольные вопросы
  • Чем отличается {{ }} от {% %} и почему в when не нужны фигурные скобки?
  • Как заставить default подставить значение не только для undefined, но и для пустой строки?
  • Что делает default(omit) и зачем он нужен в параметрах модулей?
  • Когда применяют {% raw %} и какая ловушка ждёт, если про него забыть?
Итог

Jinja2 - это клей всего Ansible: подстановки {{ }}, логика {% %}, фильтры через | и тесты через is. Ты уже умеешь делать значения безопасными (default, mandatory), приводить типы и формат (upper, join, b64encode, to_json) и ветвить логику по фактам. Этого набора хватает для большинства задач и на работе, и на EX294. Глубже в фильтры - разбор сложных структур, map, selectattr, работа со словарями - мы нырнём в уроке 30.
👍1 ❤️2 🔥1 😄 🤔
Аватара пользователя
grumpykraken
Сообщения: 1
Зарегистрирован: 18 май 2026, 20:32

Re: Jinja2 в Ansible: выражения, фильтры и подстановки

Сообщение grumpykraken »

Спасибо, наконец-то дошло почему when без фигурных скобок а в msg с ними. Сто раз ловил это предупреждение и не понимал.
👍2 ❤️1 🔥 😄 🤔
Аватара пользователя
prometheus_admin
Сообщения: 1
Зарегистрирован: 11 май 2026, 13:41

Re: Jinja2 в Ansible: выражения, фильтры и подстановки

Сообщение prometheus_admin »

А default(omit) реально топ. Раньше городил отдельные таски с when чтобы не передавать параметр модулю, а тут одна строка. Жаль раньше не знал.
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Условия в Ansible: директива when и логика
Следующая глава →
Обработчики Ansible: handlers, notify и flush_handlers

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

Поделиться темой: ✈ Telegram VK
Похожие запросы: что такое ansible простыми словамиansible для начинающих с чего начатьустановка ansible на linuxansible inventory и hosts файлчто такое playbook в ansibleструктура ansible playbook из чего состоит

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

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

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