Формирование и проверка шаблонов конфигурации

AnsibleBeginner
Практиковаться сейчас

Введение

Автоматизация шаблонов сохраняет один источник, создавая конфигурацию из входных данных каждого хоста. Вы сформируете файлы из переменных и фактов, преобразуете заголовок встроенным фильтром Jinja, выберете условную ветвь и загрузите проверенную конфигурацию nginx через обработчик. Настоящие запросы HTTP и отклонённый некорректный кандидат покажут разницу между исходным текстом, управляемыми файлами и поведением действующей службы.

Сформируйте управляемое содержимое из переменных хостов и фактов

На этом шаге вы создадите один шаблон страницы и сформируете из одного источника разные настоящие файлы на обоих целевых узлах.

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

Перейдите в проект управляющего узла и создайте каталог templates. mkdir -p создаёт каталог при необходимости без ошибки, если он уже существует:

cd /home/labex/project
mkdir -p templates

Определите типизированные входные данные хостов. Окружение и порт прослушивания различаются, а значения maintenance_mode без кавычек — логические значения YAML:

cat > host_vars/web1.yml <<'YAML'
environment_label: development
service_port: 8081
maintenance_mode: true
YAML
cat > host_vars/web2.yml <<'YAML'
environment_label: production
service_port: 8082
maintenance_mode: false
YAML

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

cat > templates/page.txt.j2 <<'JINJA'
host={{ inventory_hostname }}
environment={{ environment_label }}
distribution={{ ansible_facts.distribution }}
JINJA

Используйте модуль template для формирования. Copy обычно перенёс бы байты источника без интерпретации этих выражений Jinja. Соберите факты перед использованием значения дистрибутива и явно задайте владельца и права управляемого файла:

cat > templates.yml <<'YAML'
- name: Render host-specific website content
  hosts: all
  gather_facts: true
  become: true
  tasks:
    - name: Prepare the rendered site directory
      ansible.builtin.file:
        path: /var/www/template-site
        state: directory
        owner: root
        group: root
        mode: "0755"

    - name: Render each host's website content
      ansible.builtin.template:
        src: templates/page.txt.j2
        dest: /var/www/template-site/index.html
        owner: root
        group: root
        mode: "0644"
YAML

Сформируйте обе управляемые страницы:

ansible-playbook templates.yml --syntax-check
ansible-playbook templates.yml

Прочитайте фактические целевые файлы:

ansible all -m ansible.builtin.command -a 'cat /var/www/template-site/index.html'

Каждая страница должна обозначать собственный хост, соответствующее окружение development/production и distribution=Ubuntu. На управляющем узле по-прежнему один многократно используемый источник, а два управляемых результата различаются.

Добавьте встроенный фильтр и условную ветвь конфигурации

На этом шаге вы сформируете корректную конфигурацию nginx, меняющую поведение HTTP по входным данным каждого хоста.

Фильтр Jinja преобразует значение через символ вертикальной черты. upper — встроенный фильтр, переводящий текст в верхний регистр; это не пользовательский плагин. Управляющие инструкции Jinja используют разделители из фигурной скобки и знака процента. Ветвь if/else/endif ниже выбирает один заголовок обслуживания по логическому входному значению.

Создайте полный шаблон конфигурации nginx. Порт, заголовок окружения и заголовок обслуживания поступают из данных каждого хоста. Настройки root и index обслуживают уже сформированную страницу:

cat > templates/nginx.conf.j2 <<'JINJA'
events {}
http {
    server_tokens off;
    server {
        listen {{ service_port }};
        root /var/www/template-site;
        index index.html;
        add_header X-Environment "{{ environment_label | upper }}" always;
{% if maintenance_mode %}
        add_header X-Maintenance "enabled" always;
{% else %}
        add_header X-Maintenance "disabled" always;
{% endif %}
    }
}
JINJA

Добавьте задачи конфигурации и службы и именованный обработчик перезагрузки в существующий плейбук. Команда validate задачи template проверяет временный сформированный кандидат (%s) перед заменой управляемой конфигурации. Изменённая корректная конфигурация уведомляет обработчик; обычная задача service сохраняет nginx запущенным.

cat >> templates.yml <<'YAML'

    - name: Render and validate the nginx candidate before replacement
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: "0644"
        validate: /usr/sbin/nginx -t -c %s
      notify: Reload nginx

    - name: Keep the rendered site service running
      ansible.builtin.service:
        name: nginx
        state: started

  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded
YAML

Примените полный плейбук:

ansible-playbook templates.yml

Задача конфигурации должна изменить оба хоста и вызвать обработчик перезагрузки. Изучите web1 на порту 8081 и web2 на порту 8082. curl -i включает заголовки ответа вместе с телом:

ansible web1 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8081/'
ansible web2 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8082/'

Web1 должен возвращать X-Environment: DEVELOPMENT и X-Maintenance: enabled; web2 — X-Environment: PRODUCTION и X-Maintenance: disabled. Оба тела сохраняют правильную страницу своего хоста. Даты заголовков меняются; сравнивайте значения, полученные из данных, и успешный статус.

Измените входные данные и отклоните некорректный кандидат

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

Измените сохранённое окружение web1 на staging и его режим обслуживания на false, сохраняя существующий порт:

cat > host_vars/web1.yml <<'YAML'
environment_label: staging
service_port: 8081
maintenance_mode: false
YAML

Примените те же исходные шаблоны:

ansible-playbook templates.yml

Страница и конфигурация web1 должны измениться, уведомив его обработчик перезагрузки; web2 должен остаться без изменений. Снова изучите web1:

ansible web1 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8081/'

Его тело должно показывать environment=staging с X-Environment: STAGING и X-Maintenance: disabled. Шаблоны остались многократно используемыми при изменении входных данных.

Теперь проверьте отклонение кандидата. cp сохраняет корректный источник управляющего узла, чтобы его можно было восстановить. Замените только шаблон nginx заведомо некорректным текстом:

cp templates/nginx.conf.j2 templates/nginx.conf.j2.good
printf 'invalid nginx configuration;\n' > templates/nginx.conf.j2

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

ansible-playbook templates.yml || printf 'Expected candidate validation rejection\n'

Прочитайте ошибку задачи: nginx должен отклонить временный кандидат. Рабочая управляемая конфигурация должна остаться на месте, поэтому обе действующие службы по-прежнему должны отвечать правильно:

ansible web1 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8081/'
ansible web2 -m ansible.builtin.command -a 'curl --fail --silent --show-error -i http://127.0.0.1:8082/'

mv восстанавливает сохранённый корректный источник под исходным именем. Запустите полный плейбук ещё раз:

mv templates/nginx.conf.j2.good templates/nginx.conf.j2
ansible-playbook templates.yml

Оба хоста должны сообщать changed=0, failed=0 и unreachable=0 без запланированного обработчика перезагрузки. Проверка защитила действующую конфигурацию, не сделав копию некорректного кандидата желаемым итоговым состоянием.

Резюме

Вы сформировали содержимое из переменных хостов и фактов модулем template, использовали встроенный фильтр upper и логическую ветвь Jinja и применили проверенную конфигурацию через обработчик. Изменённые входные данные дали другой действующий результат без переписывания источников. Некорректный кандидат был отклонён до замены, а восстановленные корректные шаблоны достигли нужного состояния без лишних изменений.