Skip to content

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

Разберем как перебирать переменные или факты инвентаризации с помощью простого шаблона Jinja2.

Это может оказаться непростой задачей, а документация не самая лучшая для новичка, поэтому это будет очень короткий пост.

Проблематика

Одна из наиболее распространенных вещей, которые мы хотим сделать с Ansible, — это создать файл конфигурации для удаленного сервера. В идеале мы хотим делать это динамически на основе данных из нашего инвентаря, но доступ к инвентарю и его перебор может быть немного сложным для понимания.

В этом примере мы будем работать с инвентарем из 5 хостов с именами webserver01 – webserver05:

#--inventory.yaml

---
all:
  hosts:
    webserver[01:05]

  children:
    webservers:
      webserver[01:05]

  vars:
    system_domain: truedev.ru
...

Для нашей демонстрации мы собираемся создать файл конфигурации haproxy, который в конечном итоге должен выглядеть следующим образом:

#--haproxy.cfg

defaults
    mode    http
    timeout check 10s

frontend http
    bind *:443
    mode tcp
    default_backend application

backend application
    mode tcp
    balance     roundrobin
    server webserver01.truedev.ru 10.0.1.10:8080 check fall 3 rise 2
    server webserver02.truedev.ru 10.0.1.11:8080 check fall 3 rise 2
    server webserver03.truedev.ru 10.0.1.12:8080 check fall 3 rise 2
    server webserver04.truedev.ru 10.0.1.13:8080 check fall 3 rise 2
    server webserver05.truedev.ru 10.0.1.14:8080 check fall 3 rise 2
И как нам это сделать?

Решение

Очевидно, мы можем найти имя хоста наших серверов, используя ansible host variable. Однако мы не можем просто использовать это в play. На первый взгляд это может выглядеть именно так, но если мы это сделаем, мы просто получим файл конфигурации с файлом, в котором одна и та же запись 5 раз, потому что мы ничего не зацикливаем, именно здесь на помощь приходит использование шаблона Jinja2. Мы также можем искать IP-адрес каждого узла, используя факты Ansible, что позволяет нам динамически искать IP-адрес каждого сервера во время выполнения.

Сначала нам нужно создать отдельный файл шаблона с именем haproxy.cfg.j2 (это просто имя файла, который вы пытаетесь создать, с дополнительным суффиксом .j2). Туда мы добавим некоторую шаблонную логику:

#--haproxy.cfg.j2

defaults
    mode    http
    timeout check 10s

frontend http
    bind *:443
    mode tcp
    default_backend application

backend application
    mode tcp
    balance     roundrobin
{% for host in groups['webservers'] %}
    server {{ host }}.{{ system_domain }} {{ hostvars[host].ansible_default_ipv4.address }}:8080 check fall 3 rise 2
{% endfor %}
Затем мы можем сослаться на этот файл, используя задачу Ansible:

---
- name: Build Config Files
  hosts: webservers
  gather_facts: true
  any_errors_fatal: 

  tasks:
  - name: Build haproxy.cfg
    template:
      src: haproxy.cfg.j2
      dest: haproxy.cfg
...

Это создаст именно тот файл конфигурации, который мы ищем!