利用 ControlPersist 和 Pipelining 提升 Ansible 性能

通过启用 ControlPersist 的 SSH 连接重用功能,并利用 Pipelining 优化模块执行流程,显著提升你的 Ansible playbook 性能。本指南提供了必要的见解和实用的配置,以减少执行时间,特别是在大规模环境中。学习如何调整你的 `ansible.cfg` 文件,以实现更快、更高效的 IT 自动化。

40 浏览量

通过 ControlPersist 和 Pipelining 最大化 Ansible 性能

Ansible 是一个强大的 IT 基础架构自动化工具,能够大规模实现配置管理和应用程序部署。然而,在海量环境或管理大量节点时,为每个任务建立 SSH 连接的固有开销会成为一个主要的瓶颈。这可能导致剧本执行时间慢得令人痛苦。幸运的是,Ansible 提供了两个强大的功能:ControlPersistPipelining,它们可以通过优化 Ansible 与受管节点的通信方式来显著提高性能。

本指南将引导您了解和实现 ControlPersist 和 Pipelining。通过利用这些技术,您可以显著减少执行时间,使您的 Ansible 自动化更高效、响应更快,尤其是在拥有数百或数千台主机的环境中。对于希望有效扩展 Ansible 部署的任何人来说,掌握这些优化至关重要。

理解 Ansible 的默认连接行为

默认情况下,Ansible 会为剧本中执行的每个任务在每个受管主机上建立一个新的 SSH 连接。对于每个连接,它会执行以下几个步骤:

  1. 建立 SSH 连接:建立一个新的 SSH 连接。
  2. 传输模块:Ansible 将必要的 Python 模块(或其他相关文件)传输到远程主机。
  3. 执行模块:在远程主机上执行模块。
  4. 接收输出:Ansible 检索执行结果。
  5. 关闭连接:终止 SSH 连接。

虽然这种方法很稳健,并确保每个任务都处于干净的状态,但重复的连接和模块传输过程会消耗大量时间,尤其是在处理大量任务或大型清单时。

使用 ControlPersist 优化连接

ControlPersist 是一项 SSH 功能,允许您在指定的持续时间内保持 SSH 连接打开,即使在初始命令完成后也是如此。这意味着针对同一主机的后续 Ansible 任务可以重用现有的、打开的连接,而不是建立新的连接。这大大减少了与设置 SSH 会话相关的延迟。

ControlPersist 的工作原理

启用后,ControlPersist 指示 SSH 客户端维护一个控制主连接。随后使用相同凭据和选项连接到同一主机的 SSH 连接可以通过此主连接进行多路复用。Ansible 通过在 SSH 配置中设置 ControlPathControlPersist 选项来利用这一点。

在 Ansible 中启用 ControlPersist

