Введение
Установленный пакет, существующий файл конфигурации и отвечающая служба — разные результаты. Вы будете управлять каждым явно: установите и удалите утилиту, настроите nginx, объявите его рабочее состояние и перезагрузите изменённую конфигурацию через обработчик. Настоящие HTTP-ответы обоих управляемых узлов подтвердят работу службы.
Объявите состояния установки и отсутствия пакетов
На этом шаге вы установите небольшую утилиту, проверите её и удалите через многократно используемое объявление пакета.
Модуль apt управляет пакетами Ubuntu на управляемом хосте. Его state: present запрашивает установку, а state: absent — удаление. В этом окружении есть подготовленные списки пакетов и кэш загрузок, поэтому сохраняйте update_cache: false; обновление списков или запрос последних версий добавили бы ненужную зависимость от сети. Политики обновления в эксплуатации могут отличаться.
Перейдите в проект управляющего узла:
cd /home/labex/project
Создайте плейбук, в котором переменная выбирает желаемое состояние пакета tree. Операции с пакетами требуют become на целевых узлах. install_recommends: false исключает необязательные рекомендуемые пакеты.
cat > packages.yml <<'YAML'
- name: Declare a utility package state
hosts: all
gather_facts: false
become: true
vars:
utility_state: present
tasks:
- name: Converge the tree package
ansible.builtin.apt:
name: tree
state: "{{ utility_state }}"
update_cache: false
install_recommends: false
YAML
Установите утилиту:
ansible-playbook packages.yml
Команда tree отображает деревья каталогов; здесь её параметр версии демонстрирует, что исполняемый файл действительно установлен на каждом управляемом узле:
ansible all -m ansible.builtin.command -a 'tree --version'
Каждый целевой узел должен вернуть версию tree. Повторите плейбук; уже присутствующим пакетам не нужна ещё одна установка:
ansible-playbook packages.yml
Теперь запросите отсутствие через дополнительную переменную вместо редактирования многократно используемой задачи:
ansible-playbook packages.yml -e utility_state=absent
Повторите то же желаемое отсутствие. Теперь обе строки итога должны показывать changed=0, failed=0 и unreachable=0:
ansible-playbook packages.yml -e utility_state=absent
Состояние пакета — объявление об установке, а не доказательство, что служба запущена или отвечает. Оставьте tree отсутствующим, пока следующий шаг развёртывает nginx.
Настройте и запустите настоящую веб-службу
На этом шаге вы установите nginx, развернёте полную проверенную конфигурацию и явно сохраните его службу запущенной.
Два управляемых узла — контейнеры с отдельными конечными точками SSH и файловыми системами. В них не запущен systemd. Модуль service использует доступный им диспетчер служб; не выполняйте systemctl на этих целевых узлах. Мы будем управлять текущим рабочим состоянием, а не обещать политику загрузки systemd.
Создайте статическую страницу на управляющем узле. Она заканчивается переводом строки, чтобы точные управляемые байты были предсказуемы:
printf 'Ansible service ready\n' > page.txt
Напишите полную конфигурацию nginx. events и http — контексты верхнего уровня nginx, server определяет сайт, listen выбирает порт 8080, root выбирает каталог документов, а index — страницу для запросов /. Это настройки nginx, а не YAML Ansible.
cat > nginx-course.conf <<'NGINX'
events {}
http {
server {
listen 8080;
root /var/www/ansible-site;
index index.html;
}
}
NGINX
Создайте плейбук развёртывания. Задача apt использует policy_rc_d: 101, чтобы установщик пакетов не запускал nginx неявно; последующая задача service явно объявляет рабочее состояние. Параметр validate задачи copy выполняет тест конфигурации nginx для временного кандидата (%s) перед заменой назначения.
Обработчик — именованное действие в handlers. Изменившаяся задача конфигурации уведомляет Reload nginx, который выполняется один раз в конце play. Нет изменения конфигурации — нет уведомления. Обычная задача service использует started, сохраняющий уже работающую службу запущенной без безусловного перезапуска.
cat > web.yml <<'YAML'
- name: Deploy a working web service
hosts: all
gather_facts: false
become: true
tasks:
- name: Install nginx without refreshing the prepared package lists
ansible.builtin.apt:
name: nginx
state: present
update_cache: false
install_recommends: false
policy_rc_d: 101
- name: Prepare the site directory
ansible.builtin.file:
path: /var/www/ansible-site
state: directory
owner: root
group: root
mode: "0755"
- name: Deploy the static page
ansible.builtin.copy:
src: /home/labex/project/page.txt
dest: /var/www/ansible-site/index.html
owner: root
group: root
mode: "0644"
- name: Validate and deploy nginx configuration
ansible.builtin.copy:
src: /home/labex/project/nginx-course.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: "0644"
validate: /usr/sbin/nginx -t -c %s
notify: Reload nginx
- name: Keep nginx running
ansible.builtin.service:
name: nginx
state: started
handlers:
- name: Reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
YAML
Проверьте синтаксис, затем примените развёртывание:
ansible-playbook web.yml --syntax-check
ansible-playbook web.yml
Оба узла должны установить nginx, получить файлы и успешно запуститься. Первое изменение конфигурации также планирует обработчик перезагрузки. Одна лишь проверка версии пакета не подтверждала бы ни один из этих аспектов поведения службы.
curl — клиент HTTP. Его параметр --fail считает неуспешный статус HTTP сбоем команды; --silent убирает вывод хода работы, а --show-error сохраняет сведения об ошибках. Выполните его на каждом управляемом хосте для собственного петлевого интерфейса этого хоста:
ansible all -m ansible.builtin.command -a 'curl --fail --silent --show-error http://127.0.0.1:8080/'
Каждый результат должен содержать Ansible service ready. У управляющего и каждого целевого узла отдельные петлевые интерфейсы; эта команда проверяет обе целевые службы, а не управляющий узел.
Примените изменение конфигурации через обработчик
На этом шаге вы измените действующую настройку nginx, увидите обработчик и подтвердите настройку через HTTP-ответ.
Директива nginx server_tokens управляет тем, раскрывают ли заголовки ответа версию nginx. Добавьте server_tokens off внутри http, заменив конфигурацию управляющего узла этой полной версией:
cat > nginx-course.conf <<'NGINX'
events {}
http {
server_tokens off;
server {
listen 8080;
root /var/www/ansible-site;
index index.html;
}
}
NGINX
Примените тот же плейбук:
ansible-playbook web.yml
Копирование конфигурации должно сообщить changed и уведомить Reload nginx на обоих хостах. Обработчик перезагружает работающую службу после успешной проверки новой конфигурации. Его выполнение вводит конфигурацию в действие; простое копирование файла не подтверждает, что загрузил процесс.
Параметр curl -I запрашивает заголовки HTTP. Изучите фактический ответ службы на обоих хостах:
ansible all -m ansible.builtin.command -a 'curl --fail --silent --show-error -I http://127.0.0.1:8080/'
Оба ответа должны иметь успешный статус HTTP и заголовок Server со значением nginx без суффикса версии. Другие поля заголовков, например даты, меняются.
Повторите полный плейбук:
ansible-playbook web.yml
Оба хоста должны сообщить changed=0 без сбоев и недоступных задач, и обработчик перезагрузки не должен планироваться. Статическая страница остаётся доступной, tree — отсутствующим, а nginx — установленным и запущенным.
Резюме
Вы объявили присутствие и отсутствие пакетов, отделили установку от рабочего состояния службы и развернули полную конфигурацию nginx с проверкой кандидата. Изменённая конфигурация уведомила обработчик перезагрузки, настоящие ответы HTTP подтвердили действующее поведение, а повторный запуск без изменений избежал лишних изменений и перезагрузок.



