常见问题解答
以下是一些常见问题的答案。
所有模块都去哪里了?
2019 年 7 月,我们宣布集合将是 Ansible 内容交付的未来。集合是 Ansible 内容的分布格式,可以包含剧本、角色、模块和插件。在 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 速度?
Ansible 在具有慢速磁盘的系统(如 Raspberry PI)上可能感觉很迟钝。请参阅 如果 libyaml 不可用,Ansible 可能会运行缓慢,以获取有关如何改进此问题的提示。
如何为任务或整个剧本设置 PATH 或任何其他环境变量?
可以使用 environment 关键字设置环境变量。它可以在任务或剧本中的其他级别使用。
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
中的 setup 任务也会从剧本继承 environment 指令,您可能需要使用 |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"'
尝试连接到组 gatewayed
中的任何主机时,Ansible 将将这些参数附加到命令行。(这些参数将与来自 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 连接超时。另一个解决方案是在全局 SSH 配置中添加 ServerAliveInterval
。您需要自行决定 ServerAliveInterval
的合适值,请记住,ServerAliveCountMax=3
是 SSH 的默认值,因此您设置的任何值在终止 SSH 会话之前都会乘以 3。
如何加快针对云提供商(EC2、OpenStack 等)服务器运行 Ansible 的速度?
不要尝试从笔记本电脑管理云提供商的一组机器。相反,先连接到此云提供商内部的管理节点,然后从那里运行 Ansible。
如何处理远程机器上没有在 /usr/bin/python 上安装 Python 解释器的情况?
虽然您可以使用任何语言编写 Ansible 模块,但大多数 Ansible 模块都是用 Python 编写的,包括让 Ansible 正常工作的核心模块。
默认情况下,Ansible 假设它可以在远程系统上找到一个 /usr/bin/python,该 Python 解释器是 Python2 版本 2.6 或更高版本,或者 Python3 版本 3.5 或更高版本。
在任何主机上设置 inventory 变量 ansible_python_interpreter
将告诉 Ansible 自动用该值替换 Python 解释器。因此,如果系统上的 /usr/bin/python 指向的不是兼容的 Python 解释器,则可以将它指向系统上任何您想要的 Python。
某些平台可能默认只安装了 Python 3。如果它没有安装在 /usr/bin/python 上,则需要通过 ansible_python_interpreter
配置解释器的路径。虽然大多数核心模块可以使用 Python 3,但可能有一些特殊用途的模块不能使用,或者您可能会在边缘情况下遇到 bug。作为临时解决方案,您可以在托管主机上安装 Python 2,并通过 ansible_python_interpreter
配置 Ansible 使用该 Python。如果模块文档中没有提到该模块需要 Python 2,您也可以在我们的 bug 跟踪器 上报告一个 bug,以便在将来的版本中修复这种不兼容性。
不要替换 Python 模块的 shebang 行。Ansible 会在部署时自动为您执行此操作。
此外,这适用于任何解释器,例如 ruby:ansible_ruby_interpreter
,perl:ansible_perl_interpreter
,等等,因此您可以将它用于用任何脚本语言编写的自定义模块,并控制解释器的位置。
请记住,如果您在模块的 shebang 行中放入 env
(#!/usr/bin/env <other>
),此功能将被忽略,因此您将受制于远程 $PATH。
如何处理 Ansible 安装期间 Ansible 包依赖项所需的包依赖项?
在安装 Ansible 时,有时您可能会遇到类似 没有找到包 'libffi' 或 致命错误:Python.h:没有此文件或目录 的错误。这些错误通常是由缺少的包引起的,这些包是 Ansible 所需包的依赖项。例如,libffi 包是 pynacl 和 paramiko 的依赖项 (Ansible -> paramiko -> pynacl -> libffi)。
为了解决这些类型的依赖项问题,您可能需要使用操作系统本机包管理器(例如 yum、dnf 或 apt)安装所需的包,或者按照包安装指南中的说明进行操作。
请参阅相应包的文档,了解此类依赖项及其安装方法。
常见平台问题
Red Hat 支持哪些客户平台?
很多!有关完整列表,请参阅此 知识库文章。
在 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] 可能是另一个线程在调用 fork() 时正在进行中。我们不能安全地调用它或在 fork() 子进程中忽略它。改为崩溃。在 objc_initializeAfterForkError 上设置断点以调试。ERROR!在死状态下找到一个工作进程
通常,推荐的解决方法是在 shell 中设置以下环境变量
$ export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
在 macOS 上作为目标运行
当通过 SSH 管理 macOS Monterey 12、macOS Ventura 13 或更高版本的操作系统时,可能会发生以下错误
错误
“eDSPermissionError” DS 错误:-14120 (eDSPermissionError)
这表明 允许远程用户完全访问磁盘 尚未启用。
另请参阅
有关更多详细信息,请查看 Apple 官方用户指南文章。
在 BSD 上运行
另请参阅
在 Solaris 上运行
默认情况下,Solaris 10 及更早版本运行非 POSIX shell,该 shell 无法正确扩展 Ansible 使用的默认临时目录 (~/.ansible/tmp
)。如果您在 Solaris 机器上看到模块错误,这很可能是问题所在。有一些解决方法
您可以将
remote_tmp
设置为一个可以使用您正在使用的 shell 正确扩展的路径(请参阅 C shell、fish shell 和 Powershell 的插件文档)。例如,在 ansible 配置文件中,您可以设置remote_tmp=$HOME/.ansible/tmp
在 Ansible 2.5 及更高版本中,您也可以在 inventory 中按主机设置它,如下所示
solaris1 ansible_remote_tmp=$HOME/.ansible/tmp
您可以将 ansible_shell_executable 设置为 POSIX 兼容 shell 的路径。例如,许多 Solaris 主机在
/usr/xpg4/bin/sh
上安装了 POSIX shell,因此您可以在 inventory 中进行如下设置solaris1 ansible_shell_executable=/usr/xpg4/bin/sh
(如果您安装了 bash、ksh 和 zsh,它们也应该与 POSIX 兼容)。
在 z/OS 上运行
在尝试在 z/OS 上作为目标执行 Ansible 时,可能会遇到一些常见错误。
z/OS 上的 Python 版本 2.7.6 无法与 Ansible 一起使用,因为它在内部将字符串表示为 EBCDIC。
为了解决此限制,请下载并安装 z/OS 上的 Python 的更高版本 (2.7.13 或 3.6.1),该版本在内部将字符串表示为 ASCII。已验证版本 2.7.13 可以正常工作。
当
pipelining = False
在 /etc/ansible/ansible.cfg 中时,Ansible 模块将通过 sftp 以二进制模式传输,但 Python 执行会失败,并出现以下错误错误
SyntaxError:文件 /a/user1/.ansible/tmp/ansible-tmp-1548232945.35-274513842609025/AnsiballZ_stat.py 第 1 行的非 UTF-8 代码以 '\x83' 开头,但没有声明编码;有关详细信息,请参阅 https://pythonlang.cn/dev/peps/pep-0263/
要解决此问题,请在 /etc/ansible/ansible.cfg 中将
pipelining = True
设置为。Python 解释器在目标主机上的默认位置
/usr/bin/python
中找不到。错误
/usr/bin/python:EDC5129I 没有此文件或目录
要解决此问题,请在 inventory 中将路径设置为 Python 安装路径,如下所示
zos1 ansible_python_interpreter=/usr/lpp/python/python-2017-04-12-py27/python27/bin/python
Python 启动失败,并出现错误
The module libpython2.7.so was not found.
错误
EE3501S 未找到模块 libpython2.7.so。
在 z/OS 上,必须从 gnu bash 执行 Python。如果 gnu bash 安装在
/usr/lpp/bash
上,则可以通过在 inventory 中指定ansible_shell_executable
来解决此问题zos1 ansible_shell_executable=/usr/lpp/bash/bin/bash
在 fakeroot 下运行
由于fakeroot
默认情况下不会创建完整的 POSIX 兼容系统,因此会产生一些问题。众所周知,它无法正确扩展 Ansible 使用的默认 tmp 目录 (~/.ansible/tmp
)。如果您遇到模块故障,这很可能是问题所在。简单的解决方法是将remote_tmp
设置为一个可以正确扩展的路径(有关详细信息,请参阅您使用的 shell 插件的文档)。
例如,在 ansible 配置文件(或通过环境变量)中,您可以设置
remote_tmp=$HOME/.ansible/tmp
如何最好地使内容可重用/可重新分发?
如果您还没有这样做,请阅读有关剧本文档中“角色”的所有信息。这有助于您使剧本内容独立,并且非常适合使用 git 子模块与他人共享内容。
如果其中一些插件类型看起来很奇怪,请参阅 API 文档以获取有关 Ansible 可扩展方式的更多详细信息。
配置文件在哪里,以及我在其中可以配置什么?
请参阅 配置 Ansible.
如何禁用 cowsay?
如果安装了 cowsay,Ansible 会自动在运行剧本时让您的一天更快乐。如果您决定在没有奶牛的专业环境中工作,您可以卸载 cowsay,在 ansible.cfg
中设置 nocows=1
,或者设置 ANSIBLE_NOCOWS
环境变量。
export ANSIBLE_NOCOWS=1
如何查看所有 ansible_ 变量的列表?
Ansible 默认情况下会收集受管机器的“事实”,这些事实可以在剧本和模板中访问。要查看有关机器的所有可用事实的列表,可以将setup
模块作为临时操作运行
ansible -m setup hostname
这将打印出该特定主机的所有可用事实的字典。您可能需要将输出管道到分页器。这并不包括清单变量或内部“魔法”变量。如果您需要更多信息,而不仅仅是“事实”,请参阅下一个问题。
如何查看为我的主机定义的所有清单变量?
通过运行以下命令,您可以查看主机的清单变量
ansible-inventory --list --yaml
如何查看我的主机特有的所有变量?
要查看所有主机特定的变量,这些变量可能包括事实和其他来源
ansible -m debug -a "var=hostvars['hostname']" localhost
除非您使用事实缓存,否则通常需要先使用收集事实的剧本,才能将事实包含在上面的任务中。
如何在模板中循环遍历组中的主机列表?
一个很常见的模式是迭代主机组内的主机列表,也许是为了用服务器列表填充模板配置文件。为此,您只需在模板中访问“$groups”字典,如下所示
{% for host in groups['db_servers'] %}
{{ host }}
{% endfor %}
如果您需要访问这些主机的“事实”,例如每个主机名的 IP 地址,则需要确保已填充这些事实。例如,确保您有一个与 db_servers 交谈的剧本
- 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 组中第一个 webserver 的 ip 地址,会发生什么?嗯,我们也可以做到这一点。请注意,如果我们使用动态清单,哪个主机是“第一个”可能不一致,因此除非您的清单是静态且可预测的,否则您不希望这样做。(如果您使用的是 AWX 或 Red Hat Ansible Automation Platform,它将使用数据库顺序,因此即使您使用的是基于云的清单脚本,这也不是问题)。
无论如何,这是诀窍
{{ hostvars[groups['webservers'][0]]['ansible_eth0']['ipv4']['address'] }}
请注意我们是如何提取 webservers 组中第一台机器的主机名的。如果您在模板中这样做,您可以使用 Jinja2 的“#set”指令来简化此操作,或者在剧本中,您也可以使用 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 }}
如果您需要设置环境变量以执行 TASK,请参阅 设置远程环境(位于 高级剧本 部分)。有几种方法可以在目标机器上设置环境变量。您可以使用 template、replace 或 lineinfile 模块将环境变量引入文件。要编辑的确切文件取决于您的操作系统、发行版和本地配置。
如何为 user 模块生成加密密码?
Ansible 临时命令是最简单的选择
ansible all -i localhost, -m debug -a "msg={{ 'mypassword' | password_hash('sha512', 'mysecretsalt') }}"
大多数 Linux 系统上提供的 mkpasswd
实用程序也是一个不错的选择
mkpasswd --method=sha-512
如果您的系统上没有安装此实用程序(例如,您使用的是 macOS),那么您仍然可以使用 Python 轻松生成这些密码。首先,确保已安装 Passlib 密码哈希库
pip install passlib
库准备就绪后,可以使用以下方式生成 SHA512 密码值
python -c "from passlib.hash import sha512_crypt; import getpass; print(sha512_crypt.using(rounds=5000).hash(getpass.getpass()))"
使用集成的 哈希和加密字符串和密码 来生成密码的哈希版本。您不应该在剧本或 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
的优先级之上设置批量变量,优先级顺序请参考 变量优先级:应该在哪里放置变量? (上面的例子是安全的,因为剧本变量优先于事实)禁用 INJECT_FACTS_AS_VARS 配置设置,以防止事实值与变量冲突(这也会禁用原始警告)
我可以获得 Ansible 的培训吗?
是的!请查看我们的 服务页面 ,了解我们的服务和培训产品。请发送电子邮件至 info@ansible.com 获取更多详细信息。
我们还定期提供免费的在线培训课程。请查看我们的 网络研讨会页面 ,了解即将举行的网络研讨会。
是否有 Web 界面 / REST API / GUI?
是的!开源 Web 界面是 Ansible AWX。支持 Red Hat 产品,使 Ansible 更加强大且易于使用,即 Red Hat Ansible Automation Platform.
如何在剧本中保留秘密数据?
如果您想在 Ansible 内容中保留秘密数据,并同时公开共享或将其保留在源代码控制中,请参阅 使用加密变量和文件.
如果您有一个任务,您不想在使用 -v(详细)模式时显示其结果或命令,则以下任务或剧本属性可能很有用
- name: secret task
shell: /usr/bin/do_something --value={{ secret_value }}
no_log: True
这可用于保留详细输出,但隐藏敏感信息,以免其他人能够看到输出。
no_log
属性也可以应用于整个剧本
- hosts: all
no_log: True
但这会使剧本难以调试。建议仅将其应用于单个任务,一次完成剧本。请注意,使用 no_log
属性不会阻止数据在通过 ANSIBLE_DEBUG
环境变量调试 Ansible 本身时显示。
何时应该使用 {{ }}?另外,如何插值变量或动态变量名称?
一个坚定不移的规则是“始终使用 {{ }}
,除非是 when:
”。条件始终通过 Jinja2 运行以解析表达式,因此 when:
、failed_when:
和 changed_when:
始终是模板化的,您应该避免添加 {{ }}
。
在大多数其他情况下,您应该始终使用括号,即使以前您可以不指定使用变量(例如 loop
或 with_
子句),因为这使得难以区分未定义的变量和字符串。
另一个规则是“胡子不能叠加”。我们经常看到这种情况
{{ 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
等等。
如何修复在获取文件时出现的“协议错误:文件名与请求不匹配”错误?
自 OpenSSH 的 7.9p1
版本起,SCP 客户端存在一个 错误,当使用 SCP 作为文件传输机制时,该错误可能会在 Ansible 控制节点上触发。
错误
无法将文件传输到 /tmp/ansible/file.txtrnprotocol 错误:文件名与请求不匹配
在这些版本中,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/生物识别/指纹/U 盘/OTP/…
不,Ansible 旨在针对多个目标执行多个任务,最大限度地减少用户交互。与大多数自动化工具一样,它与旨在处理人为交互的交互式安全系统不兼容。大多数这些系统要求每个目标进行二次提示,这会阻止扩展到数千个目标。它们还往往具有非常短的有效期,因此需要频繁重新授权,这对许多主机和/或长时间的任务来说也是一个问题。
在这种环境中,我们建议对 Ansible 的执行进行安全保护,但仍然允许它使用不需要此类措施的“自动化用户”。使用 AWX 或 Red Hat Ansible Automation Platform,管理员可以设置对清单的 RBAC 访问权限,以及管理凭据和作业执行。
“验证”选项不足以满足我的需求,我该怎么办?
许多创建或更新文件的 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
为什么 regex_search
过滤器返回 None 而不是空字符串?
在 jinja2 2.10 版本之前,Jinja 只能返回字符串,但 Ansible 在某些情况下需要 Python 对象。Ansible 使用 safe_eval
,并且仅将看起来像特定类型 Python 对象的字符串通过此函数发送。对于 regex_search
无法找到匹配项的情况,结果(None
)将转换为字符串“None”,这在非本地 jinja2 中没有用。
以下是一个单一模板操作的示例,展示了这种行为
{{ 'ansible' | regex_search('foobar') }}
这个示例不会导致 Python None
,因此 Ansible 在历史上将其转换为“” (空字符串)。
原生 jinja2 功能实际上允许我们返回完整的 Python 对象,这些对象在任何地方都始终以 Python 对象的形式表示,因此使用 regex_search
的单一模板操作的结果可能导致 Python None
。
注意
当 regex_search
用作中间结果,然后与 jinja2 none
测试进行比较时,不需要原生 jinja2 功能。
{{ 'ansible' | regex_search('foobar') is none }}
如何向文档提交更改?
Ansible 的文档保存在主项目 git 仓库中,贡献的完整说明可以在 docs README GitHub 上查看 中找到。感谢!
ansible.legacy
和 ansible.builtin
集合有什么区别?
两者都不是真正的集合。它们是由核心引擎虚拟构建的(合成集合)。
ansible.builtin
集合只引用与 ansible-core
一起提供的插件。
ansible.legacy
集合是 ansible.builtin
的超集(您可以通过 ansible.legacy
引用内置插件)。您还可以将“自定义”插件添加到 已配置的路径和相邻目录 中,并能够覆盖具有相同名称的内置插件。
此外,当您没有指定 FQCN 时,ansible.legacy
是您默认获得的。所以这
- shell: echo hi
实际上等同于
- ansible.legacy.shell: echo hi
但是,如果您没有覆盖 shell
模块,您也可以直接将其写为 ansible.builtin.shell
,因为 legacy 将解析为内置集合。
这里没有我的问题
如果您没有找到问题的答案,您可以在我们的邮件列表或聊天频道中提问。有关订阅邮件列表或加入聊天频道的说明,请参阅 与 Ansible 社区沟通。
另请参阅
- 使用剧本
剧本简介
- Ansible 提示和技巧
剧本技巧和窍门
- 用户邮件列表
有疑问?访问 Google 群组!