首页 文章

如何调试Ansible问题?

提问于
浏览
18

有时, ansible 没有帮助 . 例如,我现在正在尝试启动 coturn 服务器,该服务器在 systemd OS(Debian Jessie)上附带了init脚本 . Ansible认为它正在运行,但它在引擎盖下发生了什么?执行哪些命令,以及输出/退出代码是什么?

7 回答

  • 5

    调试模块

    • 最基本的方法是通过将 -vvv 添加到执行行来以更高的详细级别运行 ansible / ansible-playbook .

    • 用Python(Linux / Unix)编写的模块最彻底的方法是运行 ansible / ansible-playbook ,环境变量 ANSIBLE_KEEP_REMOTE_FILES 设置为 1 (在控制机器上) .

    它使Ansible在目标机器上保留它执行的Python脚本的完全副本(成功或不成功) .

    脚本的路径打印在Ansible日志中,对于常规任务,它们存储在SSH用户的主目录下: ~/.ansible/tmp/ .

    确切的逻辑嵌入在脚本中,并取决于每个模块 . 有些人使用Python标准或外部库,有些正在调用外部命令 .

    调试剧本

    • 与调试模块类似,使用 -vvv 参数增加详细级别会导致更多数据打印到Ansible日志

    • 自Ansible 2.1 a Playbook Debugger允许交互式调试失败的任务:检查,修改数据;重新运行任务 .

    调试连接

    • -vvvv 参数添加到 ansible / ansible-playbook 调用会导致日志包含连接的调试信息 .
  • 2

    这就是我想出来的 .

    Ansible将模块发送到目标系统并在那里执行它们 . 因此,如果您在本地更改模块,则更改将在运行playbook时生效 . 我的机器模块位于 /usr/lib/python2.7/site-packages/ansible/modulesansible-2.1.2.0 ) . service 模块位于core/system/service.py . Anisble modules(在 module_utils/basic.py 声明的AnsibleModule类的实例)具有log方法,该方法将消息发送到systemd日志(如果可用),或者回退到 syslog . 因此,在目标系统上运行 journalctl -f ,在本地向模块添加调试语句( module.log(msg='test') ),然后运行您的playbook . 您将在 ansible-basic.py 单位名称下看到调试语句 .

    此外,当您使用 -vvv 运行 ansible-playbook 时,您可以在 systemd 日志中看到一些调试输出,至少是调用消息,以及错误消息(如果有) .

    还有一件事,如果您尝试使用 pdbimport pdb; pdb.set_trace() )调试本地运行的代码,您很可能会遇到 BdbQuit 异常 . 那是因为创建线程时 python closes stdinansible worker) . 这里的解决方案是在运行 pdb.set_trace() 之前重新打开 stdin ,如建议here

    sys.stdin = open('/dev/tty')
    import pdb; pdb.set_trace()
    
  • 21

    如果任务不是您自己的,那么调试Ansible任务几乎是不可能的 . 与Ansible网站所说的相反 .

    不需要特殊的编码技能

    Ansible需要高度专业化的编程技能,因为它不是YAML或Python,它是两者的混乱 .

    之前已尝试过使用标记语言进行编程的想法 . XML一度在Java社区中非常流行 . XSLT也是一个很好的例子 .

    随着Ansible项目的增长,复杂性因此呈指数级增长 . 以OpenShift Ansible项目为例,它具有以下任务:

    - name: Create the master server certificate
      command: >
        {{ hostvars[openshift_ca_host]['first_master_client_binary'] }} adm ca create-server-cert
        {% for named_ca_certificate in openshift.master.named_certificates | default([]) | lib_utils_oo_collect('cafile') %}
        --certificate-authority {{ named_ca_certificate }}
        {% endfor %}
        {% for legacy_ca_certificate in g_master_legacy_ca_result.files | default([]) | lib_utils_oo_collect('path') %}
        --certificate-authority {{ legacy_ca_certificate }}
        {% endfor %}
        --hostnames={{ hostvars[item].openshift.common.all_hostnames | join(',') }}
        --cert={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.crt
        --key={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.key
        --expire-days={{ openshift_master_cert_expire_days }}
        --signer-cert={{ openshift_ca_cert }}
        --signer-key={{ openshift_ca_key }}
        --signer-serial={{ openshift_ca_serial }}
        --overwrite=false
      when: item != openshift_ca_host
      with_items: "{{ hostvars
                      | lib_utils_oo_select_keys(groups['oo_masters_to_config'])
                      | lib_utils_oo_collect(attribute='inventory_hostname', filters={'master_certs_missing':True}) }}"
      delegate_to: "{{ openshift_ca_host }}"
      run_once: true
    

    我想我们都同意这是YAML的编程 . 不是一个好主意 . 此特定代码段可能会失败并显示消息

    致命:[master0]:失败! => {“msg”:“条件检查项目!= openshift_ca_host”失败 . 错误是:评估条件时出错(项目!= openshift_ca_host):'item'未定义\ n \ n错误似乎已在' /home/user/openshift-ansible/roles/openshift_master_certificates/tasks/main.yml':第39行,第3列,但可能在文件的其他位置,具体取决于确切的语法问题 . \ n \ n违规行似乎是:\ n \ n \ n-名称:创建主服务器证书\ n ^ here \ n“}

    如果你点击这样的消息你就注定了 . 但我们有调试器吗?好的,我们来看看发生了什么 .

    master0] TASK: openshift_master_certificates : Create the master server certificate (debug)> p task.args
    {u'_raw_params': u"{{ hostvars[openshift_ca_host]['first_master_client_binary'] }} adm ca create-server-cert {% for named_ca_certificate in openshift.master.named_certificates | default([]) | lib_utils_oo_collect('cafile') %} --certificate-authority {{ named_ca_certificate }} {% endfor %} {% for legacy_ca_certificate in g_master_legacy_ca_result.files | default([]) | lib_utils_oo_collect('path') %} --certificate-authority {{ legacy_ca_certificate }} {% endfor %} --hostnames={{ hostvars[item].openshift.common.all_hostnames | join(',') }} --cert={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.crt --key={{ openshift_generated_configs_dir }}/master-{{ hostvars[item].openshift.common.hostname }}/master.server.key --expire-days={{ openshift_master_cert_expire_days }} --signer-cert={{ openshift_ca_cert }} --signer-key={{ openshift_ca_key }} --signer-serial={{ openshift_ca_serial }} --overwrite=false"}
    [master0] TASK: openshift_master_certificates : Create the master server certificate (debug)> exit
    

    这有什么用?它没有 .

    这里的要点是,使用YAML作为编程语言是一个非常糟糕的主意 . 这是一团糟 . 我们正在创造的混乱的症状无处不在 .

    一些额外的事实 . 在Openshift Ansible的Azure上提供先决条件阶段需要50分钟 . 部署阶段需要70多个分钟 . 每一次!首次运行或后续运行 . 并且无法将配置限制为单个节点 . 这个 limit 问题是2012年Ansible的一部分,它现在仍然是Ansible的一部分 . 这个事实告诉我们一些事情

    这里的要点是Ansible应该按预期使用 . 对于没有YAML编程的简单任务 . 适用于许多服务器,但它不应用于复杂的配置管理任务 .

    Ansible不是基础设施代码(IaC)工具 .

    如果您询问如何调试Ansible问题,那么您将以不打算使用它的方式使用它 . 不要将它用作IaC工具 .

  • 0

    Debugging roles/playbooks

    基本上,调试大型网络中大型库存的安全自动化只不过是调试分布式网络应用程序 . 它可能非常繁琐和精致,并且没有足够的用户友好工具 .

    因此,我相信你的问题的答案也是在我的小补充之前所有答案的结合 . 所以在这里:

    • 绝对必须:你必须要知道发生了什么,即你正在自动化什么,你期望发生什么 . 例如ansible未能检测到systemd单元作为运行或停止的服务通常意味着服务单元文件或服务模块中的错误,因此您需要1.识别错误,2 . 向供应商/社区报告错误,3 . 提供您的解决方法与TODO和链接到错误 . 4.修复错误后 - 删除您的解决方法

    • 使您的代码更容易调试使用模块,尽可能多

    • 为所有任务和变量赋予有意义的名称 .

    • 使用静态代码分析工具,如 ansible-lint . 这样可以避免真正愚蠢的小错误 .

    • 利用详细标志和日志路径

    • 明智地使用 debug 模块

    • “了解你的事实” - 有时将目标机器事实转储到文件中并将其拉到ansible master是有用的

    • 使用 strategy: debug 在某些情况下,您可能会在出错时陷入任务调试器 . 然后,您可以评估任务正在使用的所有参数,并决定下一步该做什么

    • 最后的手段是使用Python调试器,将其附加到本地ansible运行和/或执行模块的远程Python . 这通常很棘手:您需要允许打开机器上的其他端口,如果打开端口的代码是导致问题的端口?

    此外,有时“旁观”是有用的 - 连接到目标主机并增加其可调试性(更详细的日志记录)

    当然,日志收集可以更容易地跟踪由于安全操作而发生的变化 .

    正如您所看到的,与任何其他分布式应用程序和框架一样 - 调试能力仍然不如我们所希望的那样 .

    Filters/plugins

    这基本上是Python开发,调试任何Python应用程序

    Modules

    根据技术的不同,您需要了解本地和远程发生的事情,您最好选择足够容易远程调试的语言 .

  • 7

    您可以使用寄存器模块和调试模块来打印返回值 . 例如,我想知道我的脚本执行的返回代码是什么叫做“somescript.sh”,所以我将把我的任务放在游戏中,例如:

    - name: my task
      shell: "bash somescript.sh"
      register: output
    
    - debug:
      msg: "{{ output.rc }}"
    

    对于您可以在Ansible中访问的完整返回值,您可以查看此页面:http://docs.ansible.com/ansible/latest/common_return_values.html

  • 2

    您可能需要多个级别的调试,但最简单的是添加 ANSIBLE_STRATEGY=debug 环境变量,这将在第一个错误时启用调试器 .

  • 1

    第一种方法:通过 q 模块调试Ansible模块,并通过 q 模块将调试日志打印为 q('Debug statement') . 请检查 q 模块页面以检查在大多数情况下生成日志的 tmp 目录中的位置,它将在以下位置生成: $TMPDIR\q\tmp\q ,因此可以执行 tail -f $TMPDIR\q 以检查Ansible模块播放后生成的日志跑(参考:q module) .

    第二种方法:如果游戏正在 localhost 上运行,可以使用 pdb 模块调试相应文档之后的游戏:https://docs.ansible.com/ansible/latest/dev_guide/debugging.html

    第3种方法:使用Ansible debug 模块打印播放结果并调试模块(参考:Debug module) .

相关问题