Ansible 故障排查与调试技巧
Ansible 故障排查与调试技巧
故障排查基础
理解 Ansible 执行流程
# Ansible 执行流程
1. 加载配置(ansible.cfg)
2. 加载 Inventory
3. 加载 Playbook
4. 收集 Facts(如果启用)
5. 应用变量和模板
6. 执行任务
7. 调用 Handlers(如果需要)
8. 输出结果
调试模式
增加详细输出
# -v: 基本详细信息
ansible-playbook site.yml -v
# -vv: 更详细信息
ansible-playbook site.yml -vv
# -vvv: 包含 SSH 连接详细信息
ansible-playbook site.yml -vvv
# -vvvv: 最详细信息,包含模块参数和返回值
ansible-playbook site.yml -vvvv
使用 check mode(干运行)
# 检查模式:只显示会发生的变更,不实际执行
ansible-playbook site.yml --check
# 配合 diff 使用:显示变更的详细差异
ansible-playbook site.yml --check --diff
# 示例输出:
# --- before: /etc/nginx/nginx.conf (content)
# +++ after: /etc/nginx/nginx.conf (content)
# @@ -1,5 +1,5 @@
# worker_processes 4;
# -worker_connections 1024;
# +worker_connections 2048;
限制执行范围
# 只在特定主机上执行
ansible-playbook site.yml --limit web1.example.com
# 使用模式匹配
ansible-playbook site.yml --limit "web*.example.com"
# 使用组
ansible-playbook site.yml --limit webservers
# 多个目标
ansible-playbook site.yml --limit "web1,db1"
debug 模块
输出变量
---
- name: 调试变量
hosts: all
tasks:
- name: 显示主机名
debug:
msg: "主机名: {{ inventory_hostname }}"
- name: 显示所有 facts
debug:
var: ansible_facts
- name: 显示特定 fact
debug:
var: ansible_default_ipv4
- name: 显示注册的变量
shell: uname -a
register: kernel_info
- name: 显示命令输出
debug:
msg: "{{ kernel_info.stdout }}"
verbosity: 1
条件调试
- name: 条件调试
debug:
msg: "这是生产环境,请谨慎操作"
when: deployment_env == "production"
- name: 根据详细级别输出
debug:
msg: "详细的调试信息"
when: ansible_verbosity > 0
常见问题诊断
连接问题
# 问题:SSH 连接失败
# 解决方案1:检查 SSH 连接
ansible all -m ping -vvv
# 解决方案2:使用密码认证
ansible-playbook site.yml -k
# 解决方案3:指定 SSH 密钥
ansible-playbook site.yml --private-key ~/.ssh/mykey
# 解决方案4:跳过主机密钥检查
ansible-playbook site.yml -e "ansible_ssh_common_args='-o StrictHostKeyChecking=no'"
# 解决方案5:检查防火墙
ansible all -m raw -a "ufw status" -u root
权限问题
# 问题:权限不足
# 解决方案1:使用 become
- name: 需要 root 权限的任务
become: yes
apt:
name: nginx
state: present
# 解决方案2:指定 become 用户
- name: 以特定用户身份执行
become: yes
become_user: postgres
postgresql_user:
name: myapp
# 解决方案3:提供 sudo 密码
ansible-playbook site.yml -K
# 解决方案4:检查 sudo 配置
ansible all -m command -a "sudo -l" --become
Python 环境问题
# 问题:Python 版本不匹配或未安装
# 解决方案1:指定 Python 解释器
ansible-playbook site.yml -e "ansible_python_interpreter=/usr/bin/python3"
# 解决方案2:在 Inventory 中指定
[webservers]
web1.example.com ansible_python_interpreter=/usr/bin/python3
# 解决方案3:使用 ansible_python_interpreter 变量
[all:vars]
ansible_python_interpreter=auto_legacy_silent
# 解决方案4:安装 Python
ansible all -m raw -a "apt-get install -y python3" --become
Facts 收集问题
# 问题:Facts 收集失败或耗时太长
# 解决方案1:禁用 Facts 收集
- name: 不需要 Facts 的 Play
gather_facts: no
tasks:
- name: 简单任务
debug:
msg: "不需要 Facts"
# 解决方案2:只收集特定 Facts
- name: 收集特定 Facts
gather_facts: yes
gather_subset:
- network
- virtual
- hardware
# 解决方案3:使用 Facts 缓存
# ansible.cfg
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400
模块相关故障
模块未找到
# 问题:模块未找到
# 解决方案1:检查模块路径
ansible-doc -l | grep module_name
# 解决方案2:使用完整模块路径
- name: 使用完整路径
mynamespace.mycollection.my_module:
# 解决方案3:安装 collections
ansible-galaxy collection install community.general
模块参数错误
# 问题:模块参数错误
# 解决方案1:查看模块文档
ansible-doc module_name
# 解决方案2:使用 validate 参数
- name: 配置前验证
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
validate: 'nginx -t -c %s'
# 解决方案3:使用 check mode 测试
ansible-playbook site.yml --check
变量问题
变量未定义
# 问题:变量未定义导致错误
# 解决方案1:使用 default 过滤器
- name: 使用默认值
debug:
msg: "值: {{ my_var | default('default_value') }}"
# 解决方案2:使用 Jinja2 的 default
{{ my_var is defined | ternary(my_var, 'default') }}
# 解决方案3:检查变量是否定义
- name: 检查变量
debug:
msg: "变量未定义"
when: my_var is undefined
# 解决方案4:设置必需变量
- name: 确保必需变量存在
assert:
that:
- my_var is defined
- my_var | length > 0
fail_msg: "必需变量 my_var 未定义"
success_msg: "变量 my_var 已定义"
变量优先级问题
# 问题:变量优先级导致意外值
# 解决方案1:显示变量来源
ansible-playbook site.yml -vvv
# 解决方案2:使用 debug 显示所有同名变量
- name: 显示所有可能的变量
debug:
msg:
- "Play vars: {{ play_vars }}"
- "Host vars: {{ hostvars[inventory_hostname] }}"
# 解决方案3:使用 {{ hostvars }} 查看所有变量
- name: 显示主机所有变量
debug:
var: hostvars[inventory_hostname]
性能问题
执行缓慢
# 问题:Playbook 执行缓慢
# 解决方案1:增加并发数
# ansible.cfg
[defaults]
forks = 50
# 解决方案2:禁用 Facts 收集
- name: 快速执行
gather_facts: no
# 解决方案3:启用 pipelining
# ansible.cfg
[ssh_connection]
pipelining = True
# 解决方案4:使用 SSH 管道复用
# ansible.cfg
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
# 解决方案5:使用 async 异步执行
- name: 异步执行长任务
command: /usr/local/bin/long_task.sh
async: 3600
poll: 0
日志分析
启用日志记录
# ansible.cfg
[defaults]
log_path = /var/log/ansible.log
# 查看日志
tail -f /var/log/ansible.log
grep "ERROR" /var/log/ansible.log
grep "FAILED" /var/log/ansible.log
分析输出
# 使用 jq 分析 JSON 输出
ansible all -m setup -a "filter=ansible_*" --json | jq '.ansible_facts'
# 过滤失败任务
ansible-playbook site.yml 2>&1 | grep -A 5 "FAILED"
# 统计变更
ansible-playbook site.yml 2>&1 | grep "changed" | wc -l
使用 ansible-playbook
step 模式
# 逐步执行,每个任务前确认
ansible-playbook site.yml --step
从特定任务开始
# 从特定任务开始
ansible-playbook site.yml --start-at-task "安装 Nginx"
只执行特定 tags
# 只执行特定标签的任务
ansible-playbook site.yml --tags "nginx"
# 跳过特定标签
ansible-playbook site.yml --skip-tags "database"
常用调试工具
ansible-vault
# 查看 Vault 文件
ansible-vault view secrets.yml
# 编辑 Vault 文件
ansible-vault edit secrets.yml
# 重新加密
ansible-vault rekey secrets.yml
ansible-console
# 进入交互式控制台
ansible-console
# 常用命令
> webservers # 选择主机组
> yum name=nginx state=present # 执行任务
> cd web1.example.com # 切换主机
> gather_facts # 收集 Facts
> setup # 显示 Facts
> shell uname -r # 执行命令
ansible-inventory
# 显示 Inventory
ansible-inventory -i inventory.ini --list
# 以 YAML 格式显示
ansible-inventory -i inventory.ini --list --yaml
# 显示主机变量
ansible-inventory -i inventory.ini --host web1.example.com
# 验证 Inventory
ansible-inventory -i inventory.ini --graph
网络问题排查
测试连接
# 测试基本连接
ansible all -m ping
# 测试 SSH 连接
ansible all -m command -a "echo 'SSH connection OK'"
# 测试 Python 环境
ansible all -m command -a "python3 --version"
# 测试提权
ansible all -m command -a "whoami" --become
Playbook 语法检查
语法验证
# 检查 Playbook 语法
ansible-playbook site.yml --syntax-check
# 检查角色
ansible-playbook site.yml --syntax-check --list-tasks
# 显示 Playbook 信息
ansible-playbook site.yml --list-tasks
ansible-playbook site.yml --list-hosts
ansible-playbook site.yml --list-tags
真实故障排查案例
案例1:部署失败
# 现象:部署 Playbook 执行失败,输出不明确
# 诊断步骤:
# 1. 使用详细输出
ansible-playbook deploy.yml -vvv
# 2. 使用 check mode
ansible-playbook deploy.yml --check --diff
# 3. 单独测试失败的任务
ansible all -m template -a "src=templates/config.j2 dest=/etc/config"
# 4. 验证模板语法
- name: 验证 Jinja2 语法
template:
src: config.j2
dest: /tmp/test_config
check_mode: yes
# 5. 检查变量
- name: 显示变量
debug:
var: hostvars[inventory_hostname]
# 常见原因:
# - 模板语法错误
# - 变量未定义
# - 文件权限问题
# - 磁盘空间不足
案例2:循环错误
# 现象:循环任务执行失败
# 诊断步骤:
# 1. 显示循环变量
- name: 显示循环项
debug:
msg: "{{ item }}"
loop: "{{ my_list }}"
# 2. 检查列表内容
- name: 检查列表
set_fact:
list_content: "{{ my_list }}"
when: my_list is defined
# 3. 添加错误处理
- name: 循环任务
command: /usr/local/bin/process.sh {{ item }}
loop: "{{ my_list }}"
ignore_errors: yes
register: loop_results
- name: 显示失败的任务
debug:
msg: "失败: {{ item }}"
loop: "{{ loop_results.results }}"
when: item.failed
# 常见原因:
# - 列表为空
# - 列表包含无效项
# - 某个项导致命令失败
案例3:条件判断错误
# 现象:条件判断不按预期工作
# 诊断步骤:
# 1. 显示条件值
- name: 显示条件变量
debug:
msg: "{{ condition_var }}"
# 2. 测试条件
- name: 测试条件
debug:
msg: "条件为真"
when: condition_var
# 3. 使用 assert
- name: 验证条件
assert:
that:
- condition_var is defined
- condition_var | bool
fail_msg: "条件不满足"
success_msg: "条件满足"
# 常见原因:
# - 变量类型错误(字符串 vs 布尔)
# - 变量未定义
# - 条件逻辑错误
最佳实践
- 逐步验证: 使用 --check 和 --diff 预览变更
- 详细日志: 使用 -vvv 获取详细信息
- 小步前进: 分步验证,逐步构建 Playbook
- 错误处理: 添加适当的错误处理和回滚机制
- 文档记录: 记录常见问题和解决方案
- 版本控制: 使用 Git 管理变更
- 测试环境: 先在测试环境验证
- 日志分析: 定期分析日志找出潜在问题
总结
通过本教程,你已经了解了 Ansible 故障排查的方法:
- 调试模式和详细输出
- 常见连接、权限、Python 环境问题
- 模块和变量问题诊断
- 性能优化技巧
- 日志分析和使用工具
- 真实故障排查案例
- 故障排查最佳实践
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。