您可以通过多种方式启用 ControlPersist:

  1. 通过 ansible.cfg(推荐用于全局或项目特定设置)
    编辑或创建您的 ansible.cfg 文件(位于您的 Ansible 项目目录、~/.ansible.cfg/etc/ansible/ansible.cfg 中)。将以下配置添加到 [ssh_connection] 部分:

    ini [ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=600 -o ControlPath=~/.ssh/ansible_control_%r@%h:%p

    • -o ControlMaster=auto:启用连接共享。如果存在主连接,则使用它;否则,创建一个。
    • -o ControlPersist=600:将控制连接保持打开 600 秒(10 分钟)。根据您的工作流程和安全策略调整此值。持续时间越长,潜在的重用机会越多,但同时占用的资源也越多。
    • -o ControlPath=~/.ssh/ansible_control_%r@%h:%p:定义控制套接字的路径。%r 是远程用户名,%h 是主机名,%p 是端口。这确保了不同连接使用唯一的套接字。
  2. 通过环境变量
    您可以通过环境变量直接设置 SSH 参数:

    bash export ANSIBLE_SSH_ARGS='-o ControlMaster=auto -o ControlPersist=600 -o ControlPath=~/.ssh/ansible_control_%r@%h:%p' ansible-playbook your_playbook.yml

  3. 通过剧本(对于此设置不太常见)
    虽然可行,但通常不建议在剧本本身中设置持久性 SSH 选项,因为它是一个连接级别的设置。但是,为完整起见,您可以使用 ansible.builtin.set_fact 或类似方法来影响它,但首选 ansible.cfg

ControlPersist 的注意事项

  • 安全性:确保 ControlPath 得到保护,只有授权用户才能访问控制套接字。示例中的默认路径通常对用户级别的配置是安全的。
  • 资源使用:保持连接打开会消耗控制节点和受管节点上的资源。如果您有非常多的持久连接,请监控资源使用情况。
  • 连接重置:如果中间网络设备或远程 SSH 服务器强制执行的连接超时短于 ControlPersist 的设置值,连接仍可能中断。ControlPersist 在稳定的网络环境中效果最佳。

使用 Pipelining 简化模块执行

Pipelining 是另一个强大的 Ansible 优化功能,它进一步减少了任务执行的开销。Pipelining 不再是将模块传输到远程主机、执行它们,然后再检索输出,而是直接通过 SSH 连接流式传输命令。这意味着 Ansible 不需要将模块放置在远程文件系统上或为输出创建临时文件。

Pipelining 的工作原理

启用 Pipelining 后,Ansible 会通过远程主机上的 ssh 直接执行模块。模块的标准输出和标准错误通过同一 SSH 连接管道传回给 Ansible。这消除了 Ansible 需要将文件(如 /usr/bin/ansible_module_name 或临时文件)写入远程文件系统然后执行的需要。这对于不需要权限升级或与远程文件系统进行大量交互的模块尤其有效。

在 Ansible 中启用 Pipelining

Pipelining 通过 ansible.cfg 文件或环境变量启用。

  1. 通过 ansible.cfg
    添加或修改 [ssh_connection] 部分:

    ini [ssh_connection] pipelining = True

  2. 通过环境变量
    bash export ANSIBLE_PIPELINING=True ansible-playbook your_playbook.yml

Pipelining 的注意事项

  • 权限提升:Pipelining 最适用于不需要权限提升的模块(例如,使用 become: yessudo)。当使用 become 时,Ansible 通常需要将文件复制到远程系统。如果您经常使用 become,Pipelining 带来的好处可能不那么明显,甚至可能导致某些模块类型出现问题。
  • 模块兼容性:大多数内置 Ansible 模块都与 Pipelining 兼容良好。然而,自定义模块或那些严重依赖远程文件系统操作的模块可能会表现不同。请彻底测试。
  • 连接稳定性:稳定的 SSH 连接对于 Pipelining 正确工作至关重要。
  • requiretty SSH 设置:Pipelining 与远程服务器上的 requiretty SSH 选项不兼容。如果您的 SSH 服务器在 /etc/sudoers 中有 Defaults requiretty,您可能需要禁用它或为 Ansible 连接的用户使用 !requiretty

结合 ControlPersist 和 Pipelining 以获得最大的性能提升

为了获得最显著的性能提升,强烈建议同时启用 ControlPersist 和 Pipelining。这种组合解决了两个主要的开销:连接建立和模块执行。

以下是同时启用这两项功能的 ansible.cfg 示例:

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=600 -o ControlPath=~/.ssh/ansible_control_%r@%h:%p
pipelining = True

当两者都处于活动状态时:

  1. Ansible 启动一个 SSH 连接,并在不存在主连接时建立一个控制主连接 (ControlPersist)。
  2. 对于后续任务,重用现有的、打开的连接并流式传输模块执行 (Pipelining)。

这种协同作用极大地减少了 Ansible 与每个受管节点通信所花费的时间,从而使剧本运行速度大大加快。

实际示例场景

假设有一个剧本需要在 100 台主机上执行 10 个简单的任务。

没有优化时
每个任务都需要一个新的 SSH 连接、模块传输、执行和连接关闭。这相当于 100 个主机 * 10 个任务 * (连接时间 + 模块传输时间)。如果 连接时间 是 0.5 秒,模块传输时间 是 0.2 秒,那么仅通信和传输的开销就是 100 * 10 * 0.7 = 700 秒,这还不包括实际的模块执行时间。

启用 ControlPersist 和 Pipelining 后

  1. 在每台主机上的第一个任务建立初始连接并设置控制主连接。
  2. 该主机上所有后续的 9 个任务将重用打开的连接并流式传输模块执行。

每台主机的开销更接近于 连接时间 + (9 * 最小流式处理开销)。总时间显著减少,剧本执行时间的大部分都用于模块执行的实际工作,而不是通信机制。

何时需要谨慎

虽然这些优化功能很强大,但并非在所有情况下都适用,需要仔细考虑:

  • 具有严格防火墙或网络限制的环境:频繁的连接中断或状态检查可能会干扰 ControlPersist。
  • 高安全环境:在监管严格的环境中,持续时间较长的 SSH 连接可能是一个安全隐患。请相应调整 ControlPersist 的持续时间。
  • 严重依赖 become 和文件操作的剧本:当持续使用 become 时,Pipelining 的有效性会降低,因为它通常需要文件操作。请测试对性能的影响。

结论

优化 Ansible 与受管节点的通信是实现高效、可扩展自动化的关键步骤。通过了解和实施 ControlPersistPipelining,您可以大幅缩短剧本的执行时间。ControlPersist 保持 SSH 连接的活动状态,减少连接开销,而 Pipelining 流式传输模块执行,消除了文件传输的需要。主要通过 ansible.cfg 结合使用这两个设置是管理大量主机或运行复杂剧本的 Ansible 用户的最佳实践。请始终在您的特定环境中测试这些配置,以微调性能并确保兼容性。