Ansible не перезапустил сервис: когда срабатывает handler
Playbook обновил конфигурационный файл, а приложение продолжает отвечать со старым лимитом. В выводе нет ожидаемого RUNNING HANDLER. Прежде чем добавлять безусловный restart, стоит пройти всю цепочку: задача действительно изменила файл, отправила уведомление нужному handler и дошла до момента его выполнения?
Handler удобен для действий, которые нужны только после изменения. Несколько задач могут поправить разные фрагменты конфигурации, а перезапуск достаточно выполнить один раз. Отсюда две особенности диагностики: наличие notify ещё не означает уведомление, а уведомление ещё не означает немедленный запуск.
Воспроизведём механизм без перезапуска сервиса
Следующий самостоятельный playbook пишет файл в отдельный временный каталог локального Linux control node. Handler читает получившееся содержимое. Для выполнения нужны установленный Ansible и Python на этой машине; привилегии администратора и SSH не требуются.
- name: Understand notifications
hosts: localhost
connection: local
gather_facts: false
vars:
demo_value: alpha
tasks:
- name: Create demo directory
ansible.builtin.file:
path: /tmp/latorn-handler-demo
state: directory
mode: '0700'
- name: Write configuration
ansible.builtin.copy:
content: "value={{ demo_value }}\n"
dest: /tmp/latorn-handler-demo/app.conf
mode: '0600'
notify: Read resulting configuration
- name: Run pending handlers now
ansible.builtin.meta: flush_handlers
handlers:
- name: Read resulting configuration
ansible.builtin.command:
argv: [cat, /tmp/latorn-handler-demo/app.conf]
changed_when: false
ansible-playbook -i localhost, demo.yml
ansible-playbook -i localhost, demo.yml
ansible-playbook -i localhost, demo.yml -e demo_value=beta
При первом запуске с отсутствующим файлом copy должен вернуть changed, после чего появится handler. Второй запуск с alpha оставляет файл прежним, поэтому уведомления и чтения не будет. Третий меняет содержимое на beta и снова уведомляет handler. В его выводе проверьте stdout через подробный вывод Ansible, если текущий callback не показывает результат успешной command.
Changed управляет уведомлением
Найдите в реальном журнале задачу, у которой указан notify. Если она завершилась ok, отсутствие handler ожидаемо. Например, шаблон уже совпадает с файлом назначения или условие when пропустило задачу. Сначала сравните ожидаемое содержимое шаблона с dest на нужном хосте; одинаковое имя файла на другой машине не объясняет результат этого запуска.
Особенно внимательно смотрите на changed_when: false. Эту настройку полезно ставить на чтение, как в нашем handler, но у задачи записи она подавит и changed, и уведомление. Исправлять это безусловным changed_when: true тоже не стоит: тогда повторный запуск будет перезапускать сервис даже при одинаковом файле. Смысл changed должен совпадать с фактическим изменением.
Когда handler получает управление
Обычно обработчики выполняются в предусмотренных Ansible точках после секций задач, а повторные уведомления одного handler до такой точки объединяются. В примере meta: flush_handlers специально запускает накопленные обработчики сразу после записи. Это полезно, когда следующая задача уже должна обращаться к процессу с новой конфигурацией.
Flush выполняет все ожидающие handlers в этой точке, поэтому его место влияет на другие роли. Если вы хотите убедиться в работе механизма, сначала оставьте минимальный play, затем верните роли и зависимые задачи. Уведомление по имени требует точного совпадения; при использовании listen сопоставляется имя темы. Неоднозначные одинаковые имена обработчиков из нескольких ролей затрудняют диагностику.
Порядок нескольких handlers определяется их определением, а не порядком строк notify. Если перед reload требуется валидация, лучше проверять конфигурацию в задаче формирования файла или явно выразить зависимость. Нельзя рассчитывать, что список уведомлений сам построит безопасную последовательность.
Ошибка между записью и перезапуском
Если после изменения файла другая задача завершается ошибкой на хосте, отложенный handler по умолчанию может не выполниться на этом хосте. Тогда файл уже новый, а процесс ещё старый. Сопоставьте сообщения changed и failed на одной машине. Опция force_handlers меняет поведение при ошибках, но не делает недоступный хост доступным.
Для реального сервиса замените чтение файла обработчиком service или systemd_service и сначала подтвердите корректность конфигурации штатным валидатором приложения. Выбор между restart и reload зависит от того, умеет ли процесс перечитывать нужный параметр. Механика уведомлений разобрана в справке handlers, а поведение после ошибки — в обработке failures.
Проверяйте исправление двумя последовательными запусками: первый должен применить изменение и вызвать обработчик, второй — сохранить состояние без лишнего действия. Так проверяется вся причинная цепочка, а не только наличие слова notify в YAML.
Ещё по теме
- Ansible check mode: что реально проверяет dry run и чего он не видит
- Ansible взял не ту переменную: разбираем inventory, group_vars и host_vars
Продолжить изучение
Хотите собрать настройку серверов в повторяемый процесс? Inventory, роли, шаблоны и обновление сервисов входят в программу «Ansible: автоматизация инфраструктуры».
Продолжить на практике
- Ansible: автоматизация инфраструктуры ↗
Настраивайте серверы воспроизводимо: inventory, playbooks, роли, шаблоны и секреты. Соберите автоматизацию для нескольких окружений, проверьте повторный запуск и обновляйте сервисы управляемо.
