首页/系统与基础设施/自动化运维速查/块与救援结构的错误处理
Ansible 核心70 条

块与救援结构的错误处理

块、救援、收尾三段式把“失败后做什么”写进流程:救援段在块内任一任务失败时执行用于回滚或留证,收尾段始终执行用于清理;块内注册变量在救援段可见,救援段完成后主机继续本 play,因此需要显式中止时应主动报错。

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌​​​​‌​‌‌‌​‌​‌​‌‌‌​‌​​​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌‌‌​‌‌​​​‌​​‌‌​‌‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌​‌​‌‌​​‌​‌‌​‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌‌​​‌‌​‌‌​​​‌‌​‌‌‌​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌​​​‌‌‌​‌‌‌​‌‌​​​​‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​‌​‌‌​‌​‌‌​​‌​‌​‌‌‌​​‌​​‌‌‌​​‌​​‌‌​‌‌‌‌​‌‌‌​​‌​​​‌​‌‌​‌​‌‌​‌​​​​‌‌​​​​‌​‌‌​‌‌‌​​‌‌​​‌​​​‌‌​‌‌​​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​

块、救援与收尾三段式

把一组任务包成块后,可以给它配两段处理逻辑:救援段在块内任一任务失败时执行,收尾段不论成功失败都会执行。这相当于给一组操作加上异常处理与收尾动作:前半段做变更,救援段做回滚或记录失败,收尾段做清理。它让“失败之后怎么办”从依赖人工判断变成剧本里的固定流程。

基本信息

结构块、救援、收尾三段,救援与收尾可只写其中之一
救援触发块内任一任务在该主机上失败时执行
收尾触发无论块是否失败都执行,用于清理与记录
变量可见性块内任务注册的变量在救援段可见,即使该任务失败也已写入
失败主机救援段成功完成后,该主机继续参与同一 play 的后续任务
嵌套块可嵌套,内层救援先处理,外层处理未被恢复的失败

典型使用场景

  • 带回滚的发布:新版本部署失败时自动切回上一版并恢复配置
  • 配置变更保护:改配置前后做校验,校验不通过就恢复备份文件
  • 临时资源清理:无论成败都删除临时目录与临时账号
  • 失败留证:救援段收集日志、快照关键状态,便于事后分析
  • 可降级组件:可选组件安装失败时记录并继续,不阻塞主流程
  • 批量变更隔离:把高风险操作包成一个单元,失败只影响该单元

回滚与清理写法

回滚与清理写法
- name: 带回滚的发布
  block:
    - name: 备份当前版本
      ansible.builtin.copy:
        src: /opt/app/current
        dest: /opt/app/previous
        remote_src: true
        mode: "0755"

    - name: 切换新版本
      ansible.builtin.file:
        src: "/opt/app/releases/{{ app_version }}"
        dest: /opt/app/current
        state: link
      register: switch_result

    - name: 校验新版本可用
      ansible.builtin.command: /opt/app/current/bin/app --selftest
      changed_when: false

  rescue:
    - name: 回滚到上一版
      ansible.builtin.file:
        src: /opt/app/previous
        dest: /opt/app/current
        state: link

    - name: 记录失败信息
      ansible.builtin.debug:
        msg: "发布失败,已回滚;失败详情 {{ switch_result.msg | default('见上方输出') }}"

    - name: 回滚后仍然报错,避免整体被误判为成功
      ansible.builtin.fail:
        msg: "发布失败且已回滚,请人工确认"

  always:
    - name: 清理临时目录,无论成败
      ansible.builtin.file:
        path: /tmp/app-deploy
        state: absent

三段职责

段落执行时机典型内容
块正常流程变更动作与校验
救援块内失败时回滚、降级、记录失败信息
收尾始终执行清理临时资源、写状态标记
嵌套内层内层失败时局部处理,例如单项降级
嵌套外层内层未恢复时统一回滚整批变更
救援段成功执行后,该主机会继续参与同一 play 的后续任务,这是“局部失败不再扩散”的基础。但如果只是吞掉错误而不上报,整体会被判定为成功——需要显式中止时,在救援段末尾主动报错。
救援段自己要足够健壮:回滚动作引用了不存在的备份、清理动作依赖已被删掉的对象,都会让救援段失败,此时该主机整体失败且可能留在中间状态。救援段的实现应尽量简单、只依赖确定存在的资源。

什么时候值得用

当一组操作满足“失败后必须有人做点什么”(回滚、清理、留证)时,用三段式把这些动作固化成流程;如果失败后本来就应该停下来等人工处理,救援段只写记录与显式失败即可,不必强行设计自动回滚——不可靠的自动回滚比不回滚更危险。

易错点

  • 救援段吞掉错误却不上报,整体判定为成功,故障留到更晚才被发现
  • 救援段依赖的备份或资源实际不存在,回滚本身失败,主机卡在中间状态
  • 把收尾动作写在块内而不是收尾段,失败时清理被跳过,临时资源长期残留
  • 嵌套层数过多,内层已恢复的失败仍被外层重复处理,产生重复回滚
  • 期待框架自动回滚:没有显式写回滚步骤,失败后状态就是停在半途

数据来源与参考

  • Ansible 官方文档 Blocks(block/rescue/always 错误处理)
  • Ansible 官方文档 Error handling in playbooks
  • Ansible 官方文档 Handlers 与失败后的执行行为

整理校对:其其网ICT文档中心 · 本页地址:docs.qiqicto.com/automation/block-rescue-always-error-handling.html

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌​​‌​‌‌‌‌​‌‌​​​​‌​‌‌‌​‌​‌​‌‌‌​‌​​​‌‌​‌‌‌‌​‌‌​‌‌​‌​‌‌​​​​‌​‌‌‌​‌​​​‌‌​‌​​‌​‌‌​‌‌‌‌​‌‌​‌‌‌​​​‌​‌‌‌‌​‌‌​​​‌​​‌‌​‌‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌​‌​‌‌​​‌​‌‌​‌​‌‌‌​​‌​​‌‌​​‌​‌​‌‌‌​​‌‌​‌‌​​​‌‌​‌‌‌​‌​‌​‌‌​​‌​‌​​‌​‌‌​‌​‌‌​​​​‌​‌‌​‌‌​​​‌‌‌​‌‌‌​‌‌​​​​‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​‌​‌‌​‌​‌‌​​‌​‌​‌‌‌​​‌​​‌‌‌​​‌​​‌‌​‌‌‌‌​‌‌‌​​‌​​​‌​‌‌​‌​‌‌​‌​​​​‌‌​​​​‌​‌‌​‌‌‌​​‌‌​​‌​​​‌‌​‌‌​​​‌‌​‌​​‌​‌‌​‌‌‌​​‌‌​​‌‌‌​​‌​‌‌‌​​‌‌​‌​​​​‌‌‌​‌​​​‌‌​‌‌​‌​‌‌​‌‌​​