1

ansible故障排查

ansible简单但功能强大。ansible的简单意思是操作容易理解和遵循。能够理解和遵循对于在调试不希望的行为的时候就非常重要了。本章,我们将探索各种可以用于检查、反思、修改、以及调试ansible操作的各种方法:

  • 剧本日志及赘言。
  • 可变内省。
  • 调试本地代码执行。
  • 调试远程代码执行。

剧本日志及赘言(playbook logging and verbosity)

增加ansible输出赘言可以解决很多问题。从无效模块参数到不正确的连接命令,增加赘言对于指出错误源头至关重要。剧本日志和赘言在第二章大致上讨论了关于在执行剧本时如何保护秘密值。这一节会深入描述赘言和日志。

赘言

当使用ansible-playbook执行剧本的时候,输出会显示到标准输出。使用默认级别的赘言,显示非常少的信息。剧情在执行的时候,ansible-playbook会打印带剧情名字的PLAY头。然后每个任务,会打印带有任务名的TASK头。每个主机执行任务的时候,主机名和任务状态会一起打印出来,任务状态可能有ok, fatal, changed几种。没有更多的任务信息会打印出来,例如被执行的模块,提供给模块的参数,或者执行返回的数据。这对于优秀的剧本来说很好了,但我更倾向于更多的了解我的剧情。本书之前的例子中,我们都使用了一个赘言级别为2(-vv),因此我们能看到模块、模块参数、以及返回数据。

总共有五种级别的赘言级别:

  • none: 也就是默认的赘言级别。
  • 1(-v): 会显示返回值。
  • 2(-vv): 会显示输入数据及返回值。
  • 3(-vvv): 还提供详细的连接尝试。
  • 4(-vvvv): 会传递额外的赘言选项给连接插件(例如传递-vvv给ssh命令)。

增加赘言可以帮助准确指出错误可能发生的地方,以及提供更多了解ansible如何执行它的操作的额外信息。

超过1的赘言可能会导致敏感信息输出,因此在潜在共享环境下增加赘言级别的时候要小心些。

日志

默认情况下,ansible-playbook会将日志输出到标准输出,输出量可能超出终端模拟器使用的缓冲大小;因此,有必要将输出保存到指定文件中。各种shell都提供了一些机制能对输出进行重定向,更优雅的解决方法是将ansible-playbook日志重定向到文件。可以通过在ansible.cfg文件中配置log_path参数或使用环境变量ANSIBLE_LOG_PATH来设置。两者的值都是一个日志文件的路径。如果路径不存在,ansible会尝试创建这个文件。如果文件不存在,ansible会尝试创建文件。如果文件存在,那么,ansible会将输出附加到文件末尾,允许合并多个剧本执行日志。

使用日志文件和将日志在终端标准输出是不互相排斥的。两者同时发生,并且提供的赘言级别对两者都有影响。

可变内省

开发ansible剧本常见的问题就是对变量值的不恰当使用或无效假设。这点对于使用任务结果注册变量,并将其使用到后续的任务或模版中的时候就更加常见了。如果结果的期望元素没有正确访问,最终结果将是步伐预料的,或者甚至是有害的。

要检查不正确变量的使用,变量值的监测是关键。监测变量值最简单的方法就是使用debug模块。debug模块允许在屏幕上显示自由格式的文本,并与其他任务一样,模块参数也可以利用Jinja2模版语法。让我们来演示一下,创建一个执行任务的简单剧本,注册结果,然后用使用Jinja2语法呈现变量的调试语句展示结果:

---
- name: variable introspection demo
  hosts: localhost
  gather_facts: false

  tasks:
      - name: do a thing
        uri:
            url: https://derpops.bike
        register: derpops
      - name: show deppops
        debug:
            msg: "derpops value is {{ derpops }}"

运行剧本后,输出大致如下:

PLAYBOOK: introspection.yaml ***************************************************************************************************************************************************
1 plays in introspection.yaml

PLAY [variable introspection demo] *********************************************************************************************************************************************
META: ran handlers

TASK [do a thing] **************************************************************************************************************************************************************
task path: /Users/apple/Sites/workspace/k8s-cluster/ansibledemo/introspection.yaml:7
ok: [localhost] => {"changed": false, "connection": "close", "content_length": "2", "content_type": "text/plain;charset=UTF-8", "cookies": {}, "cookies_string": "", "date": "Sun, 12 Aug 2018 15:23:37 GMT", "msg": "OK (2 bytes)", "redirected": false, "server": "nginx", "status": 200, "url": "http://xxxx"}

