调试靠的是分层观察
playbook 出错时常见的无效做法是一直加 debug 任务。更有效的顺序是:先用清单类开关确认这次到底要跑哪些任务、哪些主机,再用逐步模式把执行停在可疑任务前,然后用输出详细度看连接与参数细节,最后才用交互式调试器进入现场。每一层解决不同问题,从外到内逐层收窄。
基本信息
| 清单预览 | --list-tasks、--list-hosts、--list-tags 只列不跑 |
|---|---|
| 逐步确认 | --step 每个任务前询问,交互可回答 y/n/c |
| 从中间开始 | --start-at-task 从指定任务名开始执行 |
| 详细度 | -v 到 -vvvv 逐级增加,连接层细节在 -vvv 以上 |
| 交互调试 | 任务级 debugger: on_failed,配合配置项启用调试器 |
| 变量打印 | ansible.builtin.debug 的 msg 与 var 两种输出方式 |
典型使用场景
- 接手陌生仓库:先 --list-tasks --list-hosts,建立“会动谁、动什么”的全局认识
- 怀疑目标主机选错:--list-hosts 直接列出命中清单,不必真跑
- 任务在中间失败:用 --start-at-task 从失败点重跑,避免重复前置步骤
- 只想到某一步:--step 逐任务确认,遇可疑点停下检查现场
- 连接或提权失败:-vvv 及以上能看到实际使用的连接命令与参数
- 变量不是预期值:先在任务里 debug 打印,再判断是优先级问题还是取值时机问题
命令与任务写法
命令与任务写法
# 先看清楚会跑什么,再做任何变更
ansible-playbook -i inventory site.yml --list-tasks --list-hosts
# 从某个任务开始,只在一台主机上验证
ansible-playbook -i inventory site.yml --start-at-task '写配置文件' --limit web1
# 逐任务确认(交互回答 y/n/c),并显示连接细节
ansible-playbook -i inventory site.yml --step -vvv
# 任务内打印变量(yaml 片段)
# - name: 看看变量实际值
# ansible.builtin.debug:
# var: app_version
#
# - name: 自定义格式输出
# ansible.builtin.debug:
# msg: "当前 {{ inventory_hostname }} 的版本是 {{ app_version }}"
# failed_when: false # 排障期间避免因断言误中断手段与适用问题
| 手段 | 回答的问题 | 注意点 |
|---|---|---|
| --list-tasks | 这次会执行哪些任务 | 只列静态结构,不评估条件是否命中 |
| --list-hosts | 这次会操作哪些主机 | 确认清单与 limit 的实际交集 |
| --step | 这一步是不是该做 | 交互式,不适合放自动化脚本 |
| --start-at-task | 从失败点继续 | 跳过的前置任务若改变了状态,结果可能与完整运行不同 |
| -vvv 以上 | 连接、参数、提权到底怎么执行 | 输出量大,敏感值可能被打印 |
| 任务调试器 | 失败现场逐帧检查变量与继续执行 | 需在配置中启用,生产环境谨慎 |
失败后重跑前先判断幂等性:如果前面的任务本身幂等,--start-at-task 基本安全;如果其中夹着非幂等的命令类任务,直接跳过去可能让状态不一致,此时更稳妥的做法是整段重跑或先在测试环境复现。
排障时常用的 -vvv 与 debug 打印会把变量原值打到终端与日志中,含口令、令牌的任务会被连带暴露。排障任务应当限定 --limit 与 --tags,排完立即移除临时 debug,并对敏感任务设置 no_log。
顺序建议
先静态看清楚(列表类开关),再小范围真跑(limit 加 start-at-task),再逐步确认(step),再放大细节(提高详细度),最后才进调试器。反过来做的话,最容易出现“信息太多、问题没定位到”的僵局。