对ANSIBLE进行故障排除
对playbook进行故障排除
ANSIBLE日志文件
默认情况下,红帽ansible引擎配置为不将其输出记录到任何日志文件。它提供了一个内置日志基础架构,可以通过ansible.cfg配置文件的default部分中的log_path参数进行配置,或通过$ANSIBLE_LOG_PATH环境变量来配置。如果进行了其中任一/全部配置,ansible会把来自ansible和ansible-playbook命令的输出存储到通过ansible.cfg配置文件或$ANSIBLE_LOG_PATH环境变量配置的日志文件中。
如果将ansible配置为将日志文件写入/var/log。则红帽建议配置logrotate来管理ansible日志文件。
调试模块
通过debug模块可以了解play中发生的情况。此模块可以显示play中某个点上某个变量的值。在对使用变量相互通信的任务(例如,将一项任务的输出用作后续任务的输出)进行调试时,此功能可以发挥关键作用。
以下示例使用debug任务中的msg和var设置,第一个示例显示ansible_facts[‘memfree_mb’]事实的运行时值,作为ansible-playbook输出中显示的消息的一部分。第二个示例显示output变量的值。
[root@server ansible]# vim a.yml
---
- name: test
hosts: node1
tasks:
- name: free mem
debug:
msg: this system free mem is {{ansible_memfree_mb}}
register: output
- name: output vars
debug:
var: output
管理错误:
playbook运行期间可能会发生多种问题,他们主要与playbook或它使用的任何模板的语法相关,或者源自与受管主机的连接问题(例如,清单文件中受管主机的主机名称存在错误)。这些错误在执行时由ansible-playbook命令发出。
可以使用--syntax-check选项检查playbook的YAML语法。在使用playbook之前,或者遇到了相关问题时,最好对其运行语法检查。
[root@foundation0 ansible]# ansible-playbook --syntax-check a.yml
也可以使用--step选项来逐步调试playbook,一次一个任务。ansible-playbook --step命令以交互方式提示确认希望运行的每个任务。
[root@foundation0 ansible]# ansible-playbook --step a.yml
对ansible受管主机进行故障排除
将检查模式用作测试工具
可以使用ansible-playbook --check命令对playbook运行烟雾测试。此选项会执行playbook,但不对受管主机的配置进行更改。如果playbook中使用的模块支持检查模式,则将显示已在受管主机上进行的更改,但不干预他们。如果模块不支持检查模式,则不显示更改,但模块仍然不执行任何操作。
语法:ansible-playbook --check playbook.yml
注意:如果使用了条件,则ansible-playbook --check可能无法正常运作。
还可以通过check_mode设置控制各个任务是否以检查模式运行。如果任务设置了check_mode: yes,则它始终以检查模式运行,不论是否将--check选项传递给ansible-playbook。同样,如果任务设置了check_mode: no,它将始终正常运行,即使将--check传递给ansible-playbook。
示例1:
[root@server ansible]# vim b.yml
---
- name: touch file
hosts: node1
tasks:
- name: touch file1
file:
path: /tmp/file1
state: touch
[root@server ansible]# ansible-playbook b.yml --check
PLAY [touch file] **********************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [node1]
TASK [touch file1] *********************************************************************************
ok: [node1]
PLAY RECAP *****************************************************************************************
node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
此时我们去node1中去验证/tmp目录下是否创建了file1文件,发现并没有创建file1文件,说明通过--check选项对我们playbook检查时,并不会真正的对受控主机进行更改,和我之前给大家讲的-C是一样的,属于预执行。
[root@server ansible]# ssh root@node1
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Thu May 13 17:33:59 2021 from 172.16.30.30
[root@node1 ~]# ls /tmp/
systemd-private-d415e2d79c8344a699f94b887c2e33d6-bluetooth.service-LnOEkh
systemd-private-d415e2d79c8344a699f94b887c2e33d6-bolt.service-pEp4ii
systemd-private-d415e2d79c8344a699f94b887c2e33d6-colord.service-iWH4dE
systemd-private-d415e2d79c8344a699f94b887c2e33d6-fwupd.service-xrlwGf
systemd-private-d415e2d79c8344a699f94b887c2e33d6-geoclue.service-FhuTfg
systemd-private-d415e2d79c8344a699f94b887c2e33d6-ModemManager.service-OLIlWO
systemd-private-d415e2d79c8344a699f94b887c2e33d6-rtkit-daemon.service-KmmVEn
tracker-extract-files.0
vmware-root_791-4282302006
[root@node1 ~]#
示例2:在playbook当中设置check_mode参数为yes,再次执行该playbook
[root@server ansible]# cat b.yml
---
- name: touch file
hosts: node1
check_mode: yes
tasks:
- name: touch file1
file:
path: /tmp/file1
state: touch
当我们正常使用ansible-playbook命令执行时,它仍然处于预执行,也就是说不管你手动是否添加了--check选项,它都属于预执行。
[root@server ansible]# ansible-playbook b.yml
PLAY [touch file] **********************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [node1]
TASK [touch file1] *********************************************************************************
ok: [node1]
PLAY RECAP *****************************************************************************************
node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
示例3:在playbook当中设置check_mode参数为no,再次执行该playbook
[root@server ansible]# cat b.yml
---
- name: touch file
hosts: node1
check_mode: no
tasks:
- name: touch file1
file:
path: /tmp/file1
state: touch
我们在执行该playbook的时候添加--check选项,此时我们会发现并没有进行预执行,而是对受控主机进行了修改
[root@server ansible]# cat b.yml
---
- name: touch file
hosts: node1
check_mode: no
tasks:
- name: touch file1
file:
path: /tmp/file1
state: touch
验证:
[root@server ansible]# ssh root@node1
Activate the web console with: systemctl enable --now cockpit.socket
Last login: Thu May 13 17:40:49 2021 from 172.16.30.30
[root@node1 ~]# ls /tmp/
file1
systemd-private-d415e2d79c8344a699f94b887c2e33d6-bluetooth.service-LnOEkh
systemd-private-d415e2d79c8344a699f94b887c2e33d6-bolt.service-pEp4ii
systemd-private-d415e2d79c8344a699f94b887c2e33d6-colord.service-iWH4dE
systemd-private-d415e2d79c8344a699f94b887c2e33d6-fwupd.service-xrlwGf
systemd-private-d415e2d79c8344a699f94b887c2e33d6-geoclue.service-FhuTfg
systemd-private-d415e2d79c8344a699f94b887c2e33d6-ModemManager.service-OLIlWO
systemd-private-d415e2d79c8344a699f94b887c2e33d6-rtkit-daemon.service-KmmVEn
tracker-extract-files.0
vmware-root_791-4282302006
[root@node1 ~]#
此外,ansible-playbook命令还提供一个 --diff 选项。此选项可报告对受管主机上的模板文件所做的更改。如果与--check选项结合,则命令输出中会显示这些更改,但实际上不进行更改。
示例1:只使用--diff,它真正意义上是执行了playbook的,同时会把受控主机前后更改的信息给列出来。
[root@server ansible]# cat b.yml
---
- name: touch file
hosts: node1
tasks:
- name: touch file2
file:
path: /tmp/file2
state: touch
[root@server ansible]# ansible-playbook --diff b.yml
PLAY [touch file] **********************************************************************************
TASK [Gathering Facts] *****************************************************************************
ok: [node1]
TASK [touch file2] *********************************************************************************
--- before
+++ after
@@ -1,6 +1,6 @@
{
- "atime": 1620898998.0370545,
- "mtime": 1620898998.0370545,
+ "atime": 1620898998.04052,
+ "mtime": 1620898998.04052,
"path": "/tmp/file2",
- "state": "absent"
+ "state": "touch"
}
changed: [node1]
PLAY RECAP *****************************************************************************************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
使用模块进行测试
一些模块可以提供关于受管主机状态的额外信息。下表中列出了一些ansible模块,可用于测试和调试受管主机上的问题。
uri模块提供了一种方式,可以检查RESTful API是否返回需要的内容
示例1:
新建a.yml的playbook,然后检查url为http://server.example.com,设置需要返回内容,把检查该url执行的结果注册成变量cy,并把cy变量内容显示出来,我们会发现该url的内容在变量cy.content中显示出来了。
[root@server ansible]# vim a.yml
---
- name: test
hosts: node1
tasks:
- name: uri test
uri:
url: http://server.example.com
return_content: yes
register: cy
- name: debug1
debug:
var: cy
[root@server ansible]# ansible-playbook a.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
TASK [uri test] ****************************************************************
ok: [node1]
TASK [debug1] ******************************************************************
ok: [node1] => {
"cy": {
"accept_ranges": "bytes",
"changed": false,
"connection": "close",
"content": "chenyu\n",
"content_length": "7",
"content_type": "text/html; charset=UTF-8",
"cookies": {},
"cookies_string": "",
"date": "Fri, 14 May 2021 14:33:17 GMT",
"elapsed": 0,
"etag": "\"7-5c24b04a72bbf\"",
"failed": false,
"last_modified": "Fri, 14 May 2021 14:25:39 GMT",
"msg": "OK (7 bytes)",
"redirected": false,
"server": "Apache/2.4.37 (Red Hat Enterprise Linux)",
"status": 200,
"url": "http://server.example.com"
}
}
PLAY RECAP *********************************************************************
node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
示例2:
检查url为http://server.example.com,设置不需要返回内容,把检查该url执行的结果注册成变量cy,并把cy变量内容显示出来,我们会发现压根就没有cy.content这个变量。
[root@server ansible]# vim a.yml
---
- name: test
hosts: node1
tasks:
- name: uri test
uri:
url: http://server.example.com
return_content: no
register: cy
- name: debug1
debug:
var: cy
[root@server ansible]# ansible-playbook a.yml //会发现变量cy中压根就没有content的子项。
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
TASK [uri test] ****************************************************************
ok: [node1]
TASK [debug1] ******************************************************************
ok: [node1] => {
"cy": {
"accept_ranges": "bytes",
"changed": false,
"connection": "close",
"content_length": "7",
"content_type": "text/html; charset=UTF-8",
"cookies": {},
"cookies_string": "",
"date": "Fri, 14 May 2021 14:34:56 GMT",
"elapsed": 0,
"etag": "\"7-5c24b04a72bbf\"",
"failed": false,
"last_modified": "Fri, 14 May 2021 14:25:39 GMT",
"msg": "OK (7 bytes)",
"redirected": false,
"server": "Apache/2.4.37 (Red Hat Enterprise Linux)",
"status": 200,
"url": "http://server.example.com"
}
}
PLAY RECAP *********************************************************************
node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
script模块支持在受管主机上执行脚本,如果该脚本的返回代码不为零,则报告失败。脚本必须存在于控制节点上,传输到受管主机并在其上执行。
示例:
写一个脚本adhoc.sh,并使用script模块,讲该脚本传输到受控主机上执行
[root@server ansible]# cat adhoc.sh
#!/bin/bash
touch /tmp/file2
[root@server ansible]# cat b.yml
---
- name: test
hosts: all
tasks:
- name: script test
script: /etc/ansible/adhoc.sh
[root@server ansible]# ansible-playbook b.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
ok: [node2]
TASK [script test] *************************************************************
changed: [node2]
changed: [node1]
PLAY RECAP *********************************************************************
node1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
node2 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
验证:
验证发现该脚本在每个受控主机中都执行了
[root@node1 ~]# ls /tmp/
file2
[root@node2 ~]# ls /tmp
file2
stat模块收集文件的事实,与stat命令非常相似。可以使用它来确定受控主机的文件是否存在或获取有关该文件的其他信息。如果文件不存在,则stat任务不会失败,但其注册的变量会为*.stat.exists报告false。
示例1:
检查受控节点node1的/tmp/abc文件是否存在
[root@server ansible]# cat c.yml
---
- name: test
hosts: node1
tasks:
- name: stat test
stat:
path: /tmp/abc
register: cy
- name: debug1
debug:
var: cy
执行c.yml这个playbook,我们发现cy.stat.exists变量的值为false,说明此文件在node1上不存在。
[root@server ansible]# ansible-playbook c.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
TASK [stat test] ***************************************************************
ok: [node1]
TASK [debug1] ******************************************************************
ok: [node1] => {
"cy": {
"changed": false,
"failed": false,
"stat": {
"exists": false
}
}
}
PLAY RECAP *********************************************************************
node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
示例2:
检查受控节点node1的/tmp/file2文件是否存在
[root@server ansible]# cat c.yml
---
- name: test
hosts: node1
tasks:
- name: stat test
stat:
path: /tmp/file2
register: cy
- name: debug1
debug:
var: cy
执行该playbook,我们发现cy.stat变量的值里面有/tmp/file2的相关信息,说明该文件存在
[root@server ansible]# ansible-playbook c.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
TASK [stat test] ***************************************************************
ok: [node1]
TASK [debug1] ******************************************************************
ok: [node1] => {
"cy": {
"changed": false,
"failed": false,
"stat": {
"atime": 1621004553.648727,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 0,
"charset": "binary",
"checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"ctime": 1621003594.5807807,
"dev": 2051,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 136,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "inode/x-empty",
"mode": "0644",
"mtime": 1621003594.5807807,
"nlink": 1,
"path": "/tmp/file2",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 0,
"uid": 0,
"version": "3070191212",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
}
PLAY RECAP *********************************************************************
node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
assert是fail模块的一种替代选择。assert模块支持that选项,该选项取一个条件列表作为值。如果这些条件中的任何一个为false,则任务失败
示例1:
当assert模块的参数that的判断是一个真命题时,会成功执行任务。
[root@server ansible]# cat c.yml
---
- name: test
hosts: node1
tasks:
- name: stat test
stat:
path: /tmp/file2
register: cy
- name: fail
assert:
that:
- cy.stat.block_size is defined
fail_msg: chenyu failed
success_msg: chenyu success
- name: debug1
debug:
msg: chenyu
[root@server ansible]# ansible-playbook c.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
TASK [stat test] ***************************************************************
ok: [node1]
TASK [fail] ********************************************************************
ok: [node1] => {
"changed": false,
"msg": "chenyu success"
}
TASK [debug1] ******************************************************************
ok: [node1] => {
"msg": "chenyu"
}
PLAY RECAP *********************************************************************
node1 : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
示例2:
当assert模块的参数that判断是多个判断时,其中一个真、一个假,则返回失败消息
[root@server ansible]# cat c.yml
---
- name: test
hosts: node1
tasks:
- name: stat test
stat:
path: /tmp/file2
register: cy
- name: fail
assert:
that:
- cy.stat.block_size is defined
- cy.stat.path is not defined
fail_msg: chenyu failed
success_msg: chenyu success
- name: debug1
debug:
msg: chenyu
[root@server ansible]# ansible-playbook c.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1]
TASK [stat test] ***************************************************************
ok: [node1]
TASK [fail] ********************************************************************
fatal: [node1]: FAILED! => {
"assertion": "cy.stat.path is not defined",
"changed": false,
"evaluated_to": false,
"msg": "chenyu failed"
}
PLAY RECAP *********************************************************************
node1 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
对连接进行故障排除
使用ansible管理主机时的许多常见问题与主机连接相关,也与围绕远程用户和特权升级的配置问题有关。
如果遇到与受管主机身份验证相关的问题,请确保在配置文件或play中正确设置了remote_user。还应确认设置了正确的SSH密钥或为该用户提供正确的密码。
务必正确设置become,并且使用正确的become_user(默认为root)。确认输入了正确的sudo密码并且受管主机上正确配置了sudo。
一个更微妙的问题与清单设置有关。对于具有多个网络地址的复杂服务器,连接该系统时可能需要使用特定的地址或DNS名称。用户可能不希望将改地址用作计算机的清单名称,从而提高可读性。可以设置主机清单变量ansible_host,它会用其他名称或IP地址覆盖清单名称并供ansible用于连接该主机。该变量可以在该主机的host_vars文件或目录中设置,或者在清单文件本身中设置。
[root@server ansible]# cat hosts
node1
node100 ansible_host=node1
[root@server ansible]# cat a.yml
---
- name: test
hosts: node100
tasks:
- name: touch file
file:
path: /tmp/aaa
state: touch
执行该playbook后,我们去验证一下是否在node1中创建了/tmp/aaa文件
[root@server ansible]# ansible-playbook a.yml
PLAY [test] ********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [node100]
TASK [touch file] **************************************************************
changed: [node100]
PLAY RECAP *********************************************************************
node100 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
验证:验证得知,我们对node100主机进行操作,实际上是对node1主机进行执行任务
[root@node1 ~]# ls /tmp/
aaa
使用临时命令测试受管主机
下面几个示例演示了一些可通过使用临时命令在受管主机上执行的检查。
可以使用ping模块来测试是否能够连接到受管主机,也可以传递选项,测试是否正确配置了特权升级和凭据。