Ansible 通过 handlers 区块配合任务中的 notify 关键字实现配置变更后自动重启服务。Handlers 机制适合需要保持幂等性的服务管理场景,风险边界在于 handler 名称必须与 notify 声明完全一致,若名称不一致重启动作不会触发。
先说结论:Ansible handlers 机制确保服务仅在配置实际变更时重启,避免不必要的服务中断。
- 适合:配置文件推送、软件版本更新、需要重启生效的参数调整。
- 先准备:确认服务管理命令(如 systemctl)在目标主机可用,规划 handler 名称。
- 验收:执行 playbook 后检查服务状态及 Ansible 输出中的 changed 标记。
命令速用版
tasks:
- name: Deploy nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
为什么会这样
Handlers 是仅在收到通知时才执行的特殊任务,且默认在 play 结束时统一运行。这种延迟执行机制保证了即使多个任务通知同一个 handler,服务也只会重启一次,同时确保只有配置发生变更(changed)时才会触发通知。
分步处理
1. 编写任务任务:在 tasks 列表中定义配置变更任务,使用 module 如 template 或 lineinfile。
2. 添加通知声明:在任务中加入 notify 字段,值必须与 handlers 区块中的 name 完全匹配。
3. 定义 handler 动作:在 playbook 顶层或 role 的 handlers 文件中定义具体重启命令,如 service 或 systemd 模块。
4. 执行并观察:运行 ansible-playbook,观察输出中 handler 是否被触发。
怎么验证是否生效
查看 Ansible 执行结果末尾的 PLAY RECAP,确认 handler 对应的任务状态为 changed 而非 skipped。登录目标主机执行 systemctl status 服务名,确认服务处于 active (running) 且 Recent log 显示重启时间。
常见坑
1. 名称不匹配:notify 字符串与 handler name 大小写或空格不一致,导致通知失效。
2. 任务未变更:如果配置任务结果为 ok 而非 changed,handler 不会被通知,服务不会重启。
3. 包含关系复杂:在 include_tasks 或 role 中调用 handler 时,需确保作用域可见,必要时使用 listen 关键字。
常见问题
Handler 是在任务执行后立即运行吗?
不是,Handler 默认在当前 play 的所有任务执行完毕后统一运行。
如果有多个任务通知同一个 Handler 会重启多次吗?
不会,无论收到多少次通知,Handler 在一次 play 中仅执行一次。
如何强制运行 Handler 而不依赖配置变更?
可以使用 meta: flush_handlers 任务强制立即触发已排队的所有 handler。
参考来源
1. Ansible Documentation, "Playbook Handlers", https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_handlers.html