1. 引言
Ansible 作为主流的无代理自动化运维工具,凭借其简洁的 YAML 语法和无需安装 Agent 的特性,在服务器配置管理、应用部署、任务编排等领域得到广泛应用。然而,在实际生产环境中,运维人员时常会遭遇各种故障——从最基础的连接失败,到复杂的变量覆盖、模块执行异常等。本文基于真实运维场景,系统梳理 Ansible 常见故障的排查思路与解决步骤,并总结可落地的最佳实践,帮助运维团队提升自动化稳定性。
2. 连接失败排查
2.1 SSH 连接问题
故障场景:执行 ansible all -m ping 时,部分主机返回 UNREACHABLE,错误信息类似:
fatal: [web-01]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).", "unreachable": true}
排查步骤:
1. **验证 SSH 基础连通性**:在控制节点手动执行 `ssh user@host`,确认是否能正常登录。若失败,检查:
– 目标主机是否开启 SSH 服务(systemctl status sshd)
– 防火墙是否放行 22 端口(iptables -L -n | grep 22)
– SSH 密钥是否已正确分发(ssh-copy-id)
2. **检查 Ansible 配置**:查看 `/etc/ansible/ansible.cfg` 或项目级 `ansible.cfg`,确认:
– host_key_checking = False(避免首次连接主机指纹确认)
– private_key_file 指向正确的私钥路径
– remote_user 是否具备 sudo 权限
3. **测试多因素认证**:若目标主机启用 SSH 双因子认证,需在 `ansible.cfg` 中设置 `pipelining = False`,否则可能导致连接中断。
解决示例:
# 在 ansible.cfg 中增加配置 [defaults] host_key_checking = False private_key_file = ~/.ssh/id_rsa_ansible remote_user = deploy [ssh_connection] pipelining = True # 启用流水线加速,但需确保 sudo 不需要 tty
2.2 权限不足导致失败
故障场景:Playbook 中执行需要 root 权限的任务(如安装软件包),返回 "msg": "Missing sudo password"。
排查步骤:
1. 确认目标主机 `/etc/sudoers` 中是否允许 `deploy` 用户执行 sudo 且无需密码:
`
deploy ALL=(ALL) NOPASSWD: ALL
`
2. 在 Playbook 中指定 `become: yes` 和 `become_method: sudo`,并确保 `ansible_become_password` 未在 inventory 中明文暴露(建议使用 `ansible-vault` 加密)。
故障复现与修复:
# 错误写法:缺少 become 参数
- name: Install nginx
apt:
name: nginx
state: present
# 正确写法
- name: Install nginx with sudo
become: yes
apt:
name: nginx
state: present
2.3 Python 版本兼容性
故障场景:连接成功但执行模块时报错 "module_stdout": "/bin/sh: python: command not found"。
原因:目标主机未安装 Python 或仅安装 Python 3(Ansible 2.5+ 默认依赖 Python 3,但部分旧模块仍需要 Python 2)。
排查步骤:
1. 登录目标主机检查 Python 版本:`python –version` 或 `python3 –version`
2. 在 inventory 中为每台主机指定 `ansible_python_interpreter`:
`ini
[webservers]
web-01 ansible_python_interpreter=/usr/bin/python3
web-02 ansible_python_interpreter=/usr/bin/python3
`
自动化修复:使用 raw 模块先安装 Python(需依赖 shell 可用):
- name: Ensure Python is installed raw: test -e /usr/bin/python || (apt -y update && apt install -y python3) become: yes
3. 模块执行失败
3.1 模块参数错误
故障场景:使用 copy 模块时,src 路径不存在导致任务失败。
排查方法:
• 开启 `-vvvv` 调试模式,查看模块实际发送的参数和返回的 JSON 数据。
• 使用 `check_mode: yes` 先做语法验证(不实际执行)。
示例:
ansible-playbook deploy.yml -vvvv --check
定位到错误:
fatal: [web-01]: FAILED! => {"changed": false, "msg": "Source /opt/conf/nginx.conf not found"}
解决:修正 src 路径或使用 file 模块创建缺失目录。
3.2 幂等性被破坏
故障场景:同一个 Playbook 重复执行时,每次都会触发 changed 状态,且可能导致服务重启。
根源:模块未实现幂等性。例如使用 command 模块执行 mkdir -p /data,虽然目录已存在,但任务仍报告 changed。
最佳实践:
• 优先使用 Ansible 原生模块(`file`、`copy`、`template`),它们天然具有幂等性。
• 若必须使用 `command`/`shell`,通过 `creates` 或 `when` 条件控制执行:
`yaml
– name: Create data directory
command: mkdir -p /data
args:
creates: /data
`
4. 超时与重试
4.1 任务执行超时
故障场景:通过 shell 模块执行耗时命令(如数据库迁移),任务默认超时时间(30秒)不足。
配置方法:
• 在 Playbook 级别设置 `timeout`:
`yaml
– name: Run long migration
shell: /opt/scripts/migrate.sh
async: 600 # 最长等待 600 秒
poll: 10 # 每 10 秒轮询一次状态
`
• 全局超时可在 `ansible.cfg` 中设置:
`ini
[defaults]
timeout = 60
`
4.2 网络抖动导致重试
故障场景:批量操作时,部分主机因网络瞬时中断导致任务失败。
解决方案:启用 Ansible 内置重试机制,在 Playbook 中添加 retries 和 delay:
- name: Install package with retry
apt:
name: curl
state: present
register: result
until: result is success
retries: 3
delay: 5
5. 变量覆盖问题
5.1 变量优先级混乱
故障场景:在 group_vars 中定义 nginx_port: 8080,但在 Playbook 中 vars 部分又定义了 nginx_port: 80,最终使用哪个值?
变量优先级(从高到低):
1. `–extra-vars` 命令行参数
2. Playbook 中 `vars`/`vars_files`
3. Inventory 中 `host_vars` > `group_vars`
4. `role` 中的 `defaults/main.yml`(最低)
调试技巧:在任务前使用 debug 模块打印变量值:
- name: Debug nginx_port
debug:
msg: "The port is {{ nginx_port }}"
5.2 变量引用错误
故障场景:"The variable 'app_version' is undefined"。
排查步骤:
1. 检查变量是否在 `group_vars` 或 `host_vars` 中定义。
2. 确认角色依赖是否加载(`meta/main.yml` 中的 `dependencies`)。
3. 使用 `ansible-inventory –list` 查看解析后的变量树。
6. 调试技巧
6.1 使用 `-vvvv` 查看完整通信
ansible-playbook deploy.yml -vvvv 2>&1 | tee debug.log
输出包含:
• SSH 连接详情(是否使用密钥、认证方式)
• 模块传输的 JSON 参数
• 目标主机返回的原始输出
• 变量解析后的具体值
6.2 利用 `debug` 模块定位问题
- name: Show facts
debug:
var: ansible_facts['os_family']
- name: Show complex variable
debug:
msg: "{{ item.key }} -> {{ item.value }}"
loop: "{{ my_dict | dict2items }}"
6.3 检查模式(Check Mode)
ansible-playbook deploy.yml --check --diff
• `–check`:模拟执行,不实际修改系统
• `–diff`:显示文件变更差异(适用于 `template`/`copy` 模块)
7. 最佳实践
7.1 确保 Playbook 的幂等性
• **原则**:无论执行多少次,结果相同且不产生副作用。
• **检查清单**:
– 避免使用 command/shell 执行非幂等操作
– 使用 state: present 或 state: absent 控制资源状态
– 服务重启操作放在 handlers 中,仅当配置变更时触发
7.2 规范化的目录结构
推荐项目结构:
ansible-project/
├── ansible.cfg
├── inventory/
│ ├── production/
│ │ ├── hosts
│ │ └── group_vars/
│ └── staging/
├── roles/
│ ├── common/
│ │ ├── tasks/
│ │ ├── handlers/
│ │ ├── templates/
│ │ └── defaults/
│ └── nginx/
└── playbooks/
├── deploy.yml
└── site.yml
7.3 版本控制与敏感信息管理
• **版本控制**:将所有 Playbook、Roles、Inventory 纳入 Git 管理。
• **敏感信息加密**:使用 `ansible-vault` 加密包含密码、密钥的变量文件:
`bash
ansible-vault encrypt group_vars/production/vault.yml
ansible-playbook deploy.yml –ask-vault-pass
`
• **CI/CD 集成**:在 Jenkins/GitLab CI 中预先执行 `ansible-lint` 和 `ansible-playbook –syntax-check`。
7.4 日志与监控
• 启用 Ansible 日志记录:在 `ansible.cfg` 中设置 `log_path = /var/log/ansible.log`
• 结合 ELK 或 Prometheus 分析执行失败趋势
• 对关键 Playbook 设置告警:通过 `failed_when` 和 `ignore_errors` 精细控制
8. 总结
Ansible 故障排查的核心在于:理解 SSH 连接机制、掌握变量优先级规则、善用调试工具、坚持幂等性设计。建议运维团队建立故障知识库,将每次事故的排查步骤、根因分析、解决方案记录下来,形成团队资产。同时,通过持续集成、代码审查、自动化测试等手段,从源头降低故障率。
自动化运维不是一蹴而就的,而是一个持续迭代、不断优化的过程。掌握本文的排查思路与最佳实践,将帮助你在面对 Ansible 故障时更从容、更高效。
