如何调试Ansible问题?

2024-04-28 22:01:55 发布

您现在位置:Python中文网/ 问答频道 /正文

有时候,ansible做不到你想要的。而增加冗长也于事无补。例如,我现在尝试启动coturn服务器,它在systemd操作系统(Debian Jessie)上附带init脚本。Ansible认为它在运行,但事实并非如此。我该如何调查引擎盖下面发生的事?执行哪些命令,以及什么输出/退出代码?


Tags: 代码命令服务器脚本initdebianansible附带
3条回答

如果任务不是您自己的,则几乎不可能调试Ansible任务。与Ansible网站所述相反。

No special coding skills needed

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编程。不是个好主意。此特定代码段可能会失败,并显示如下消息

fatal: [master0]: FAILED! => {"msg": "The conditional check 'item != openshift_ca_host' failed. The error was: error while evaluating conditional (item != openshift_ca_host): 'item' is undefined\n\nThe error appears to have been in '/home/user/openshift-ansible/roles/openshift_master_certificates/tasks/main.yml': line 39, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Create the master server certificate\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工具。

调试模块

  • 最基本的方法是通过在执行行中添加-vvv,以更高的详细级别运行ansible/ansible-playbook

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

    它使Ansible在目标机器上保留它执行的Python脚本的精确副本(无论是否成功)。

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

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

调试剧本

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

  • 由于ansibe2.1aPlaybook Debugger允许调试交互失败的任务:检查、修改数据;重新运行任务。

调试连接

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

这是我想到的。

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

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

还有一件事,如果您尝试调试在本地运行的带有pdbimport pdb; pdb.set_trace())的代码,您很可能会遇到BdbQuit异常。这是因为在创建线程(ansible工作线程)时pythoncloses ^{}。这里的解决方案是在按照建议运行pdb.set_trace()之前重新打开stdin

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

相关问题 更多 >