第十章、对ansible进行故障排除测试

一、对playbook进行故障排除

1、ANSIBLE日志文件

默认情况下,红帽ansible引擎配置为不将其输出记录到任何日志文件。它提供了一个内置日志基础架构,但是可以通过ansible.cfg配置文件的default配置文件部分中的log_path参数进行配置、或通过$ANSIBLE_LOG_PATH环境变量来配置。如果进行了其中任一项配置,ansible会把来自ansible和ansible-playbook命令的输出结果存储到ansible.cfg配置文件中或$ANSIBLE_LOG_PATH环境变量配置的日志文件中。当然这些日子平时用的比较少,因为运行playbook时就自动输出结果了

//打开默认存储位置

[student@server ansible]$ vim ansible.cfg
#log_path = /var/log/ansible.log
[student@server ansible]$ sudo touch /var/log/ansible.log
[student@server ansible]$ ll /var/log/ansible.log 
-rw-r--r-- 1 root root 0 Nov  4 17:02 /var/log/ansible.log
//修改权限
[student@server ansible]$ sudo chown student.student /var/log/ansible.log 
[student@server ansible]$ ll /var/log/ansible.log 
-rw-r--r-- 1 student student 0 Nov  4 17:02 /var/log/ansible.log
//任意运行一个playbook就可以导入日志了
[student@server ansible]$ cat /var/log/ansible.log 
2022-11-04 17:08:16,993 p=46685 u=student n=ansible | PLAY [test] ********************************************************************
2022-11-04 17:08:17,006 p=46685 u=student n=ansible | TASK [Gathering Facts] *********************************************************

2、调试模块

通过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       //显示变量的详细内容

var这里也可以使用msg,不过需要给变量加 “{ { }}”

3、管理错误:

playbook运行期间可能会发生多种问题,他们主要与playbook或它使用的任何模板的语法相关,或者源自与受管主机的连接问题(例如,清单文件中受管主机的主机名称存在错误)。这些错误在执行时由ansible-playbook命令发出。

但也可以使用--syntax-check选项检查playbook的YAML语法。在使用playbook之前,或者遇到了相关问题时,最好对其运行语法检查格式是否有错误(适用于管理比较大的项目)。

[root@foundation0 ansible]# ansible-playbook --syntax-check a.yml

也可以使用--step选项来逐步调试playbook,一次一个任务。ansible-playbook --step命令以交互方式提示确认希望运行的每个任务。
//交互式的方式询问是否执行

[student@server ansible]$ ansible-playbook test.yml --step

PLAY [test] ********************************************************************
Perform task: TASK: Gathering Facts (N)o/(y)es/(c)ontinue: y

二、对ansible受管主机进行故障排除

将检查模式用作测试工具

可以使用ansible-playbook --check命令对playbook运行烟雾测试(也就是预执行)。此选项会执行playbook,但不对受管主机的配置进行更改。如果playbook中使用的模块支持检查模式,则将显示已在受管主机上进行的更改,但不干预他们。如果模块不支持检查模式,则不显示更改,但模块仍然不执行任何操作。

语法:ansible-playbook --check playbook.yml

注意:如果使用了条件,则ansible-playbook --check可能无法正常运作,只是模拟。

还可以通过在play中添加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模块,可用于测试和调试受管主机上的问题。

1、uri模块

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",       #网页返回内容,因为我们定义了return_content: yes
        "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   

2、script模块

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

3、stat模块

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   

4、assert模块

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         ——判断cy这个变量是被定义了的
        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   

fail 判断的条件为真的时候 中止playbook
assert 判断的条件为假的时 中止playbook

四、对连接进行故障排除

使用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模块来测试是否能够连接到受管主机,也可以传递选项,测试是否正确配置了特权升级和凭据。

[student@server ansible]$ ansible all -m ping
node1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}

猜你喜欢

转载自blog.csdn.net/cxyxt/article/details/127692743
今日推荐