TASK [show deppops] ************************************************************************************************************************************************************
task path: /Users/apple/Sites/workspace/k8s-cluster/ansibledemo/introspection.yaml:11
ok: [localhost] => {
    "msg": "derpops value is {u'status': 200, u'content_length': u'2', u'cookies': {}, u'url': u'https://xxxx', u'changed': False, u'server': u'nginx', 'failed': False, u'connection': u'close', u'content_type': u'text/plain;charset=UTF-8', u'date': u'Sun, 12 Aug 2018 15:23:37 GMT', u'redirected': False, u'cookies_string': u'', u'msg': u'OK (2 bytes)'}"
}
META: ran handlers
META: ran handlers

PLAY RECAP *********************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0   

debug模块具有不同的选项,可能会非常有用。接下来我们不直接打印debug模版使用的自由格式的字符串,这个模块可以直接简单的打印任意变量的值。我们可以使用var参数代替msg参数。 接着我们重复上面的例子,但是这次,我们使用var参数,我们将访问derpops变量的server子元素:

---
- name: variable introspection demo
  hosts: localhost
  gather_facts: false

  tasks:
      - name: do a thing
        uri:
            url: http://hzzdnb.zjtech.cc/cbapi/dev-batch-reg-result
        register: derpops
      - name: show deppops
        debug:
            var: derpops.server

然后执行剧本后,可以看到可以看到server的值如下:

TASK [show deppops] ************************************************************************************************************************************************************
task path: /Users/apple/Sites/workspace/k8s-cluster/ansibledemo/introspection.yaml:11
ok: [localhost] => {
    "derpops.server": "nginx"
}

注意,使用msg参数的时候,变量名需要使用模版中变量的语法,外边用双大括号包围;而使用var参数的时候,我们就不用对变量进行包装了。这是因为msg期望接受的是字符串,因此ansible需要呈现模版为字符串。然而,var期望的是单个未呈现变量。

可变子元素

另外一个在剧本中经常出错的是对复杂变量的子元素的不恰当引用。复杂变量不是字符串;它可能是列表或哈希。通常会引用错误的子元素,或者元素使用不同的类型不恰当的引用了。

列表很容易使用,哈希代表一些唯一挑战。哈希是无序key-value集合。

子元素以及python对象方法

调试代码执行

有时候只对变量数据进行日志和监测不足够定位问题。如果发生这样的情况,有必要深入ansible的内核。有两种重要的ansible代码集合:

  • 在ansible主机本地运行的代码。
  • 在ansible远程主机运行的代码。

调试本地代码

本地ansible代码是与ansible一起出现的最大一部分代码。所有的剧本、剧情、角色、以及任务解析代码都在本地。所有的任务结果处理代码以及传输代码都在本地。所有的代码除了传输给远程主机的装配模块代码都位于本地。

本地ansible代码可以分为三个主要部分:

  • 库存(inventory)
  • 剧本(playbook)
  • 运行器(runner)

库存代码处理解析来自目录树中主机文件、动态库存脚本、或两者组合中的库存数据。剧本代码用于将剧本yaml代码解析为ansible内部的python对象。运行器代码是处理进程fork、连接主机、执行模块、处理结果、以及很多其他事情的核心API。学习启动调试的一般区域是在实践中进行的,但是这里描述的只是一般领域的一个起点。

因为ansible是用python实现的,调试本地代码执行的是python debugger, pdb。这个工具可以让我们给ansible代码里边插入断点,并逐行的进行交互执行代码。这对于在执行本地代码时检查ansible内部状态非常有用。有很多书籍和网站都介绍了pdb的使用,你可以通过python pdb进行搜索,这里不做重复了。基础是编辑源代码来调试,插入新代码行创建断点,然后执行代码。 代码执行会在断点处停止,并提供提示来探索代码的状态。

调试库存代码

库存代码处理查找库存源、读取或执行发现的文件、解析库存数据到库存对象、以及从库存加载变量数据。要调试ansible如何处理库存,必须在inventory/__init__.py或inventory/子目录中的其他文件中添加断点。

对于linux系统或mac系统,我们可以通过下面的方式查找ansible源码所在的目录:

pip show ansible

我自己的ansible源码位于/usr/local/lib/python2.7/site-packages/ansible。

断点调试回头整理pdb调试相关的资料。

调试剧本代码
调试运行器代码

调试远程代码

调试行为插件

总结

词汇

  • 最大一部分(最好一部分): the lion's share of。

目录


老将廉颇
878 声望297 粉丝