Ansible Handlers #
什么是 Handlers? #
Handlers 是特殊的任务,只在被通知(notify)且产生变更时执行。通常用于配置变更后的服务重启或重载。
text
┌─────────────────────────────────────────────────────────────┐
│ Handlers 工作流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Task 1 (notify: Handler A) │
│ ├── 变更发生 ──────────────────┐ │
│ │ │ │
│ Task 2 (notify: Handler A) │ │
│ ├── 变更发生 ──────────────────┤ │
│ │ │ │
│ Task 3 (notify: Handler B) │ │
│ └── 无变更 │ │
│ ▼ │
│ 执行 Handlers │
│ ──────────── │
│ Handler A (只执行一次) │
│ Handler B (不执行) │
│ │
└─────────────────────────────────────────────────────────────┘
Handler 特点 #
- 条件执行:只在被通知且产生变更时执行
- 去重执行:即使被多次通知,也只执行一次
- 延迟执行:在 Play 中所有任务执行完后执行
- 顺序执行:按定义顺序执行,而非通知顺序
基本使用 #
定义 Handler #
yaml
---
- name: Configure web server
hosts: webservers
become: yes
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
- name: Deploy Nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart Nginx
- name: Deploy site configuration
template:
src: site.conf.j2
dest: /etc/nginx/sites-available/default
notify: Restart Nginx
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
通知多个 Handler #
yaml
tasks:
- name: Update configuration
template:
src: app.conf.j2
dest: /etc/app/app.conf
notify:
- Restart App
- Reload Firewall
- Clear Cache
handlers:
- name: Restart App
service:
name: app
state: restarted
- name: Reload Firewall
command: ufw reload
- name: Clear Cache
command: rm -rf /var/cache/app/*
Handler 执行顺序 #
按定义顺序执行 #
yaml
tasks:
- name: Task A
debug:
msg: "Task A"
notify: Handler 2 # 第二个通知
- name: Task B
debug:
msg: "Task B"
notify: Handler 1 # 第一个通知
handlers:
- name: Handler 1
debug:
msg: "Handler 1 executed"
- name: Handler 2
debug:
msg: "Handler 2 executed"
# 执行顺序:Handler 1 -> Handler 2(按定义顺序,非通知顺序)
多次通知只执行一次 #
yaml
tasks:
- name: Update config 1
template:
src: config1.j2
dest: /etc/app/config1.conf
notify: Restart App
- name: Update config 2
template:
src: config2.j2
dest: /etc/app/config2.conf
notify: Restart App
- name: Update config 3
template:
src: config3.j2
dest: /etc/app/config3.conf
notify: Restart App
handlers:
- name: Restart App
service:
name: app
state: restarted
# 即使通知三次,Handler 也只执行一次
Handler 作用域 #
Play 级别 Handler #
yaml
- name: Play 1
hosts: webservers
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
tasks:
- name: Configure Nginx
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart Nginx
- name: Play 2
hosts: databases
handlers:
- name: Restart MySQL
service:
name: mysql
state: restarted
tasks:
- name: Configure MySQL
template:
src: my.cnf.j2
dest: /etc/mysql/my.cnf
notify: Restart MySQL
Role 级别 Handler #
text
roles/
└── nginx/
├── handlers/
│ └── main.yml
└── tasks/
└── main.yml
yaml
# roles/nginx/handlers/main.yml
---
- name: Restart Nginx
service:
name: nginx
state: restarted
- name: Reload Nginx
service:
name: nginx
state: reloaded
- name: Validate Nginx config
command: nginx -t
changed_when: false
yaml
# roles/nginx/tasks/main.yml
---
- name: Deploy Nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify:
- Validate Nginx config
- Reload Nginx
强制执行 Handler #
meta: flush_handlers #
立即执行所有待处理的 Handler:
yaml
tasks:
- name: Update configuration
template:
src: app.conf.j2
dest: /etc/app/app.conf
notify: Restart App
- name: Force handler execution
meta: flush_handlers
- name: Check application status
uri:
url: http://localhost:8080/health
register: health_check
retries: 5
delay: 5
until: health_check.status == 200
实际应用场景 #
yaml
tasks:
- name: Stop application
service:
name: app
state: stopped
- name: Update application code
git:
repo: https://github.com/user/app.git
dest: /var/www/app
version: main
notify: Start App
- name: Run database migrations
command: /var/www/app/migrate.sh
- name: Execute handlers now
meta: flush_handlers
- name: Verify application is running
uri:
url: http://localhost:8080/health
status_code: 200
Handler 条件 #
条件 Handler #
yaml
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
when: nginx_enabled | default(true)
- name: Send notification
mail:
to: admin@example.com
subject: "Nginx restarted on {{ inventory_hostname }}"
when: send_notifications | default(false)
监听 Handler #
yaml
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
listen: "restart web services"
- name: Restart PHP-FPM
service:
name: php-fpm
state: restarted
listen: "restart web services"
tasks:
- name: Update Nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: "restart web services"
- name: Update PHP config
template:
src: php.ini.j2
dest: /etc/php.ini
notify: "restart web services"
完整示例 #
Web 服务器配置 #
yaml
---
- name: Configure web server
hosts: webservers
become: yes
vars:
nginx_port: 80
nginx_user: www-data
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: yes
notify: Enable Nginx
- name: Deploy main configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
validate: nginx -t -c %s
notify:
- Validate Nginx config
- Reload Nginx
- name: Deploy site configuration
template:
src: templates/site.conf.j2
dest: /etc/nginx/sites-available/default
owner: root
group: root
mode: '0644'
notify: Reload Nginx
- name: Deploy SSL certificate
copy:
src: files/ssl/
dest: /etc/nginx/ssl/
owner: root
group: root
mode: '0600'
notify: Reload Nginx
when: ssl_enabled | default(false)
- name: Create document root
file:
path: /var/www/html
state: directory
owner: "{{ nginx_user }}"
group: "{{ nginx_user }}"
mode: '0755'
- name: Deploy index page
template:
src: templates/index.html.j2
dest: /var/www/html/index.html
owner: "{{ nginx_user }}"
group: "{{ nginx_user }}"
mode: '0644'
handlers:
- name: Enable Nginx
service:
name: nginx
enabled: yes
- name: Validate Nginx config
command: nginx -t
changed_when: false
- name: Reload Nginx
service:
name: nginx
state: reloaded
- name: Restart Nginx
service:
name: nginx
state: restarted
应用部署 #
yaml
---
- name: Deploy application
hosts: app_servers
become: yes
vars:
app_name: myapp
app_dir: /var/www/myapp
app_user: appuser
tasks:
- name: Pull latest code
git:
repo: "{{ app_repo }}"
dest: "{{ app_dir }}"
version: "{{ app_version | default('main') }}"
notify: Restart Application
- name: Install dependencies
command: npm install --production
args:
chdir: "{{ app_dir }}"
when: git_result.changed
register: npm_result
changed_when: "'added' in npm_result.stdout"
- name: Run database migrations
command: npm run migrate
args:
chdir: "{{ app_dir }}"
when: git_result.changed
notify: Clear Cache
- name: Update configuration
template:
src: app.env.j2
dest: "{{ app_dir }}/.env"
owner: "{{ app_user }}"
group: "{{ app_user }}"
mode: '0600'
notify:
- Restart Application
- Clear Cache
- name: Force handler execution
meta: flush_handlers
- name: Wait for application
wait_for:
port: 3000
timeout: 60
- name: Health check
uri:
url: http://localhost:3000/health
return_content: yes
register: health
until: "'healthy' in health.content"
retries: 5
delay: 5
- name: Send deployment notification
slack:
token: "{{ slack_token }}"
msg: "Deployment completed on {{ inventory_hostname }}"
delegate_to: localhost
when: notify_slack | default(false)
handlers:
- name: Restart Application
systemd:
name: "{{ app_name }}"
state: restarted
daemon_reload: yes
- name: Clear Cache
file:
path: "{{ app_dir }}/cache"
state: absent
- name: Reload Nginx
service:
name: nginx
state: reloaded
listen: "web services changed"
最佳实践 #
1. 使用描述性名称 #
yaml
handlers:
- name: Restart Nginx web server
service:
name: nginx
state: restarted
2. 分离重启和重载 #
yaml
handlers:
- name: Reload Nginx
service:
name: nginx
state: reloaded
- name: Restart Nginx
service:
name: nginx
state: restarted
3. 使用 listen 组织 Handler #
yaml
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
listen: "restart web"
- name: Restart PHP-FPM
service:
name: php-fpm
state: restarted
listen: "restart web"
tasks:
- name: Update web config
template:
src: config.j2
dest: /etc/app/config
notify: "restart web"
4. 验证配置后再重载 #
yaml
handlers:
- name: Validate and reload Nginx
shell: nginx -t && systemctl reload nginx
5. 使用 flush_handlers 控制时机 #
yaml
tasks:
- name: Update config
template:
src: config.j2
dest: /etc/app/config
notify: Restart App
- name: Run migrations
command: /app/migrate.sh
- name: Flush handlers
meta: flush_handlers
- name: Verify app is running
uri:
url: http://localhost:8080/health
下一步 #
现在你已经掌握了 Handlers 处理器,接下来学习 Ansible Vault 了解如何保护敏感数据!
最后更新:2026-03-29