常见问题解答
以下是一些常见问题及其解答。
所有的模块都去哪儿了?
2019 年 7 月,我们宣布集合(collections)将成为 Ansible 内容分发的未来。集合是一种用于 Ansible 内容的分发格式,其中可以包含 Playbook、角色、模块和插件。在 Ansible 2.9 中,我们增加了对集合的支持。在 Ansible 2.10 中,我们从主要的 ansible/ansible 仓库中提取了大多数模块,并将它们放入了 集合 中。集合可以由 Ansible 团队、Ansible 社区或 Ansible 合作伙伴维护。ansible/ansible 仓库 现在仅包含基础特性和功能的代码,例如将模块代码复制到托管节点。这些代码也被称为 ansible-core(在 2.10 版本中曾短暂地被称为 ansible-base)。
要了解关于使用集合的更多信息,请参阅 使用 Ansible 集合。
要了解关于开发集合的更多信息,请参阅 开发集合。
要了解如何为现有集合做出贡献,请查阅各个集合仓库的指导方针,或者参阅 为 Ansible 维护的集合做出贡献 来为其中一个由 Ansible 维护的集合做出贡献。
这个特定模块去哪儿了?
如果您正在搜索某个特定模块,可以查看 runtime.yml 文件,该文件列出了我们从主 ansible/ansible 仓库中提取的每个模块的初始归属地。自那时起,有些模块可能再次发生了变动。您也可以在 Ansible Galaxy 上搜索,或在我们的聊天频道中询问。
在磁盘速度较慢的系统上,我该如何加速 Ansible?
在 Raspberry PI 等磁盘速度较慢的系统上,Ansible 可能会感到迟缓。有关如何改进这一点的提示,请参阅 如果 libyaml 不可用,Ansible 运行可能会变慢。
我该如何为任务或整个 Play 设置 PATH 或其他环境变量?
设置环境变量可以通过 environment 关键字完成。它可以在 Play 中的任务级别或其他级别使用。
shell:
cmd: date
environment:
LANG=fr_FR.UTF-8
hosts: servers
environment:
PATH: "{{ ansible_env.PATH }}:/thingy/bin"
SOME: value
注意
从 2.0.1 版本开始,gather_facts 的设置任务也会继承 Play 中的 environment 指令,如果在 Play 级别设置此项,您可能需要使用 |default 过滤器以避免错误。
对于需要不同用户账户或端口登录的机器,我该如何处理?
在清单文件中设置清单变量是最简单的方法。
例如,假设这些主机具有不同的用户名和端口
[webservers]
asdf.example.com ansible_port=5000 ansible_user=alice
jkl.example.com ansible_port=5001 ansible_user=bob
如果您愿意,还可以指定要使用的连接类型
[testcluster]
localhost ansible_connection=local
/path/to/chroot1 ansible_connection=chroot
foo.example.com ansible_connection=paramiko
您也可以选择将这些变量保留在组变量中,或者将它们存放在 group_vars/<groupname> 文件中。有关如何组织变量的更多信息,请参阅其余的文档。
如何让 Ansible 重用连接、启用 Kerberized SSH,或让 Ansible 识别我的本地 SSH 配置文件?
在配置文件中将默认连接类型切换为 ssh,或者使用 -c ssh,以便使用原生 OpenSSH 进行连接,而不是使用 python 的 paramiko 库。在 Ansible 1.2.1 及更高版本中,如果 OpenSSH 的版本足够新并支持 ControlPersist 选项,则默认会使用 ssh。
Paramiko 对于入门来说非常棒,但 OpenSSH 类型提供了许多高级选项。如果您使用此连接类型,建议从支持 ControlPersist 的较新版本机器上运行 Ansible。您仍然可以管理旧版客户端。如果您使用的是 RHEL 6、CentOS 6、SLES 10 或 SLES 11,其 OpenSSH 版本比较旧,所以即使您要管理旧节点,也请考虑从 Fedora 或 openSUSE 客户端运行管理操作,或者直接使用 paramiko。
我们将 paramiko 保持为默认设置,是因为如果您是在这些企业级操作系统上初次安装 Ansible,它能为新用户提供更好的体验。
如何配置跳转主机以访问我无法直接连接的服务器?
您可以在 ansible_ssh_common_args 清单变量中设置 ProxyCommand。当连接到相关主机时,此变量中指定的任何参数都会添加到 sftp/scp/ssh 命令行中。请考虑以下清单组
[gatewayed]
foo ansible_host=192.0.2.1
bar ansible_host=192.0.2.2
您可以创建 group_vars/gatewayed.yml,内容如下
ansible_ssh_common_args: '-o ProxyCommand="ssh -W %h:%p -q user@gateway.example.com"'
Ansible 在尝试连接到组 gatewayed 中的任何主机时,会将这些参数追加到命令行中。(这些参数会与 ansible.cfg 中的任何 ssh_args 结合使用,因此您无需在 ansible_ssh_common_args 中重复全局的 ControlPersist 设置。)
请注意,ssh -W 仅适用于 OpenSSH 5.4 或更高版本。在旧版本中,有必要在堡垒机上执行 nc %h:%p 或类似的命令。
在较早版本的 Ansible 中,必须在 ~/.ssh/config 中为一个或多个主机配置合适的 ProxyCommand,或者通过在 ansible.cfg 中设置 ssh_args 进行全局配置。
如何让 Ansible 及时发现目标机器已宕机?
您可以在 SSH 连接插件 中通过 ssh_args 参数添加 -o ServerAliveInterval=NumberOfSeconds。没有此选项,SSH(进而 Ansible)将等到 TCP 连接超时。另一个解决方案是将 ServerAliveInterval 添加到全局 SSH 配置中。如何设定 ServerAliveInterval 的值由您决定;请记住 ServerAliveCountMax=3 是 SSH 的默认值,因此您设置的任何值在终止 SSH 会话前都会被三倍计算。
如何加快 Ansible 在云提供商(如 EC2、OpenStack 等)服务器上的运行速度?
不要尝试从笔记本电脑上管理云提供商的机器集群。建议先连接到该云提供商内部的一个管理节点,并从那里运行 Ansible。
远程机器上没有 /usr/bin/python 解释器时,我该怎么办?
虽然您可以用任何语言编写 Ansible 模块,但大多数 Ansible 模块(包括那些让 Ansible 正常运行的核心模块)都是用 Python 编写的。
默认情况下,Ansible 假设它可以在您的远程系统上找到 /usr/bin/python,该路径应指向 Python 2.6 或更高版本(Python 2)或 Python 3.5 或更高版本(Python 3)。
在任何主机上设置清单变量 ansible_python_interpreter,会告诉 Ansible 使用该值自动替换 Python 解释器。因此,如果系统上的 /usr/bin/python 未指向兼容的解释器,您可以将其指向系统中的任意 Python。
某些平台可能默认仅安装了 Python 3。如果它未安装为 /usr/bin/python,您需要通过 ansible_python_interpreter 配置解释器的路径。虽然大多数核心模块可以在 Python 3 下正常工作,但可能存在一些特殊用途的模块无法运行,或者您可能会在某些边界情况下遇到 Bug。作为临时解决方法,您可以在受管主机上安装 Python 2,并通过 ansible_python_interpreter 配置 Ansible 使用该 Python。如果模块文档中没有提到该模块需要 Python 2,您也可以在我们的问题跟踪器上报告 Bug,以便在未来版本中修复此不兼容问题。
不要替换 Python 模块的 shebang 行。Ansible 会在部署时自动为您处理。
此外,这适用于任何解释器,例如 ruby: ansible_ruby_interpreter,perl: ansible_perl_interpreter 等,因此您可以将其用于用任何脚本语言编写的自定义模块,并控制解释器的位置。
请记住,如果您在模块的 shebang 行中放入 env (#!/usr/bin/env <other>),这将无法工作,并会被作为一个字符串解析(包括 env 和 <other> 之间的空格)。不支持也不建议使用参数。
安装 Ansible 时,如何处理 Ansible 包依赖项所需的软件包依赖问题?
安装 Ansible 时,有时您可能会遇到诸如 No package ‘libffi’ found 或 fatal error: Python.h: No such file or directory 等错误。这些错误通常是由缺失的软件包导致的,而这些包是 Ansible 所需包的依赖项。例如,libffi 包是 pynacl 和 paramiko 的依赖项(Ansible -> paramiko -> pynacl -> libffi)。
为了解决这类依赖问题,您可能需要使用操作系统原生的包管理器(如 yum、dnf 或 apt)安装所需的软件包,或者按照包安装指南中的说明进行操作。
有关此类依赖项及其安装方法,请参阅相应软件包的文档。
常见的系统问题
在 virtualenv 中运行
您可以非常简单地将 Ansible 安装到控制节点的 virtualenv 中
$ virtualenv ansible
$ source ./ansible/bin/activate
$ pip install ansible
如果您想在 Python 3 而非 Python 2 下运行,您可能需要稍微修改一下
$ virtualenv -p python3 ansible
$ source ./ansible/bin/activate
$ pip install ansible
如果您需要使用 pip 无法提供的任何库(例如,在启用了 SELinux 的 Red Hat Enterprise Linux 或 Fedora 等系统上的 SELinux Python 绑定),则需要将它们安装到 virtualenv 中。有两种方法
创建 virtualenv 时,指定
--system-site-packages以利用系统 Python 中安装的任何库$ virtualenv ansible --system-site-packages
从系统中手动复制这些文件。例如,对于 SELinux 绑定,您可以这样做
$ virtualenv ansible --system-site-packages $ cp -r -v /usr/lib64/python3.*/site-packages/selinux/ ./py3-ansible/lib64/python3.*/site-packages/ $ cp -v /usr/lib64/python3.*/site-packages/*selinux*.so ./py3-ansible/lib64/python3.*/site-packages/
在 macOS 上作为控制节点运行
在 macOS 作为控制节点的系统上执行 Ansible 时,可能会遇到以下错误
错误
+[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug. ERROR! A worker was found in a dead state
通常,建议的解决方法是在 shell 中设置以下环境变量
$ export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
在 macOS 上作为目标节点运行
当通过 SSH 管理 macOS Monterey 12、macOS Ventura 13 或更高版本的系统时,可能会发生以下错误
错误
“eDSPermissionError” DS Error: -14120 (eDSPermissionError)
这表明 允许远程用户完全磁盘访问 没有被启用。
另请参阅
有关更多详细信息,请查看 Apple 官方用户指南文章。
在 BSD 上运行
另请参阅
在 Solaris 上运行
默认情况下,Solaris 10 及更早版本运行的是非 POSIX shell,无法正确展开 Ansible 使用的默认 tmp 目录 ( ~/.ansible/tmp)。如果您在 Solaris 机器上看到模块失败,这很可能是问题所在。有几种解决方法
您可以将
remote_tmp设置为在使用该 shell 时可以正确展开的路径(请参阅 C shell、fish shell 和 Powershell 的插件文档)。例如,在 ansible 配置文件中,您可以设置remote_tmp=$HOME/.ansible/tmp
在 Ansible 2.5 及更高版本中,您还可以像这样在清单中按主机设置它
solaris1 ansible_remote_tmp=$HOME/.ansible/tmp
您可以将 ansible_shell_executable 设置为 POSIX 兼容 shell 的路径。例如,许多 Solaris 主机在
/usr/xpg4/bin/sh处有 POSIX shell,因此您可以这样在清单中进行设置solaris1 ansible_shell_executable=/usr/xpg4/bin/sh
(如果您安装了 bash、ksh 和 zsh,它们也应该是 POSIX 兼容的)。
在 z/OS 上运行
总的来说,z/OS 不能用作 Ansible 控制节点。有关更多详细信息,请参阅 将 z/OS 用作控制节点。
当在目标主机上默认位置找不到 Python 解释器的路径时,可能会导致以下错误
错误
/usr/bin/python: FSUM7351 not found
Ansible 需要一个 Python 解释器在远程主机上执行模块,并会检查“默认”路径
/usr/bin/python。在 z/OS 上,Python 3 解释器(来自 IBM Open Enterprise SDK for Python)通常安装在不同的路径,通常类似于:
/usr/lpp/cyp/v3r12/pyz。Python 解释器的路径可以通过 Ansible 清单变量
ansible_python_interpreter进行配置。例如zos1 ansible_python_interpreter:/usr/lpp/cyp/v3r12/pyz
有关更多详细信息,请参阅:远程机器上没有 /usr/bin/python 解释器时,我该怎么办?。
当未启用 ANSIBLE_PIPELINING 时,或者启用了 Ansible Pipelining 但未正确设置
PYTHONSTDINENCODING属性时,可能会导致以下错误。错误
SyntaxError: Non-UTF-8 code starting with ‘\x81’ in file <stdin> on line 1, but no encoding declared; see https://peps.pythonlang.cn/pep-0263/ for details
请注意,下方的十六进制
'\x81'可能会根据导致错误的来源而有所不同启用 Ansible Pipelining 后,Ansible 会通过 Python 的 stdin 管道将所有模块代码传递到远程目标,并在一次调用中运行所有代码。有关 Pipelining 的更多详细信息,请参阅:Pipelining。
对于在 z/OS 受管节点上执行的任何任务,请在环境中包含以下内容。
PYTHONSTDINENCODING: "cp1047"
某些语言环境 (LE) 配置启用了 z/OS 系统上的 Python 所需的自动转换和自动文件标记功能(IBM Open Enterprise SDK for Python)。
为任何 z/OS 受管节点设置远程环境时,请包含以下配置
_BPXK_AUTOCVT: "ON" _CEE_RUNOPTS: "FILETAG(AUTOCVT,AUTOTAG) POSIX(ON)" _TAG_REDIR_ERR: "txt" _TAG_REDIR_IN: "txt" _TAG_REDIR_OUT: "txt"
Ansible 可以通过这些选项配置远程环境变量
inventory - inventory.yml, group_vars/all.yml, 或 host_vars/all.yml
playbook - Playbook 顶部的
environment变量。block 或 task -
environment关键字。
有关更多详细信息,请参阅 设置远程环境。
在 fakeroot 下运行
由于 fakeroot 默认不会创建完整或符合 POSIX 标准的系统,因此会出现一些问题。众所周知,它无法正确展开 Ansible 使用的默认 tmp 目录 (~/.ansible/tmp)。如果您看到模块失败,这很可能是问题所在。简单的解决方法是将 remote_tmp 设置为可以正确展开的路径(有关详细信息,请参阅您正在使用的 shell 插件的文档)。
例如,在 ansible 配置文件中(或通过环境变量),您可以设置
remote_tmp=$HOME/.ansible/tmp
实现内容可重用/可再分发的最佳方式是什么?
如果您还没有这样做,请阅读 Playbook 文档中关于“Roles”的所有内容。这有助于您使 Playbook 内容自包含,并能很好地与 Git 子模块等内容共享工具配合使用。
如果其中一些插件类型对您来说很陌生,请参阅 API 文档以获取有关扩展 Ansible 方法的更多详细信息。
配置文件在哪里,我可以在里面配置什么?
请参阅 配置 Ansible。
如何禁用 cowsay?
如果安装了 cowsay,Ansible 会在运行 Playbook 时自作主张让您的一天更快乐。如果您决定在一个专业的“无牛”环境中工作,您可以卸载 cowsay,在 ansible.cfg 中设置 nocows=1,或者设置 ANSIBLE_NOCOWS 环境变量
export ANSIBLE_NOCOWS=1
如何查看所有 ansible_ 变量的列表?
Ansible 默认收集关于受管机器的“事实”(facts),这些事实可以在 Playbook 和模板中访问。要查看关于某台机器的所有可用事实列表,您可以将 setup 模块作为 ad hoc 操作运行
ansible -m setup hostname
这将打印出该特定主机所有可用事实的字典。您可能需要将输出通过管道传送到分页器中。这不包括清单变量或内部的“魔法”变量。如果您需要的不仅仅是“事实”,请参阅下一个问题。
如何查看为我的主机定义的所有清单(inventory)变量?
通过运行以下命令,您可以查看主机的清单变量
ansible-inventory --list --yaml
如何查看特定于我的主机的变量?
要查看所有特定于主机的变量(可能包括事实和其他来源)
ansible -m debug -a "var=hostvars['hostname']" localhost
除非您使用事实缓存,否则通常需要先运行一个收集事实的 Play,才能在上述任务中包含事实。
如何在模板中遍历组内的主机列表?
一种非常常见的模式是遍历主机组中的主机列表,例如用服务器列表填充模板配置文件。要做到这一点,您只需在模板中访问 “$groups” 字典,如下所示
{% for host in groups['db_servers'] %}
{{ host }}
{% endfor %}
如果您需要访问关于这些主机的事实(例如每个主机名的 IP 地址),则需要确保事实已被填充。例如,确保您有一个与 db_servers 通信的 Play
- hosts: db_servers
tasks:
- debug: msg="doesn't matter what you do, just that they were talked to previously."
然后,您就可以在模板中使用这些事实,如下所示
{% for host in groups['db_servers'] %}
{{ hostvars[host]['ansible_eth0']['ipv4']['address'] }}
{% endfor %}
如何以编程方式访问变量名?
可能会出现这种情况:我们需要获取任意接口的 ipv4 地址,而要使用的接口可以通过角色参数或其他输入提供。变量名可以通过使用 “~” 将字符串连接起来构建,如下所示
{{ hostvars[inventory_hostname]['ansible_' ~ which_interface]['ipv4']['address'] }}
通过 hostvars 访问的技巧是必要的,因为它是一个包含完整变量命名空间的字典。inventory_hostname 是一个魔法变量,它表示您当前在主机循环中遍历的主机。
在上面的例子中,如果您的接口名称中有连字符,则必须用下划线替换它们
{{ hostvars[inventory_hostname]['ansible_' ~ which_interface | replace('_', '-') ]['ipv4']['address'] }}
另请参阅 dynamic_variables。
如何访问组变量?
严格来说,您不能这样做,Ansible 实际上并不直接使用组。组是用于主机选择和批量分配变量的标签,它们不是一级实体,Ansible 只关心主机和任务。
话虽如此,您可以通过选择该组的一部分主机来访问该变量,有关示例,请参阅下面的 first_host_in_a_group。
如何访问组内第一台主机的变量?
如果我们想要 webservers 组中第一台 Web 服务器的 IP 地址会怎样?嗯,我们也可以这样做。请注意,如果我们使用动态清单,哪台主机是“第一台”可能不一致,因此除非您的清单是静态且可预测的,否则您不会想这样做。(如果您使用的是 AWX 或 Red Hat Ansible Automation Platform,它将使用数据库顺序,所以即使您使用基于云的清单脚本,这也不是问题)。
总之,诀窍如下
{{ hostvars[groups['webservers'][0]]['ansible_eth0']['ipv4']['address'] }}
注意我们是如何提取 webservers 组第一台机器的主机名的。如果您在模板中执行此操作,可以使用 Jinja2 的 ‘#set’ 指令来简化;或者在 Playbook 中,您也可以使用 set_fact
- set_fact: headnode={{ groups['webservers'][0] }}
- debug: msg={{ hostvars[headnode].ansible_eth0.ipv4.address }}
注意我们是如何在括号语法和点号语法之间转换的——这可以在任何地方完成。
如何将文件递归复制到目标主机?
copy 模块有一个递归参数。但是,如果您想为大量文件执行更高效的操作,请查看 synchronize 模块。synchronize 模块封装了 rsync。有关这两个模块的信息,请参阅模块索引。
如何访问 Shell 环境变量?
在控制节点机器上:要访问控制节点上的现有变量,请使用 env 查找插件。例如,要访问管理机器上 HOME 环境变量的值
---
# ...
vars:
local_home: "{{ lookup('env','HOME') }}"
在目标机器上:环境变量可以通过 ansible_env 变量中的事实获取
{{ ansible_env.HOME }}
如果您需要为任务执行设置环境变量,请参阅 高级 Playbooks 部分中的 设置远程环境。在目标机器上设置环境变量有多种方法。您可以使用 template、replace 或 lineinfile 模块将环境变量引入文件中。具体要编辑的文件取决于您的操作系统、发行版和本地配置。
如何为 user 模块生成加密密码?
Ansible ad hoc 命令是最简单的选择
ansible all -i localhost, -m debug -a "msg={{ 'mypassword' | password_hash('sha512', 'mysecretsalt') }}"
大多数 Linux 系统上可用的 mkpasswd 实用程序也是一个很好的选择
mkpasswd --method=sha-512
openssl 实用程序是另一个很好的选择
openssl passwd -6 -noverify
这将生成一个带有 SHA512 哈希值的密码,不含 salt 值,默认轮数为 5000。查看 openssl passwd 文档 以获取更多选项。
使用集成的 哈希和加密字符串与密码 来生成密码的哈希版本。您不应在 Playbook 或 host_vars 中放入明文密码;相反,请使用 使用加密的变量和文件 来加密敏感数据。
在 OpenBSD 中,基础系统中有一个类似的选项,称为 encrypt (1)
Ansible 允许对变量使用点记法和数组记法。我应该使用哪种记法?
点记法源自 Jinja,对于不含特殊字符的变量效果很好。如果您的变量包含点 (.)、冒号 (:) 或连字符 (-),或者如果键以两个下划线开头和结尾,或者如果键使用了任何已知的公共属性,则使用数组记法更安全。有关已知公共属性的列表,请参阅 使用变量。
item[0]['checksum:md5']
item['section']['2.1']
item['region']['Mid-Atlantic']
It is {{ temperature['Celsius']['-3'] }} outside.
此外,数组记法允许动态变量组合,请参阅 dynamic_variables。
“点记法”的另一个问题是某些键会导致问题,因为它们与 Python 字典的属性和方法冲突。
当
item是字典时,不正确语法的示例
item.update
该变体导致语法错误,因为 update() 是 Python 字典的方法。
正确语法的示例
item['update']
什么时候从变量批量设置任务参数是不安全的?
您可以从字典类型的变量中设置任务的所有参数。此技术在某些动态执行场景中很有用。但是,它引入了安全风险。我们不建议这样做,因此当您执行此类操作时,Ansible 会发出警告
#...
vars:
usermod_args:
name: testuser
state: present
update_password: always
tasks:
- user: '{{ usermod_args }}'
此特定示例是安全的。但是,构建这样的任务是有风险的,因为传递给 usermod_args 的参数和值可能会被受攻击目标机器上的 host facts 中的恶意值覆盖。为了降低此风险
以高于
host facts的优先级级别设置批量变量,详见 变量优先级:我应该把变量放在哪里?(上面的示例是安全的,因为 Play 变量的优先级高于事实)禁用 INJECT_FACTS_AS_VARS 配置设置,以防止事实值与变量冲突(这也会禁用原始警告)
我可以获得 Ansible 的培训吗?
是的!有关我们的服务和培训产品的信息,请参阅我们的 服务页面。更多详情请发送电子邮件至 info@ansible.com。
我们还定期提供免费的基于 Web 的培训课程。有关即将举行的网络研讨会的更多信息,请参阅我们的 网络研讨会页面。
有 Web 界面 / REST API / GUI 吗?
是的!开源 Web 界面是 Ansible AWX。使 Ansible 更强大且更易于使用的受支持 Red Hat 产品是 Red Hat Ansible Automation Platform。
如何保护 Playbook 中的敏感数据?
如果您想在 Ansible 内容中保留敏感数据,同时仍将其公开共享或保留在版本控制中,请参阅 使用加密的变量和文件。
如果您有一个任务在运行时不想显示结果或使用的命令(在使用 -v 详细模式时),以下任务或 Playbook 属性可能很有用
- name: secret task
shell: /usr/bin/do_something --value={{ secret_value }}
no_log: True
这可用于保持详细输出,但向他人隐藏敏感信息,而其他人本可以查看到该输出。
no_log 属性也可以应用于整个 Play
- hosts: all
no_log: True
尽管这会使 Play 在调试时有些困难。建议仅在 Playbook 完成后将其应用于单个任务。请注意,使用 no_log 属性并不能阻止数据在通过 ANSIBLE_DEBUG 环境变量调试 Ansible 本身时被显示。
什么时候应该使用 {{ }}?此外,如何插值变量或使用动态变量名
一条铁律是“永远使用 {{ }},但 when: 除外”。条件总是通过 Jinja2 运行以解析表达式,所以 when:、failed_when: 和 changed_when: 总是会被模版化,您应该避免添加 {{ }}。
在大多数其他情况下,即使以前可以在不指定的情况下使用变量(如 loop 或 with_ 子句),您也应该始终使用括号,因为这很难区分未定义的变量和字符串。
另一条规则是“胡子(moustaches)不能堆叠”。我们经常看到这种情况
{{ somevar_{{other_var}} }}
上面的写法并不能按预期工作,如果需要使用动态变量,请根据需要使用以下方法
{{ hostvars[inventory_hostname]['somevar_' ~ other_var] }}
对于“非主机变量”,您可以使用 vars 查找 插件
{{ lookup('vars', 'somevar_' ~ other_var) }}
要确定关键字是否需要 {{ }} 或是否支持模板化,请使用 ansible-doc -t keyword <name>,这将返回关于关键字的文档,包括一个带有以下值的 template 字段:explicit(需要 {{ }})、implicit(假设 {{ }},因此不需要显式添加)或 static(不支持模板化,所有字符将被字面解释)
当代理任务时,如何获取原始的 ansible_host?
如文档所述,连接变量取自 delegate_to 主机,因此 ansible_host 被覆盖,但您仍然可以通过 hostvars 访问原始变量
original_host: "{{ hostvars[inventory_hostname]['ansible_host'] }}"
这适用于所有被覆盖的连接变量,例如 ansible_user、ansible_port 等。
获取文件时出现“protocol error: file name does not match request”错误,该如何修复?
自 OpenSSH 的 7.9p1 版本以来,SCP 客户端中存在一个 Bug,当使用 SCP 作为文件传输机制时,它会在 Ansible 控制节点上触发此错误
错误
failed to transfer file to /tmp/ansible/file.txtrnprotocol error: file name does not match request
在这些版本中,SCP 尝试验证要获取文件的路径是否与请求的路径匹配。如果远程文件名需要引号来转义其路径中的空格或非 ASCII 字符,验证就会失败。要避免此错误
- 确保您正在使用 SFTP,它是安全性、速度和可靠性方面的最佳传输方法。检查您是否正在执行以下操作之一
依赖默认设置(即
smart)——如果ssh_transfer_method未在任何地方被显式设置,则此设置有效在控制节点上设置环境变量:
export ANSIBLE_SSH_TRANSFER_METHOD=smart运行 Ansible 时传递环境变量:
ANSIBLE_SSH_TRANSFER_METHOD=smart ansible-playbook修改
ansible.cfg文件:将ssh_transfer_method=smart添加到[ssh_connection]部分。smart设置会尝试使用sftp进行传输,然后回退到scp,最后是dd。如果您希望在 SFTP 不可用时传输失败,请将ssh_transfer_method=sftp添加到[ssh_connection]部分。
注意
如果您在使用 -T 时看到 invalid argument 错误,那么您的 SCP 客户端不会执行文件名验证,也不会触发此错误。
Ansible 是否支持多因素身份验证 (2FA/MFA/生物识别/指纹/USB Key/OTP/…)
否,Ansible 旨在针对多个目标执行多个任务,最大限度地减少用户交互。与大多数自动化工具一样,它与旨在处理人类交互的交互式安全系统不兼容。这些系统大多数需要每个目标进行二次提示,这阻止了扩展到数千个目标。它们往往还有非常短的过期时间,因此需要频繁重新授权,这在管理多主机和/或长任务集时也是个问题。
在此类环境中,我们建议在 Ansible 执行层周围采取安全措施,但仍允许其使用不需要此类措施的“自动化用户”。借助 AWX 或 Red Hat Ansible Automation Platform,管理员可以设置对清单的 RBAC 访问权限,并管理凭据和作业执行。
“validate”选项不能满足我的需求,我该怎么办?
许多创建或更新文件的 Ansible 模块都有一个 validate 选项,允许您在验证命令失败时中止更新。这使用了 Ansible 在进行最终更新之前创建的临时文件。在许多情况下,这不起作用,因为特定应用程序的验证工具需要特定的名称、多个文件或此简单功能中不存在的其他因素。
对于这些情况,您必须自行处理验证和恢复。以下是如何使用 block/rescue 和备份来执行此操作的简单示例,大多数基于文件的模块也都支持这一点
- name: maintain config and backout if validation after change fails
block:
- name: do the actual update, works with copy, lineinfile and any action that allows for `backup`.
template: src=template.j2 dest=/x/y/z backup=yes moreoptions=stuff
register: updated
- name: run validation, this will change a lot as needed. We assume it returns an error when not passing, use `failed_when` if otherwise.
shell: run_validation_commmand
become: true
become_user: requiredbyapp
environment:
WEIRD_REQUIREMENT: 1
when: updated is changed
rescue:
- name: restore backup file to original, in the hope the previous configuration was working.
copy:
remote_src: true
dest: /x/y/z
src: "{{ updated['backup_file'] }}"
when: updated is changed
always:
- name: We choose to always delete backup, but could copy or move, or only delete in rescue.
file:
path: "{{ updated['backup_file'] }}"
state: absent
when: updated is changed
如何提交文档的修改建议?
Ansible 的文档保存在 ansible/ansible-documentation 项目 Git 仓库中。有关详细信息,请参阅 为 Ansible 文档做出贡献。
ansible.legacy 和 ansible.builtin 集合有什么区别?
两者都不是真正的集合。它们是由核心引擎虚拟构建的(合成集合)。
ansible.builtin 集合仅指随 ansible-core 一起分发的插件。
ansible.legacy 集合是 ansible.builtin 的超集(您可以通过 ansible.legacy 引用 builtin 中的插件)。您还可以选择在 配置的路径和相邻目录 中添加“自定义”插件,并能够覆盖同名的内置插件。
此外,ansible.legacy 是您在不指定 FQCN 时默认获得的内容。所以这
- shell: echo hi
实际上等同于
- ansible.legacy.shell: echo hi
虽然,如果您没有覆盖 shell 模块,您也可以直接将其写为 ansible.builtin.shell,因为 legacy 会解析为内置集合。
我没有看到我的问题
如果您还没有找到问题的答案,请询问社区!有关详细信息,请访问 Ansible 通信指南。
另请参阅
- 使用 Playbook
Playbook 简介
- Ansible 提示与技巧
Playbook 的提示与技巧
- 交流方式
有疑问?需要帮助?想分享你的想法?请访问 Ansible 通信指南