Аннотация
Если ты устал править конфиги руками под каждый сервер, а в плейбуках всё ещё везде copy, то самое время познакомиться с шаблонами. В этой статье разберём, что такое шаблоны Jinja2 в Ansible, почему модуль template удобнее, чем copy, как подставлять переменные ({{ my_var }}), писать простой if и for прямо внутри файла и использовать пару полезных фильтров (default, upper, lower, join).
Зачем вообще нужны шаблоны Jinja2
Боль классическая:
- один и тот же конфиг на десятках серверов;
- везде одинаковая структура, меняются только 2–3 параметра;
- ты копируешь почти одинаковые файлы, легко ошибиться и забыть где-то что-то поменять.
Шаблон Jinja2 — это «живой» конфиг, в котором вместо жёстко забитых значений стоят переменные и маленькие кусочки логики. Ansible подставляет значения переменных и на выходе даёт обычный текстовый файл — но уже под конкретный сервер.
template vs copy простыми словами
Что делает copy
copy просто берёт файл с твоей машины (или из роли) и как есть кладёт его на целевой сервер:
Если нужно поменять порт — ты правишь myapp.conf, перезапускаешь плейбук.
А если порт зависит от окружения (dev/prod) — начинаются копии файлов: myapp.dev.conf, myapp.prod.conf и так далее.
Что делает template
template берёт шаблон (обычно с расширением .j2), подставляет в него переменные и только потом копирует на сервер:
Внутри myapp.conf.j2 уже не «жёсткий» текст, а что-то вроде:
И для каждого хоста получится свой файл — только за счёт разных переменных.
Итог:
copy — статичный файл.
template — файл с переменными и логикой, из которого Ansible собирает итоговый конфиг.
Первый простой шаблон: подставляем {{ my_var }}
Допустим, мы хотим положить простой конфиг приложения:
1. Определяем переменные
Где-то в переменных (например, group_vars/app.yml):
2. Пишем шаблон templates/myapp.conf.j2
Обрати внимание на двойные фигурные скобки: {{ ... }} — это место для переменной.
3. Задача в плейбуке
4. Что получится на сервере
На целевом хосте файл /etc/myapp.conf будет выглядеть так:
Если для другого окружения ты задашь myapp_port: 9090 и myapp_env: "prod", шаблон станет тем же, а итоговый файл поменяется — магия без копипасты.
Минимум логики: if внутри шаблона
Иногда нужно включать/выключать куски конфига. Например, включать debug-лог только в dev.
Переменная
Шаблон myapp.conf.j2 с if
Разбираем:
- {% if ... %} / {% else %} / {% endif %} — управляющие конструкции Jinja2;
- эти строки не попадут в итоговый файл, они только управляют тем, какой текст вывести.
Результат, если myapp_debug: true:
Результат, если myapp_debug: false:
Чуть логики побольше: for внутри шаблона
Ещё один частый кейс — генерировать повторяющиеся строки по списку. Например, список серверов для подключения.
Переменная-список
Шаблон myapp.conf.j2 с for
Итоговый файл:
Ты добавляешь новый сервер только в списке переменных — шаблон сам подстроится.
Полезные фильтры: default, upper, lower, join
Фильтр — это «функция» после переменной, которая её немного изменяет. Записывается через | (палочку).
default: значение по умолчанию
Если переменная не задана — подставить безопасное значение.
Если myapp_env нет — будет dev.
Так удобно не получать ошибку из-за забытой переменной.
upper: в верхний регистр
"dev" превратится в "DEV".
lower: в нижний регистр
"PROD" превратится в "prod".
join: собрать список в строку
У нас был список:
В шаблоне:
Итог:
Очень удобно для списков IP, фичей, флагов.
Типичные подводные камни
1. Путаем YAML и Jinja2
В плейбуке:
Так писать нельзя — YAML подумает, что это мусор.
Нужно:
То есть в YAML — всегда берём Jinja2 в кавычки.
2. Забыли расширение .j2
Технически шаблон может называться как угодно, но расширение .j2:
- помогает самому не запутаться;
- даёт подсветку синтаксиса в редакторе.
3. Переменная не задана и всё падает
Если переменная обязательна — пусть падает.
Если необязательная — используй default:
Почему это работает
- Ansible прогоняет шаблон через движок Jinja2: подставляет переменные, выполняет if/for, применяет фильтры.
- На выходе получается обычный текстовый файл — конфиг, который понимает твой сервис.
- Вся «магия» живёт в одном месте: шаблон + переменные. Не нужно плодить кучу почти одинаковых конфигов.
- Логика в шаблоне остаётся простой: условие, цикл, парочка фильтров — этого уже достаточно, чтобы закрыть 80% реальных задач.
Что сделали в этой статье
- Разобрали, чем template удобнее, чем copy, когда речь про конфиги.
- Написали первый простой шаблон с подстановкой переменных {{ my_var }}.
- Посмотрели, как использовать if и for прямо внутри файла.
- Разобрали базовые фильтры Jinja2: default, upper, lower, join.
- Отметили типичные ошибки, которые мешают шаблонам работать.
Сделать прямо сейчас (чеклист)
- Найди в своих плейбуках место, где copy кладёт почти одинаковый конфиг на разные хосты.
- Переименуй файл в *.j2 и замени «жёсткие» значения на переменные {{ ... }}.
- Задай эти переменные в group_vars или host_vars для разных окружений.
- Заменить copy на template и запусти плейбук.
- Открой конфиг на целевом хосте и убедись, что значения действительно разные и берутся из переменных.
CTA
Если тебе зашла эта подача Ansible «без магии и боли» — подпишись на серию про Ansible в Дзене.
Пиши в комментариях:
- где шаблоны уже выручили;
- или скинь кусочек своего конфига — разберём, как превратить его в аккуратный Jinja2-шаблон.