如何通过Ansible Handlers实现SSM与CloudWatch Agent安装失败回滚?
我最近写了个Ansible任务文件用来安装SSM和CloudWatch Agent,本来想在安装过程中任何步骤失败时自动回滚,但试了fail模块根本没生效,想请教下怎么解决这个问题,另外也想搞清楚怎么用Handlers来处理失败场景下的回滚操作。
我的任务文件代码如下:
# tasks file for SSMAgnetInstall - name: status check command: systemctl status amazon-ssm-agent register: s_status - debug: msg: "{{ s_status }}" - name: Get CPU architecture command: getconf LONG_BIT register: cpu_arch changed_when: False check_mode: no when: s_status.stdout == "" ignore_errors: true - name: Install rpm file for Redhat Family (Amazon Linux, RHEL, and CentOS) 32/64-bit yum: name: "https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_386/amazon-ssm-agent.rpm" state: present when: s_status.stdout == "" become: yes ignore_errors: true - name: cloud status check command: systemctl status amazon-cloudwatch-agent register: cld_status become: yes - debug: msg: "{{ cld_status }}" - name: Register to cloud watch service become: yes become_user: root service: name: amazon-ssm-agent enabled: yes state: started - name: copy the output to a local file copy: content: "{{ myshell_output.stdout }}" dest: "/home/ansible/rama/output.txt" delegate_to: localhost
一、解决回滚不生效的核心问题
首先看你原代码里的关键问题:多处添加的ignore_errors: true会让Ansible直接跳过错误,根本不会触发后续的失败检测和回滚逻辑,这就是fail模块没生效的原因。另外你没有明确的错误捕获分支,Ansible里处理这种场景最常用的是**block/rescue/always结构**,相当于编程语言里的try-catch-finally。
我给你修改后的任务文件,加入了完整的回滚逻辑:
# tasks file for SSMAgentInstall - name: 处理SSM和CloudWatch Agent安装及回滚流程 block: - name: 检查SSM Agent当前状态 command: systemctl status amazon-ssm-agent register: s_status changed_when: false # 状态检查不标记为changed failed_when: false # 即使状态查询失败(比如未安装),也不触发任务失败 - name: 打印SSM Agent状态 debug: msg: "{{ s_status }}" - name: 获取CPU架构(仅当SSM未安装时执行) command: getconf LONG_BIT register: cpu_arch changed_when: false check_mode: no when: s_status.stdout == "" - name: 安装Redhat系SSM Agent(匹配对应架构) yum: name: "https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_{{ cpu_arch.stdout }}/amazon-ssm-agent.rpm" state: present become: yes when: s_status.stdout == "" # 这里去掉ignore_errors,让安装失败时直接进入rescue - name: 检查CloudWatch Agent状态 command: systemctl status amazon-cloudwatch-agent register: cld_status become: yes changed_when: false failed_when: false - name: 打印CloudWatch Agent状态 debug: msg: "{{ cld_status }}" - name: 启用并启动SSM Agent服务 become: yes service: name: amazon-ssm-agent enabled: yes state: started - name: 复制状态输出到本地文件 copy: content: "SSM Agent状态: {{ s_status.stdout }}\nCloudWatch Agent状态: {{ cld_status.stdout }}" dest: "/home/ansible/rama/output.txt" delegate_to: localhost rescue: # 安装失败时执行回滚操作 - name: 回滚SSM Agent安装(仅针对之前未安装的情况) yum: name: amazon-ssm-agent state: absent become: yes when: s_status.stdout == "" - name: 停止并禁用SSM Agent服务(如果已启动) become: yes service: name: amazon-ssm-agent enabled: no state: stopped - name: 输出回滚完成提示 debug: msg: "安装流程失败,已执行回滚操作" - name: 强制终止Playbook并返回失败状态 fail: msg: "SSM/CloudWatch Agent安装失败,回滚完成"
这个结构的逻辑是:
block块里放所有正常的安装流程,任何任务失败都会立刻跳转到rescue块rescue块里执行回滚:卸载刚装的SSM Agent、清理服务配置- 最后用
fail模块明确标记Playbook失败,避免Ansible返回错误的成功状态
二、用Handlers处理失败场景的回滚
Handlers的优势是可以把重复的操作封装起来,复用性更强。不过Handlers默认只在任务changed时触发,而且要等到所有任务执行完才会运行,所以要在失败场景下用Handlers,需要做两个关键配置:
1. 开启强制触发Handlers
在你的Playbook开头加上force_handlers: yes,确保即使任务失败,Handlers依然会被执行:
- name: 安装SSM和CloudWatch Agent hosts: your_target_hosts force_handlers: yes # 关键配置:失败时不跳过Handlers tasks: # 这里放你的任务代码
2. 定义回滚用的Handlers
在任务文件末尾添加Handlers:
handlers: - name: 回滚SSM Agent安装 yum: name: amazon-ssm-agent state: absent become: yes - name: 清理SSM Agent服务配置 service: name: amazon-ssm-agent enabled: no state: stopped become: yes
3. 在rescue块中触发Handlers
修改之前的rescue块,用notify触发Handlers,再用meta: flush_handlers立即执行(不然Handlers会等到所有任务结束才跑):
rescue: - name: 触发回滚Handlers debug: msg: "开始执行回滚操作" notify: - 回滚SSM Agent安装 - 清理SSM Agent服务配置 - name: 立即执行Handlers(不等待任务结束) meta: flush_handlers - name: 终止Playbook fail: msg: "安装失败,已通过Handlers完成回滚"
这样,失败时就会调用预定义的Handlers完成回滚,逻辑更清晰,后续如果要修改回滚操作,只需要调整Handlers即可。
内容的提问来源于stack exchange,提问作者Ram Krishna

