历史上,网络主要由硬件和少量软件组成。改变它的拓扑结构需要在机箱中安装和配置新的交换机或刀片,或者至少重新连接一些电缆。现在,情况发生了变化,为满足多租户环境(如云托管或基于微服务的部署)而构建的复杂基础架构需要更加灵活的网络。这导致了软件定义网络 ( SDN )的出现,这种方法集中了网络配置(历史上是按设备配置的),并导致网络拓扑被定义为一个整体,而不是一系列组成部分。如果你愿意的话,它是网络本身的一个抽象层,因此意味着就像基础设施即服务一样,网络现在可以用代码来定义。
自从这本书的前一版出版以来,大量的工作已经进入 Ansible,以增强和标准化项目中的网络自动化。除此之外,集合的出现使许多网络设备的模块与ansible-core
包分离,从而使网络供应商能够更好地掌握他们的代码,并根据需要发布它们,而不是被 Ansible 发布本身的节奏所驱动。在撰写本文时,只有少数 Ansible 集合(以及模块)仍在 Ansible Network 团队的职权范围内,大多数现在由供应商自己直接维护。这对所有相关人员来说都是一件好事,它确保了 Ansible 网络产品的更高可靠性和更快发展。
最终,这意味着一件事——您现在可以在 Ansible 行动手册中定义您的网络基础架构,就像我们在上一章中描述的那样,您可以描述您的计算基础架构。
在本章中,我们将通过涵盖以下主题来探讨这一迅速增长的重要领域:
- 可用于网络管理
- 处理多种设备类型
- 使用
cli_command
模块 - 用 Ansible 配置 Arista EOS 交换机
- 用 Ansible 配置积云网络交换机
- 最佳实践
按照本章中给出的示例,您将需要一台运行 Ansible 4.3 或更新版本的 Linux 机器。几乎任何风格的 Linux 都可以——对于那些对细节感兴趣的人来说,本章中给出的所有代码都在 Ubuntu Server 20.04 LTS 上进行了测试,除非另有说明,并且在 Ansible 4.3 上进行了测试。本章附带的示例代码可从 GitHub 下载,网址为:https://GitHub . com/packktpublishing/Mastering-Ansible-第四版/tree/main/Chapter13 。
查看以下视频,了解《行动守则》:https://bit.ly/3G5pNjJ。
核心网络设备,如交换机、路由器和防火墙,长期以来都有管理接口,尤其是在企业环境中。命令行界面 ( CLIs )在支持脚本的设备上一直很受欢迎,所以,正如你已经猜到的,它们非常适合 Ansible 自动化。
从历史上看,团队在管理这些设备时面临无数挑战,包括维护配置、应对设备故障/丢失以及在出现问题时获得支持。通常,公司发现自己被锁定在一个单一的网络供应商(或者充其量是一小部分)中,以便能够使用专有工具来管理网络。就像任何你被一项技术束缚的情况一样,这既有好处也有坏处。除此之外,软件定义网络的复杂性也在快速变化和发展,挑战变得更加严峻。在本节中,我们将探讨 Ansible 如何应对这些挑战。
正如我们在本书中所看到的,Ansible 被设计成在尽可能多的场景中使自动化代码 Ansible 和可重用。在 第 12 章 *【基础设施配置】*中,我们使用几乎相同的行动手册在四个不同的供应商上配置基础设施,为了支持这一点,给出的示例非常简单。当然,如果我们愿意的话,我们可以通过使用角色来消除如此多代码的重复来进一步发展这一点,但是这种简单性是为了证明代码是多么相似,而不管使用的是哪个提供者。
简而言之,一旦我们定义了第一个剧本,Ansible 就可以编写在多个环境中运行的剧本,以最小的努力实现相同的目标。网络也是如此。集合的出现意味着不再有中央网络模块索引,因为集合本身定义了支持哪些平台。然而,【https://docs.ansible.com/ansible/latest/network/index.html】提供的可用于网络自动化页面是开始学习所有基本概念的好地方,因为它提供了许多受支持平台的列表。但是,此页面上的平台列表并不完整–例如,在本章的后面部分,我们将了解如何配置基于 Cumulus Linux 平台的交换机,并且在前面提到的页面上没有明确列出对此的支持。
部分原因是Community.Network
集合支持积云 Linux 和大量其他网络技术。支持的平台和模块列表可以在这里找到:https://docs . ansi ble . com/ansi ble/latest/collections/community/network/。
由于 Ansible 文档是自动构建的,将模块分散到集合中在网络等领域有一点破坏性,并且无疑会随着时间的推移而改进。与此同时,稍微搜索一下,您肯定会找到对您的网络平台的支持,因为这种支持只是随着 Ansible 的发展而扩展。
结果是,有了如此广泛(且不断增长)的设备支持,网络管理员可以轻松地从一个中心位置管理所有设备,而不需要专有工具。然而,好处不止于此。
正如我们已经讨论过的,Ansible 代码是高度 Ansible 的。在网络自动化的世界里,这是极其宝贵的。首先,这意味着您可以在开发网络(或模拟器)上推出配置更改并进行测试,然后一旦配置被认为已经成功测试,就可以针对不同的清单(例如生产清单)推出相同的代码。
然而,好处不止于此。从历史上看,如果软件升级或配置更改出现问题,网络工程师面临的挑战是与供应商合作以成功获得支持和帮助。这需要向供应商发送足够的详细信息,以使他们至少了解问题,并最有可能想要重现问题(尤其是在固件问题的情况下)。当在 Ansible 中定义网络配置时,可以将行动手册本身发送给供应商,使他们能够快速准确地了解网络拓扑并诊断问题。我遇到过这样的情况:当提出支持问题时,网络供应商开始坚持使用包含网络配置的 Ansible 行动手册。这是因为它使他们能够比以往任何时候都更快地解决问题。
Ansible Vault 的有效使用确保了敏感数据不会出现在主行动手册中,这意味着在发送给第三方之前可以很容易地将其删除(即使是意外发送的,也不会被读取,因为它是在静止状态下加密的)。
虽然大多数企业都有健全的变更控制程序,但不能保证 100%的时间都遵循这些程序,而且众所周知,人类会在没有准确记录他们所做的变更的情况下调整配置。将网络配置移动到 Ansible 消除了这个问题,因为配置是由行动手册定义的已知状态,可以很容易地与使用check
运行的运行配置进行比较。
这不仅是可能的,而且可以轻松备份和恢复配置。比方说,一个开关出现故障,必须更换。如果更换的是同一类型,可以通过运行配置其前身的相同 Ansible 行动手册来快速配置和投入使用,如果合适,行动手册的运行可能仅限于更换交换机库存主机,尽管 Ansible 的幂等特性意味着在整个网络上运行应该是良性的。
这也有助于版本控制——网络配置行动手册可以被推送到一个源控制存储库,使得配置版本能够被跟踪,并且随时间变化的差异能够被容易地检查。
通常,可能需要对网络进行微小的更改来推出一个新项目——可能是一个新的 VLAN 或 VXLAN,或者是一些以前没有使用过的已经投入使用的端口。配置参数将由变更请求和/或网络设计来明确定义,而对高素质的网络工程师来说,进行简单的配置变更可能并不是最好的用途。诸如此类的任务通常是例行公事,因为配置更改可以在 Ansible 行动手册中模板化,并传递给它由更改请求定义的变量(例如,端口号和 VLAN 成员资格详细信息)。
这样,工程师就可以腾出时间从事更重要的工作,例如设计新的架构、新产品研究和测试。
再加上像 AWX 或 Ansible Tower 这样的包的使用(正如我们在本书前面所讨论的),简单且经过良好测试的更改可以完全自动化,或者通过简单地传递所需的参数传递给一线团队来安全地执行。这样,无论执行变更的人员技能如何,人为错误的风险都会大大降低。
随着这些优势的确立和理解,让我们看看如何开始编写行动手册来处理多设备网络。
在我们不局限于单一供应商的世界中,了解我们如何处理基础架构中的不同网络设备非常重要。我们在前一章中已经确定,对于不同的基础设施供应商,在让 Ansible 与其交互方面,为每个供应商都建立了类似的流程。这可能与交换机有点不同,因为并非所有的命令行交换机接口都是相同的。一些,比如在一个积云网络交换机上,可以利用直接的 SSH 连接,这意味着我们在本书中所学的关于连接到一个支持 SSH 的设备的一切仍然适用。
然而,其他设备,如 F5 BIG-IP,不使用这样的接口,因此需要模块从 Ansible 主机运行。配置参数必须直接传递给模块,而不是使用简单的连接相关主机变量,如ansible_user
。
当然,在这场讨论中有一个灰色地带。一些设备,如 Arista EOS 或基于思科 IOS 的设备,将由 SSH 管理,因此您可能会误认为您可以使用简单的 SSH 连接来连接它们,就像它们是任何其他 Linux 主机一样。然而并非如此——如果我们回顾 第 1 章**Ansible的系统架构和设计,我们会发现 ansi ble 要通过 SSH 自动执行命令,它会将一小块 Python 代码发送到远程主机上执行(或者在 Windows 主机上是 PowerShell)。大多数交换机虽然具有基于 SSH 的用户界面,但不能期望它们具有 Python 环境,因此这种操作模式是不可能的(这里的 Cumulus Linux 是个例外,因为它具有可用的 Python 环境)。因此,像 Arista EOS 和思科 IOS 这样的设备在历史上一直使用本地执行,由此 Ansible 代码在控制节点本身上运行,然后自动化请求被转换成适当的命令行界面(或应用编程接口)调用并直接传递给设备。因此,不需要远程 Python 环境。
*你会发现许多利用这种操作模式的历史例子,它们很容易被识别,因为它们在游戏定义的某个地方会有下面的一行:
connection: local
这也可能被定义为库存变量:
ansible_connection=local
不管这是如何发生的,本地连接操作模式已经被弃用,虽然大多数使用这种连接模式的传统网络行动手册今天仍将运行,但预计明年将不再支持这种模式。
在可能的情况下,鼓励用户改用以下通信协议之一:
ansible.netcommon.network_cli
:该协议通过 SSH 将播放任务转化为 CLI 命令。ansible.netcommon.netconf
:该协议将播放任务翻译成可扩展标记语言数据,通过netconf
通过 SSH 发送到设备进行配置。ansible.netcommon.httpapi
:该协议使用 HTTP 或基于 HTTPS 的 API 与网络设备对话。
前面三种通信协议都是持久的——也就是说,它们不需要为每个任务建立和拆除网络连接——本地连接方法不支持这一点,因此效率明显低于这些模式。在前面的列表中,ansible.netcommon.network_cli
是你会遇到的最常见的,我们将在下一节中看到这一点。
预计在本章的示例中,你们中的许多人将无法使用各种各样的网络硬件。后面我们会看两个可以免费下载的例子(在写的时候,以你分享一点个人信息为准),如果你愿意的话可以试用。不过,现在,我们将更详细地介绍首次自动化新网络设备时采用的流程,以便您知道如何将其应用于特定情况和首选网络供应商。
使用任何网络设备时,您的第一个任务是了解您需要使用 Ansible 的什么模块。这将涉及两件事:
- 您希望自动化管理什么设备?
- 您希望在设备上执行什么任务?
有了这些信息,您可以搜索 Ansible 文档网站和 Ansible Galaxy,了解您的设备和所需任务是否受到支持。比如说,你有一个 F5 大 IP 设备,你想在这个设备上保存和加载配置。
快速浏览一下 Ansible Galaxy 上的可用收藏,我们应该看看f5networks.f5_modules
收藏(https://galaxy.ansible.com/f5networks/f5_modules),然后从这里开始,我们应该看看f5networks.f5_modules.bigip_config
模块,它会做我们需要的事情。因此,我们可以继续进行模块配置(参见下一节),然后围绕该模块编写所需的剧本。
但是,如果您的设备没有模块,会发生什么?在这种情况下,您有两个选择。首先,您可以为 Ansible 编写一个新模块来执行您需要的任务。这是你可以贡献给社区的东西, 第 10 章扩展 Ansible 包含了开始这项任务所需的所有细节。
或者,如果您想让某个东西快速启动并运行,请记住 Ansible 可以用它支持的大多数传输方法发送原始命令。例如,在作者的实验设置中,他们有一个 TP-Link 管理的交换机。没有支持这种特定交换机的本机 Ansible 模块,但是,除了基于网络的图形用户界面之外,这种交换机还具有 SSH 管理界面。如果我想快速启动并运行某个东西,我可以使用 Ansible 的ansible.builtin.raw
模块通过 SSH 向交换机发送原始命令。很自然,这个解决方案缺乏优雅,使得很难写出幂等的剧本,但是它确实让我能够使用 Ansible 和这个设备快速启动和运行。
这捕捉到了 Ansible 的美妙之处——管理新设备的便利性,以及如何通过一点点独创性将其扩展以造福社区。
由于我们已经演示了ansible.builtin.raw
模块的使用,并扩展了 Ansible,在本书的前面,我们将继续讨论我们找到了想要使用的模块的情况。正如您可能在本书的前几章中注意到的,尽管 Ansible 包含了许多现成的模块,但并不是所有模块都能立即工作。
Ansible 是用 Python 编写的,在大多数情况下,有依赖关系的地方就会有 Python 模块。重要的是查看文档。例如,以我们在上一节中选择的f5networks.f5_modules.bigip_config
模块为例。快速浏览一下文档的需求部分可以发现,如果您运行的是 3.5 之前的 Python 版本,这需要(在编写本文时)一个ipaddress
Python 模块。
如果您没有运行 Python 3.5 或更高版本,您将需要安装它以使集合的模块正常运行。有多种方法可以安装它——一些操作系统可能已经构建了一个原生包,如果这个包是可用的,那么只要它满足版本要求,使用它是完全可以的。这在供应商支持方面可能是有利的。但是,如果没有这样的软件包,可以使用pip
(或pip3
)工具轻松安装 Python 模块。假设这已经在您的系统上,安装就像使用以下代码一样简单:
sudo pip install ipaddress
此外,请务必查看文档的注释部分(对于我们当前讨论的模块,请访问https://clouddocs . F5 . com/products/orchestration/ansi ble/develop/modules/bigip _ config _ module . html #注释)。继续这个例子,我们可以看到它只支持 BIG-IP 软件第 12 版和更新版本,所以如果你在一个较早的版本,你将不得不寻找另一个途径来自动化你的设备(或者升级软件,如果这是一个可接受的路径)。
一旦您的模块已经配置完毕,并且所有的需求(无论是 Python 模块依赖还是设备软件需求)都已满足,就该开始编写您的行动手册了。这应该是一项遵循模块文档的简单任务。假设我们想在 F5 大知识产权设备上重置配置。从文档中,我们可以看到身份验证参数被传递给了模块本身。另外,示例代码显示了delegate_to
任务关键字的使用;这两条线索都告诉我们,该模块并没有使用 Ansible 的本机 SSH 传输,而是在模块本身中定义的传输。因此,重置单个设备配置的行动手册可能如下所示:
---
- name: reset an F5
hosts: localhost
gather_facts: false
tasks:
- name: reset my F5
f5networks.f5_modules.bigip_config:
reset: yes
save: yes
provider:
server: lb.mastery.example.com
user: admin
password: mastery
validate_certs: no
在这种情况下,我们使用文档中的教科书示例来重置我们的配置。请注意,由于我们的hosts
参数仅定义了localhost
,因此我们不需要delegate_to
关键字,因为在本手册中f5networks.f5_modules.bigip_config
模块将仅从localhost
运行。
通过这种方式,我们已经自动化了一个简单的,但是手动的和重复的,可能需要执行的任务。运行剧本就像执行以下命令一样简单:
ansible-playbook -i mastery-hosts reset-f5.yaml
当然,要测试这份剧本,你必须有一台 F5 大知识产权设备来测试。不是每个人都有这个,所以,在本章的后面,我们将继续演示每个阅读这本书的人都可以使用的真实例子。但是,本章的这一部分旨在为您提供将网络设备(无论它们是什么)与 Ansible 集成的全面概述。因此,希望即使你有一个我们在这里没有提到的设备,你也能理解如何让它工作的基本原理。
在我们进入实际操作示例之前,我们必须看一下自本书上一版出版以来,已经成为网络设备配置核心的模块。
正如我们在上一节中所讨论的,不能期望大多数网络设备上有一个工作的 Python 环境,因此,Ansible 将使用本地执行——也就是说,与网络设备相关的所有任务都在 Ansible 控制节点本身上执行,转换为设备接收的正确格式(可以是 CLI、基于 HTTP 的 API 或其他格式),然后通过网络发送到设备。Ansible 2.7 主要依靠一种被称为local
的通信协议来实现网络设备自动化。这种方法效果很好,但有几个缺点,包括:
local
协议不支持持久的网络连接——需要为执行的每个任务建立一个新的连接,然后将其拆除。这非常低效和缓慢,完全不符合 Ansible 最初的愿景。- 每个模块负责自己的通信协议,因此每个模块的库需求通常是不同的,并且代码没有被共享。
- 为网络设备通信提供凭据的方式几乎没有共性,并且必须在每个任务中提供凭据,这再次导致代码效率低下。
由于这些问题,local
协议有望在明年内从 Ansible 中删除,我们鼓励您开始使用本章前面的处理多种设备类型一节中列出的三种新协议之一。其中最常见的是ansible.netcommon.network_cli
协议,该协议可用于连接您可能希望使用 Ansible 自动化的大量网络设备–通过查看https://docs . Ansible . com/Ansible/latest/network/user _ guide/platform _ index . html #逐平台设置提供的表格,您可以看到该模块在网络设备配置中的使用有多普遍。
该协议的好处在于,现在可以在清单中设置身份验证参数,就像它们可以在任何其他操作系统中设置一样,从而简化了行动手册,并且无需重复设置凭据。还支持持久连接,这意味着自动化运行更快。那么,它是如何工作的呢?
好吧,让我们假设我们有一个基于思科 IOS 的网络设备要配置。我们可以定义一个简单的清单文件,如下所示:
[ios_devices]
ios-switch1.example.org
[ios_devices:vars]
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: cisco.ios.ios
ansible_user: admin
ansible_password: password123
ansible_become: yes
ansible_become_method: enable
ansible_become_password: password123
注意到这有多容易吗?我们设置了相同的ansible_user
、ansible_password
和ansible_become
库存变量,我们已经在本书的示例中看到了这些变量。然而,我们在这里添加了ansible_connection
变量,它告诉 Ansible 使用ansible.netcommon.network_cli
协议。当然,这只是故事的一半——该协议告诉 Ansible 通过 SSH 发送 CLI 命令,但没有告诉 Ansible 连接的另一端是什么设备类型。由于所有的 CLI 在某些方面都有所不同,这很重要,因此我们使用ansible_network_os
来告诉 Ansible 它正在与哪种类型的设备通话,以便它可以对该设备说正确的 CLI 语言。
最后,我们需要改变ansible_become
方法——在 Linux 上,这几乎肯定是sudo
,但在 IOS 交换机上,这是enable
。我们还需要提供权限提升的密码,就像您将sudo
配置为需要密码一样。
这就很复杂了——一个利用这个清单及其分配的变量的简单剧本可能是这样的:
---
- name: Simple IOS example playbook
hosts: all
gather_facts: no
tasks:
- name: Save the running config
cisco.ios.ios_config:
save_when: always
请注意这是多么容易——我们现在可以用与使用 Linux 或 Windows 主机时相同的方式编写行动手册。当然,每个联网平台都有细微的差别,无数受支持设备的平台特定选项可以在这里找到:https://docs . ansi ble . com/ansi ble/latest/network/user _ guide/platform _ index . html。
使用ansible.netcommon.network_cli
协议的另一个好处是它支持ansible_ssh_common_args
库存变量,就像任何其他 SSH 托管主机(Linux 或带有 OpenSSH 的 Windows)一样。这一点很重要,因为许多网络设备都是通过安全、隔离的网络进行管理的,而且考虑到如果访问这些设备的权限落入坏人之手,可能会造成的损害,这是正确的。这意味着这些主机通常使用堡垒主机(也称为跳转主机)来访问。要通过此堡垒运行自动化行动手册,您可以将以下内容添加到库存变量中:
ansible_ssh_common_args: '-o ProxyCommand="ssh -W %h:%p -q jumphost.example.org"'
前面的示例假设您的堡垒或跳转主机的主机名为jumphost.example.org
,并且您已经设置了从您的 Ansible 控制节点对其进行基于无密码密钥的 SSH 访问。当然,还有其他方法可以使用这个堡垒主机进行身份验证,这是留给您探索的一个练习。
当然,这只是一个例子,基于思科 IOS 的设备并不是每个读这本书的人都能接触到的。然而,在撰写本文时,您可以通过在 Arista vEOS 网站上注册一个免费帐户并前往https://www.arista.com/en/support/software-download,轻松、自由地下载 Arista vEOS 映像。从这里,您可以将这些映像加载到网络模拟工具中,例如 GNS3 和自己实验 Ansible 的网络自动化,而不需要访问任何昂贵的硬件。我们将在下一节讨论这个问题。
让起来并使用 Arista 开关(或虚拟开关)运行只是留给你的一个练习,但是如果你有兴趣在 GNS3 中这样做,这是一个流行且免费提供的学习网络的开源工具,这里有一些很好的指导:https://gns3.com/marketplace/appliances/arista-veos。
您可能足够幸运,指尖上有一个基于 Arista EOS 的设备,这也没问题——本节中的自动化代码在这两种情况下都同样适用。
以下示例是针对 GNS3 中的 Arista vEOS 设备创建的,使用上述链接中的说明创建。第一次引导设备时,您需要取消 ZeroTouch 设置。为此,请使用admin
用户名登录(默认密码为空),并输入以下命令:
zerotouch cancel
虚拟设备将重新启动,当它再次启动时,使用相同的凭据登录。输入以下命令进入特权用户模式:
enable
请注意,这是我们之前在思科 IOS 示例中使用的ansible_become
方法,我们将很快再次使用相同的方法。现在,使用以下命令进入配置模式:
configure terminal
如果默认情况下 vEOS 设备的密码为空,则不能通过 SSH 管理该设备,因此我们将使用以下命令为虚拟设备设置一个简单的密码:
username admin secret admin
这会将admin
用户的密码设置为admin
。接下来(假设您已经将 vEOS 设备的管理接口连接到您的虚拟网络),您将需要启用该接口并为其提供有效的 IP 地址。确切的 IP 地址将取决于您的测试网络,但实现这一点的命令如下所示:
interface management 1
no shutdown
ip address 10.0.50.99/8
最后,退出配置模式并将配置写入交换机,以便下次重新启动时再次启动:
end
write
就是这样——您的 vEOS 设备现在可以使用 Ansible 进行管理了!
有了这个配置,您现在可以为您的测试交换机定义一个清单。我按如下方式创建了我的(基于前面的配置):
[eos]
mastery-eos ansible_host=10.0.50.99
[eos:vars]
ansible_connection=ansible.netcommon.network_cli
ansible_network_os=arista.eos.eos
ansible_user=admin
ansible_password=admin
ansible_become=yes
ansible_become_method=enable
请注意,这与我们在上一节中创建的基于思科 IOS 的示例清单有多相似?这是ansible.netcommon.network_cli
协议的伟大之处之一——当使用这个协议时,您的所有代码都更容易编写。当然,与本书中的大多数示例一样,您不会将管理密码放在外面,但它可以使示例保持简单明了,并且鼓励您探索使用 Ansible Vault 来安全存储它们。
从这里,我们可以开发一个简单的剧本来演示针对我们的虚拟交换机的命令自动化。让我们选择一个简单的任务——我们将确保交换机上的Ethernet1
接口已启用,给它一个有意义的名称,然后将配置写入交换机,以便它在重新启动后仍然存在。实现这一点的行动手册可能如下所示:
---
- name: A simple play to enable Ethernet1 on our virtual switch and write the config
hosts: all
gather_facts: no
tasks:
- name: Enable Ethernet1 on the switch
arista.eos.eos_interfaces:
config:
- name: Ethernet1
enabled: yes
description: Managed by Ansible
state: replaced
- name: Write the config to flash if it has been modified
arista.eos.eos_config:
save_when: modified
你可以用你习惯的方式来运行这个剧本。如果您正在运行本书附带的示例代码,其命令如下:
ansible-playbook -i mastery-nethosts eosconfig.yml
当您对您的开关运行时,您应该会看到类似如下的 Ansible 输出:
图 13.1–使用 Ansible 配置 Arista vEOS 设备
现在,当然,由于我们正在使用 Ansible 执行这一配置更改,我们预计更改将是等幂的——我们应该能够再次运行相同的剧本,并且不会发生任何破坏性的事情。如果您再次运行您的剧本,输出应该如下所示:
图 13.2–再次运行相同的剧本来演示幂等性
如绿色ok
任务状态所示,该行动手册已经成功运行了第二次,这次没有对交换机配置进行任何更改。
如果您选择,您可以通过将 ssh 直接插入交换机并执行以下命令来验证我们的行动手册运行结果:
enable
show running-config
从这里,您应该会看到如下内容:
图 13.3–手动查询我们的虚拟操作系统设备的配置
在这里,我们可以看到的Ethernet1
界面有我们在剧本中设置的描述,没有禁用的指令,从而确保启用。
就是这样——通过这个例子,您刚刚在 Ansible 中实现了您的第一个真实网络设备自动化!希望这能向您表明,尤其是现在,考虑到ansible.netcommon.network_cli
协议的出现,实现您想要的配置非常容易和快速。大多数支持该协议的设备都将类似地工作,如果您对此感兴趣,我们鼓励您进一步探索。然而,如果我们想用另一个设备工作呢?好吧,Cumulus Linux(现在归 NVIDIA 所有)是一个用于网络设备的开源操作系统,可以在白盒硬件上运行——也就是说,它不属于任何特定的硬件。幸运的是,你可以免费下载一份 cuculus VX,一个虚拟版本的他们的交换机操作系统进行实验。在下一节中,我们将看看 Ansible 如何实现这个网络平台的自动化。
culusLinux(由 culusNetworks 创建,被 NVIDIA 收购)是一个开源网络操作系统,可以在各种裸机交换机上运行,为数据中心联网提供了一种开源方法。对于网络设计来说,这是一个巨大的飞跃,也是对过去专有模型的重大转变。他们提供了一个免费的软件版本,可以在您选择的虚拟机管理程序上运行,用于测试和评估目的,称为“VX 积云”。本节中的示例基于积云 VX 4 . 4 . 0 版。
快速的一点研究表明,积云 VX 将使用 Ansible 的标准 SSH 传输方法。由于是专门为运行在交换机硬件上而设计的 Linux 发行版,因此能够以远程执行模式运行,因此不需要ansible.netcommon.network_cli
协议。此外,仅定义了一个模块来使用该系统,network.cumulus.nclu
,它是community.network
集合(https://galaxy.ansible.com/community/network的一部分。使用本模块不需要先决模块,因此我们可以直接定义我们的库存。
默认情况下,VX 积云启动时的管理界面已配置为使用 DHCP 获取 IP 地址。根据您的运行方式,您可能会发现它还有三个其他虚拟交换机端口供我们测试和使用其配置,尽管如果您将其集成到 GNS3 等工具中,您会发现您可以轻松地重新配置您可用的虚拟交换机端口数量。
如果您运行的是比 3.7 更早的积云 Linux 版本,您会发现该映像已经设置了默认登录凭据。因此,假设您建立了虚拟交换机的 IP 地址,您可以创建一个简单的清单,如下所示,它使用默认的用户名和密码:
[cumulus]
mastery-switch1 ansible_host=10.0.50.110
[cumulus:vars]
ansible_user=cumulus
ansible_ssh_pass=CumulusLinux!
较新版本的积云 Linux,如版本 4.4.0(编写本文时可用的最新版本,用于本节中的示例),要求您在首次启动时设置交换机的密码。如果您正在使用此版本,您将需要第一次启动虚拟交换机,然后使用默认用户名cumulus
和默认密码cumulus
登录。然后会提示您更改密码。
完成后,您就可以自动配置交换机了。您可以使用我们之前定义的清单,只需用您设置的密码替换ansible_ssh_pass
值。
请注意以下几点:
ansible_host
中指定的 IP 地址几乎肯定会与我的不同——请确保为您的 culus VX 虚拟机将其更改为正确的值。您可能需要登录虚拟机控制台,通过类似ip addr show
的命令获取 IP 地址。- 同样,您永远不会在清单文件中以明文形式输入密码,但是,为了简单和节省时间,我们将在这里指定默认密码。在真实的用例中,总是使用一个保险库,或者设置基于密钥的 SSH 认证。
定义清单后,让我们使用一个特别的命令测试与ping
模块的连接,如下所示:
ansible -i switch-inventory -m ansible.builtin.ping all
如果全部设置正确,您应该会收到以下输出:
图 13.4–检查与我们的虚拟积云 Linux 交换机的可靠连接
正如我们在 第 1 章**ansi ble的系统架构和设计中所讨论的那样,ansible.builtin.ping
模块执行完整的端到端连接测试,包括传输层的身份验证。因此,如果您收到了像前面所示的成功的测试结果,我们可以满怀信心地继续并编写我们的第一份行动手册。
*## 实例
积云 VX 映像完全未配置(除了eth0
管理端口上的 DHCP 客户端配置)。根据您下载的版本,它可能有三个标有swp1
、swp2
和swp3
的交换机端口。让我们查询其中一个接口,看看是否有任何现有的配置。我们可以用一个叫做switch-query.yaml
的简单剧本来查询swp1
:
---
- name: query switch
hosts: mastery-switch1
tasks:
- name: query swp1 interface
community.network.nclu:
commands:
- show interface swp1
register: interface
- name: print interface status
ansible.builtin.debug:
var: interface
现在,假设我们使用以下命令运行该程序:
ansible-playbook -i switch-inventory switch-query.yaml
我们应该看到如下内容:
图 13.5–使用 Ansible 查询积云 Linux 上交换机端口的默认值
这证实了我们关于虚拟机映像的最初陈述—我们可以看到交换机端口没有配置。用 Ansible 和community.network.nclu
模块很容易将这个虚拟机变成一个简单的第 2 层交换机。以下剧本名为switch-l2-configure.yaml
,正是这样做的:
---
- name: configure switch
hosts: mastery-switch1
tasks:
- name: bring up ports swp[1-3]
community.network.nclu:
template: |
{% for interface in range(1,3) %}
add interface swp{{interface}}
add bridge ports swp{{interface}}
{% endfor %}
commit: true
- name: query swp1 interface
community.network.nclu:
commands:
- show interface swp1
register: interface
- name: print interface status
ansible.builtin.debug:
var: interface
请注意我们是如何使用一些巧妙的内联 Jinja2 模板在三个接口之间运行for
循环的,省去了创建重复和繁琐代码的需要。这些命令会调出三个交换机接口,并将它们添加到默认的第 2 层网桥。
这也展示了 Ansible 中可用的各种网络模块之间的差异。在上一节中,我们配置了基于 EOS 的交换机,我们有许多不同的模块可以使用,每个模块都有不同的用途,例如配置接口、配置路由和配置虚拟局域网。相比之下,基于 Cumulus Linux 的交换机只有一个模块:community.network.nclu
。这不是一个问题,但是当我们通过一个模块发送所有的配置命令时,利用 Jinja2 模板(它可以支持诸如for
循环这样的结构)很好地为我们服务。
最后,commit: true
线立即将这些配置应用到开关上。现在,让我们假设我们使用以下命令运行这个:
ansible-playbook -i switch-inventory switch-l2-configure.yaml
此时,我们将看到swp1
的不同状态,如下所示:
图 13.6–使用 Ansible 成功配置了我们的积云 Linux 虚拟交换机
正如我们可以看到的,swp1
接口现在已经启动,并且是网桥的一部分,准备切换流量。但是,如果你仔细看前面的截图,你会发现bring up ports swp[1-3]
任务的状态是ok
,而不是changed
。然而我们可以从switch
的查询结果中看到,配置发生了变化。这似乎是community.network
系列的3.0.0
版本中的一个 bug,作者已经提出来了。希望该集合的较新版本能够在更改积云交换机的配置时正确显示已更改的状态。
然而,由于我们正在查询端口的状态,我们仍然可以再次运行剧本来测试幂等性。让我们看看如果我们再次运行行动手册而不在交换机上执行任何其他步骤会发生什么:
图 13.7–用我们的 Cumulus Linux 虚拟交换机测试我们的剧本的幂等性
这次这个任务的状态还是ok
,但是我们可以看到界面状态查询结果是一样的,说明我们的配置是持久的,没有被任何不利的方式修改过(如果不支持幂等的话可能会发生这种情况)。通过这种方式,自动配置我们的积云 Linux 交换机的行动手册是幂等的,并导致一致的状态,即使它们运行了多次。这也意味着,如果交换机的配置发生漂移(例如,由于用户干预),很容易看到某些东西发生了变化。不幸的是,community.network.nclu
模块目前不支持ansible-playbook
的check
模式,但它仍然提供了一种强大的方式来配置和管理您的交换机。
用 Ansible 自动化网络硬件,比如运行 Arista EOS 和积云 Linux 的硬件,就这么简单——想想看,使用这样的组合,你能做些什么来自动化你的网络配置!我鼓励您探索这些免费工具,以了解更多关于网络自动化的知识;我想你会很快看到其中的价值。希望,即使有这些简单的例子,您也能看到,使用 Ansible 自动化网络基础设施现在不比自动化基础设施中的任何其他东西更困难。
使用 Ansible 的所有常规最佳实践都适用于使用它自动化网络设备。例如,不要将密码存储在明文中,并在适当的地方使用ansible-vault
。尽管如此,就 Ansible 而言,网络设备是它们自己的特殊设备类别,对它们的支持从 Ansible 的 2.5 版本开始蓬勃发展。因此,在使用 Ansible 实现网络自动化时,有一些特殊的最佳实践值得一提。
在组织您的网络基础设施时,充分利用 Ansible 支持的库存结构,并特别注意分组。这样做将使您的行动手册开发更加容易。例如,假设您的网络上有两个交换机——一个是我们之前检查过的积云 Linux 交换机,另一个是基于 Arista EOS 的设备。您的清单可能如下所示:
[switches:children]
eos
cumulus
[eos]
mastery-eos ansible_host=10.0.50.99
[cumulus]
mastery-switch1 ansible_host=10.0.50.110
我们知道我们不能在除了积云交换机之外的任何设备上运行community.network.nclu
模块,因此,通过谨慎使用when
语句,我们可以在行动手册中构建任务,以确保我们在正确的设备上运行正确的命令。这是一个仅在我们在前面的清单中定义的cumulus
组中的设备上运行的任务:
- name: query swp1 interface
community.network.nclu:
commands:
- show interface swp1
register: interface
when: inventory_hostname in groups['cumulus']
同样,分组的良好使用使我们能够在设备的基础上设置变量。虽然您不会在清单中明确输入密码,但是您的给定类型的交换机可能都使用相同的用户名(例如,在 Cumulus Linux 设备中为cumulus
)。或者,您的 EOS 设备可能需要特定的 Ansible 主机变量集来进行连接,并实现执行配置所需的权限提升。因此,我们可以通过添加以下代码来扩展前面的清单示例:
[cumulus:vars]
ansible_user=cumulus
ansible_password=password
[eos:vars]
ansible_connection=ansible.netcommon.network_cli
ansible_network_os=arista.eos.eos
ansible_user=admin
ansible_password=admin
ansible_become=yes
ansible_become_method=enable
良好的库存结构和变量定义将使开发您的行动手册变得更加容易,并且生成的代码将更加易于管理和使用。
Ansible 包括几个针对网络设备的特定事实收集模块,这些模块可能有助于运行条件任务或简单地报告有关设备的数据。如果您使用的是旧的local
基于连接的协议,这些特定于设备的事实模块不能在剧本开始运行时运行,因为在这个阶段,Ansible 不知道它正在与哪种设备通信。因此,我们必须告诉它收集每个设备的事实。使用本章前面描述的ansible.netcommon.network_cli
协议可以解决这个问题,因为 Ansible 可以从清单中知道它正在与哪种设备通话。
即便如此,有时在您的设备上手动收集事实也是有用的——也许是为了验证作为更大剧本的一部分而执行的一些配置工作。无论您是在这样做,还是出于遗留原因,仍然依赖于local
基于连接的协议,您都需要注意,对于不同的连接类型,您将使用不同的事实收集模块。让我们扩展 Arista EOS 和 Cumulus Linux 的例子来看看这个。
积云 Linux 交换机没有特定的事实模块(尽管,由于它们基于 Linux,仍然可以收集标准的主机事实)。以我们的 Arista EOS 设备为例,我们将基于库存中的唯一密钥运行行动手册中的arista.eos.eos_facts
模块。在我们上一节定义的示例清单中,我们的 Arista EOS 交换机位于eos
组中,并且也将ansible_network_os
设置为arista.eos.eos
。我们可以在when
语句中使用其中任何一个作为条件,在我们的开关上运行arista.eos.eos_facts
模块。就而言,我们剧本的开头可能是这样的:
---
- name: "gather all device facts"
hosts: all
gather_facts: false
tasks:
- name: gather eos facts
arista.eos.eos_facts:
when: ansible_network_os is defined and ansible_network_os == 'arista.eos.eos'
- name: gather cumulus facts
ansible.builtin.setup:
when: inventory_hostname in groups['cumulus']
请注意,我们在本行动手册的开头将gather_facts
设置为false
。如果你使用的是local
基于连接的协议,你需要像我们之前讨论的那样这样做——否则,使用ansible.netcommon.network_cli
,如果你愿意的话,你可以在游戏开始时收集事实(显然,在这个例子中,这是多余的!).
您还会注意到我们在 Arista EOS 设备上使用的更复杂的条件。由于基于 culus Linux 的交换机使用与 Linux 主机相同的基于 SSH 的传输,因此它们不需要(或者确实具有)ansible_network_os
设置,并且如果我们试图在条件中测试该变量,我们将产生一个变量 undefined 错误,因此没有定义变量的主机(在这种情况下是我们的 culus Linux 交换机)不会尝试后续任务。这几乎不是我们期待的结果!因此,当将这些主机与同一台游戏中的其他网络设备组合时,我们必须始终检查ansible_network_os
变量是否已定义,然后再尝试对其执行任何查询,就像我们在前面的示例中所做的那样。
如果您已经按照本章中的示例进行了操作,并设置了基于 Arista EOS 和 Cumulus Linux 的虚拟设备,则可以使用以下命令运行本行动手册:
ansible-playbook -i switch-inventory switch-facts.yaml
成功运行剧本的输出应该如下所示:
图 13.8–使用单一行动手册收集多种设备类型的事实
在这里,您可以看到我们不同的 facts 模块是如何在适当的设备类型上运行的,这要归功于我们在行动手册中使用的条件。通过推断我们一起完成的工作,您可以使用本章这一部分概述的技术来构建复杂得多的多设备设置。然而,如果没有更多关于跳转主机的细节,任何关于网络自动化的章节都是不完整的。接下来我们将看看这些。
最后,一个字扑在主持人身上。出于重要的安全原因,网络设备通常位于某类堡垒或跳跃主机的后面。Ansible 为此提供了几种机制,具体取决于底层网络传输。例如,SSH 连接(例如使用积云 Linux 交换机)可以利用 SSH 代理命令的能力。有几种方法可以实现这些,但最简单的方法是向清单中添加另一个组变量。例如,如果我们只能通过名为bastion01.example.com
的主机访问我们的 Cumulus Linux 交换机,并且正在使用名为jfreeman
的帐户进行身份验证,那么我们的库存变量部分将如下所示:
[cumulus:vars]
ansible_user=cumulus
ansible_ssh_pass=CumulusLinux!
ansible_ssh_common_args='-o ProxyCommand="ssh -W %h:%p -q jfreeman@bastion01.example.com"'
前面的代理命令假设已经配置了无密码身份验证,并且适用于bastion01.example.com
上的jfreeman
帐户,并且 SSH 主机密钥已经被接受。未能完成这些任务将导致错误。
像这样的 SSH 代理命令也适用于网络设备管理中使用的其他ansible_connection
模式,包括ansible.netcommon.netconf
和ansible.netcommon.network_cli
,支持跳转主机处理各种网络设备。和以往一样,确定如何处理特定类型的连接的最佳方法是查看特定网络设备的文档并遵循其中的指导。
如果我们重复前面的例子来查询我们的 Cumulus Linux 交换机的swp1
接口,我们将看到(在正确设置了 bastion 主机的情况下)行动手册的工作方式与本章前面的完全一样,并且不需要进一步的步骤或对代码的更改:
图 13.9–运行早期的示例行动手册,但这次是通过预配置的堡垒主机
这也是 Ansible 如此受欢迎的另一个原因——它不需要设置一个特殊的代理应用或服务器来访问一个孤立的网络。使用标准 SSH 协议,它可以通过网络上配置了 SSH 的任何安全主机进行连接。
这就是我们对 Ansible 网络自动化的探索。你可以自动配置的设备数量和范围只受你想象力的限制,希望这一章帮助你在这个重要的领域获得了坚实的基础,给了你进一步探索的信心。
随着越来越多的基础设施被代码定义和管理,通过 Ansible 有效地自动化网络层变得越来越重要。自从这本书的前一次发行以来,在这一领域已经做了大量的工作,尤其是自从 Ansible 2.5 发行以来。有了这些进步,现在很容易构建行动手册来自动化网络任务,从简单的设备更改到通过 Ansible 推出整个网络架构。Ansible 与代码重用、Ansible 性等相关的所有优势对于管理网络设备的人来说都是可用的。
在本章中,您学习了 Ansible 如何实现网络管理。您学习了在基础架构中处理不同设备类型的有效策略,以及如何为它们编写行动手册,然后通过 Arista EOS 和 Cumulus Linux 上的一些具体示例对此进行了扩展。最后,您了解了使用 Ansible 管理网络基础架构时必须应用的一些最佳实践。
这使我们得出这本书的结论。我要感谢你和我一起踏上通往安西布尔心脏的旅程,我希望你已经发现这是有益的。我相信您现在应该知道管理一切的策略和工具,从小的配置更改到使用 Ansible 的整个基础架构部署,并祝您在这个重要且不断发展的技术领域好运。
回答以下问题,测试您对本章的了解程度:
-
Ansible brings all the benefits of automation from infrastructure management to the world of network device management.
真的
假的
-
When working with a new network device type for the first time, you should always do what?
a)执行设备的工厂重置。
b)查阅 Ansible 文档,了解哪些集合和模块支持它,以及对这些集合和模块的要求。
c)使用
ansible.netcommon.network_cli
连接协议。d)使用本地连接协议。
-
Which execution type is described by Ansible as running its automation code on the remote host directly?
远程执行
当地执行
-
Which execution type is described by Ansible as running its automation code on the control node, and then sending the required data over a pre-selected channel (for example, SSH or an HTTP-based API)?
远程执行
当地执行
-
Which connection protocol has (for the most part) superseded the older local connection-based protocol for network devices?
a)
ansible.netcommon.netconf
b)
ansible.netcommon.httpapi
c)
ansible.netcommon.network_cli
d)
local
-
Can you gather facts for an Arista-based EOS device at the beginning of a play?
是的。
没有。
c)可以,但仅限于使用
ansible.netcommon.network_cli
协议时。 -
All network config on Arista EOS is performed using a single module.
真的
假的
-
Cumulus Linux does not require the
ansible.netcommon.network_cli
protocol because of which reason?a)不是网络操作系统。
b)它包含完整的 Linux 实现,包括 Python。
c)它使用 SSH 协议进行管理。
它没有命令行界面。
-
Good inventory management is especially important when working in multi-device-type networks.
真的
假的
-
Ansible can support the use of bastion or jump hosts without the need for special configuration or software installation.
真的
假的**