Ответ
Ansible по умолчанию использует шаблонизатор Jinja2. Он позволяет динамически генерировать файлы конфигурации на основе переменных, фактов и логики.
Основные возможности Jinja2 в Ansible:
- Подстановка переменных:
{{ nginx_port }} - Условные операторы:
{% if enable_ssl %} ... {% endif %} - Циклы:
{% for host in backend_hosts %} ... {% endfor %} - Фильтры: Для преобразования данных, например
{{ variable | upper }}или{{ list | join(",") }}. - Макросы и наследование шаблонов: Для создания переиспользуемых компонентов.
Практический пример: Шаблон для конфигурации Nginx (templates/nginx.conf.j2).
# nginx.conf.j2
server {
listen {{ nginx_listen_port }} default_server;
server_name {{ server_name }};
root {{ web_root }};
{% if enable_ssl %}
listen 443 ssl;
ssl_certificate /etc/ssl/certs/{{ ssl_cert_name }}.crt;
ssl_certificate_key /etc/ssl/private/{{ ssl_cert_name }}.key;
{% endif %}
location / {
proxy_pass http://backend/;
proxy_set_header Host $host;
}
# Динамическое добавление бэкендов
upstream backend {
{% for host in backend_servers %}
server {{ host.ip }}:{{ host.port }};
{% endfor %}
}
}
Задача в плейбуке для применения шаблона:
- name: Generate Nginx configuration from template
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
owner: root
group: root
mode: '0644'
notify: restart nginx Ответ 18+ 🔞
А, ну вот, смотри, опять про эти шаблоны заговорили. Jinja2, блядь. Ну, в общем, представь себе такую хуйню: тебе надо на сто серверов один и тот же конфиг натянуть, но на каждом какой-то параметр свой — порт там, или имя сервера. Так вот, Ansible для этого и юзает Jinja2, ёпта. Это такой шаблонизатор, который позволяет из одного файла-заготовки наделать кучу разных конфигов, подставляя туда переменные на лету. Удобно, блядь, как швейцарский нож.
Что он, сука, умеет, этот Jinja2:
- Вставить переменную: Просто пишешь
{{ nginx_port }}, и на месте этой хуйни появится значение. Элементарно, Ватсон. - Сделать по условию:
{% if enable_ssl %} ... {% endif %}. Если переменнаяenable_sslравнаtrue, то между этими тегами весь текст в конфиг попадёт. Если нет — нихуя не попадёт. Логика, мать её. - Наделать циклов:
{% for host in backend_hosts %} ... {% endfor %}. Это когда у тебя список бэкендов, и тебе лень их руками прописывать. Цикл сам нагенерит строчек, овердохуища. - Применить фильтры: Это чтобы данные подрихтовать. Например,
{{ variable | upper }}сделает все буквы большими, а{{ list | join(",") }}склеит список через запятую. Красота. - Макросы и наследование: Ну это уже для совсем извращенцев, которые хотят переиспользовать куски кода. Как лего, только для конфигов.
Смотри, как это выглядит на практике. Допустим, шаблон для Nginx (templates/nginx.conf.j2). Выглядит почти как обычный конфиг, но с дырками для переменных.
# nginx.conf.j2
server {
listen {{ nginx_listen_port }} default_server;
server_name {{ server_name }};
root {{ web_root }};
{% if enable_ssl %}
listen 443 ssl;
ssl_certificate /etc/ssl/certs/{{ ssl_cert_name }}.crt;
ssl_certificate_key /etc/ssl/private/{{ ssl_cert_name }}.key;
{% endif %}
location / {
proxy_pass http://backend/;
proxy_set_header Host $host;
}
# Динамическое добавление бэкендов
upstream backend {
{% for host in backend_servers %}
server {{ host.ip }}:{{ host.port }};
{% endfor %}
}
}
А в плейбуке задача будет проще некуда, ядрёна вошь:
- name: Generate Nginx configuration from template
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/default
owner: root
group: root
mode: '0644'
notify: restart nginx
Запускаешь плейбук — и Ansible возьмёт этот шаблон, подставит туда все значения переменных, которые ты ему задал (в инвентаре или где ещё), и запишет готовый, уникальный для каждого сервера конфиг прямо по указанному пути. И если enable_ssl был true, то и SSL-директивы подтянутся. А цикл for нагенерит столько строчек с server, сколько у тебя бэкендов в списке. Всё, блядь, автоматизировано, можно чай пить.