Ansible失败控制需分场景:ignore_errors仅对模块执行完但返回failed的任务生效;对不可达主机需用ignore_unreachable,语法错误等解析阶段问题无法忽略;failed_when可精细判断失败条件;force_handlers确保失败后handler仍执行。

Ansible 默认遇到任务失败就中止整个 play,但生产环境需要更灵活的控制:该停的时候停,该跳过的时候跳过,该报错的时候还得精准报错。关键不是“全忽略”或“全中断”,而是分场景、分层级做判断。
什么时候用 ignore_errors: yes
它只对模块已运行完成、但返回 failed: true 的任务生效,比如:
- yum/apt 安装一个在部分节点已下线的旧包(如
name: old-monitor-agent state: present) - shell 执行
cat /etc/app/feature.conf,但某些节点没这个文件 - service 模块重启一个仅部署在部分节点的服务(如
name: telegraf state: restarted)
加了 ignore_errors: yes 后,该任务标记为 ignored,play 继续执行,主机最终统计仍为 ok,不会影响后续任务。
什么时候不能靠 ignore_errors
以下情况它完全无效,强行加也没用:
- 目标主机 不可达(UNREACHABLE),比如网络断开、SSH 服务宕机 —— 此时要用
ignore_unreachable: yes(必须写在 task 级) - playbook 语法错误、变量未定义、Jinja2 渲染失败 —— 这类属于解析阶段错误,Ansible 根本不会走到执行环节
- 模块调用失败(如传了非法参数导致模块崩溃)—— 实际未进入正常执行流
比 ignore_errors 更精细的控制:failed_when
有些命令退出码非 0 并不等于失败,比如 grep -q 没匹配到内容就返回 1。直接 ignore_errors 会掩盖真实异常(如权限拒绝、磁盘满)。推荐写法:
-
failed_when: result.rc not in [0, 1]→ 把 rc=1 当作正常流程 -
failed_when: "'Permission denied' in result.stderr"→ 只在 stderr 含权限错误时才失败 -
failed_when: result.stdout | length == 0→ 输出为空才报错
这样既保持流程连续,又保留对真正故障的敏感度。
失败后仍要触发 Handler:force_handlers
默认情况下,只要任意任务失败,play 就终止,之前 notify 过的 handler 也不会运行 —— 这会导致配置改了但服务没重启,极易引发事故。
解决方法是在 play 级加:
-
force_handlers: yes→ 即使某个任务失败,所有已通知的 handler 仍会在最后统一执行
典型场景:先 copy 配置文件并 notify 重启 nginx,再执行一条可能失败的健康检查命令。加了 force_handlers: yes,nginx 一定能按新配置重启。


















