DevOps-网络管理指南-全-
DevOps 网络管理指南(全)
原文:
annas-archive.org/md5/b436360b9a3bff3c3cdcdb394d5f5b1a译者:飞龙
前言
本书的标题是《面向网络的 DevOps》。你可能已经非常了解,DevOps 是“开发(Development)”和“运维(Operations)”的缩写,那么它为什么与网络有关系呢?的确,DevOps 的名称中并没有“Net”,尽管可以说,DevOps 的职责范围已经远远超出了最初的目标。
最初的 DevOps 运动旨在消除开发与运营团队之间的“把问题扔过墙”的被动心态,但 DevOps 可以有效地用于促进 IT 所有团队之间的协作,而不仅仅是开发和运营人员。
DevOps 作为一个概念,最初旨在解决开发人员编写代码、做出重大架构更改时,不考虑需要将代码部署到生产环境的运营团队的情况。所以,当运营团队准备将开发人员的代码变更部署到生产环境时,这通常会导致部署失败,意味着关键的软件修复或新产品无法按计划到达客户,部署过程通常需要几天甚至几周才能修复。
这导致了所有相关团队的挫败感,因为开发人员不得不停止编写新功能,而是要帮助运营人员修复部署过程。运营团队也会感到沮丧,因为他们通常没有被告知部署新版本到生产环境时需要对基础设施做出更改。因此,运营团队没有准备好生产环境,以支持架构变更。
这一常见的 IT 场景突出了一个断裂的流程和操作模型,这种情况不断发生,并在开发和运营团队之间引发摩擦。
“DevOps”是一个旨在促进之前有冲突的团队之间的合作与沟通的倡议。它鼓励团队每天进行沟通,彼此了解变更,从而避免可避免的情况发生。因此,恰恰是开发和运营人员是 DevOps 最早试图解决的孤岛。结果,DevOps 被标榜为一种将团队统一为一个流畅的整体功能的方式,但它本来也可以叫别的名字。
DevOps 旨在改善团队之间的工作关系,并创造一个更愉快的工作环境,因为坦白说,没有人喜欢每天处理冲突或修复可以避免的问题。它还旨在促进团队之间的知识共享,以防止开发团队被视为“对基础设施一无所知”,而运营团队则被视为“变更的障碍”和“拖慢开发进度”。这些是各个部门孤立工作时常见的误解,因为他们没有花时间去理解彼此的目标。
DevOps 努力构建一个团队之间彼此欣赏、尊重共同目标的办公环境。DevOps 无疑是当今 IT 行业讨论最多的话题之一。它的流行与敏捷软件开发的兴起并非偶然,因为敏捷软件开发是作为瀑布式方法的替代方案出现的。
瀑布式开发和“V 模型”包括了分析、设计、实现(编码)和测试的不同阶段。这些阶段传统上被划分为不同的孤立团队,并设有正式的项目交接日期,这些日期是固定不变的。
敏捷诞生于意识到在快节奏的软件行业中,长期运行的项目并不是最佳选择,不能为客户提供真正的价值。因此,敏捷推动项目进入更短的迭代周期,将分析、设计、实现和测试纳入两周一轮的周期(冲刺),并采用原型化方法。
原型化方法采用增量开发的概念,使得公司能够在发布周期的早期收集产品反馈,而不是使用“大爆炸”方法,在实施阶段结束时一次性交付完整解决方案。
在瀑布式实施阶段结束时以瀑布方式交付项目,存在交付客户不需要的产品或开发人员误解需求的风险。这些问题通常仅在最终测试阶段被发现,此时项目已经准备好推向市场。这常常导致项目被认为是失败,或者出现巨大的延迟,而此时可以进行昂贵的返工和变更请求。
敏捷软件开发大部分时间推动了团队之间的孤岛现象的打破,这种孤岛现象通常与瀑布式软件开发相关,并且加强了每天进行协作的需求。
随着敏捷软件开发的引入,软件测试的方式也发生了变化,DevOps 的原则同样被应用于测试功能。
质量保证测试团队再也不能只是被动应对,就像之前的运营团队一样。因此,这促使测试团队需要更高效地工作,不再拖延产品进入市场的时间。然而,这不能以牺牲产品质量为代价,因此他们需要找到一种方式,确保应用程序得到充分测试,并通过所有质量保证检查,同时以更智能的方式工作。
已广泛接受质量保证测试团队不能再与开发团队分开孤立运作;相反,敏捷软件开发推动了测试用例与软件开发并行编写,因此它们不再是一个独立的活动。这与将代码部署到测试环境中,并交给测试团队执行手动测试或运行一组测试包来被动处理问题的做法截然不同。
敏捷方法促进了开发人员和质量保证测试人员每天在敏捷团队中共同工作,在软件打包部署之前进行测试,之后这些相同的测试将得到维护、更新,并用于生成回归测试包。
这已被用来减轻由于开发人员提交的代码更改破坏了质量保证测试团队的回归测试包所引起的摩擦。在独立的测试团队中,一个常见的摩擦场景是开发人员突然更改了图形用户界面(GUI),导致部分回归测试失败。这个更改没有通知测试团队。测试失败是因为它们是为旧版 GUI 编写的,而突然变得过时,而不是因为开发人员实际上引入了软件故障或 bug。
这种反应式的测试方法没有建立对自动化测试包报告的测试失败有效性的信心,因为这些失败并不总是完全由于软件故障,而且由于 IT 结构的次优,导致了不必要的延迟。
如果开发和测试团队之间的沟通更好,运用 DevOps 提倡的原则,那么这些延迟和次优的工作方式是可以避免的。
最近,我们看到了 DevSecOps 的兴起,它通过将安全性和合规性集成到软件交付过程中,取代了手动操作和分离的反应性举措。DevSecOps 借助 DevOps 和敏捷哲学,并采用了将安全工程师嵌入到敏捷团队中的想法,以确保在项目开始时就满足安全要求。
这意味着安全性和合规性可以作为自动化阶段集成到持续交付管道中,在每次软件发布时运行安全合规检查,并且不会延缓开发人员的软件开发生命周期,同时生成必要的反馈循环。
因此,网络团队也可以从 DevOps 方法论中学习,就像开发、运维、质量保证和安全团队一样。这些团队已经利用敏捷流程来改善与软件开发过程的互动,并从使用反馈循环中受益。
网络工程师有多少次不得不推迟软件发布,因为需要实施网络变更,而这些变更通过与其他部门流程不对接的票务系统低效地进行?网络工程师手动实施的网络变更又有多少次导致生产服务中断?这并不是对网络团队或网络工程师能力的批评,而是认识到运营模型需要改变,并且他们有能力做到这一点。
本书内容概览
本书将探讨如何提高网络变更的效率,以免影响软件开发生命周期。它将帮助概述网络工程师可以采用的自动化网络操作策略。我们将重点讨论如何建立成功的网络团队,使其能够在一个自动化驱动的环境中协作工作,从而提高效率。
本书还将展示网络团队需要建立新的技能,学习如 Ansible 这样的配置管理工具,以帮助他们实现这一目标。书中将展示这些工具带来的优势,使用它们提供的网络模块,并将帮助简化自动化过程,成为一个自我启动的指南。
我们将重点讨论需要克服的一些文化挑战,以便影响和实施网络功能的自动化流程,并说服网络团队充分利用目前供应商提供的可信网络 API。
本书将讨论公有云和私有云,如 AWS 和 OpenStack,以及它们如何为用户提供网络服务。还将讨论软件定义网络解决方案的出现,如 Juniper Contrail、VMWare NSX、CISCO ACI,并重点介绍诺基亚 Nuage VSP 解决方案,旨在将网络功能变成自服务商品。
本书还将重点讲解如何将持续集成和交付流程以及部署管道应用于网络变更的管理。还将展示如何将单元测试应用于自动化网络变更,以便将其与软件交付生命周期集成。
本书的详细章节概述如下:
第一章,云对网络的影响,将讨论公有云的 AWS 和私有云的 OpenStack 的出现如何改变了开发者对网络的需求。它将探讨 AWS 和 OpenStack 提供的一些即插即用的网络服务,并展示它们提供的部分网络功能。书中将举例说明这些云平台如何将网络变成像基础设施一样的商品。
第二章,软件定义网络的出现,将讨论软件定义网络如何出现。它将探讨方法论,并重点介绍 AWS 和 OpenStack 提供的开箱即用体验之上,软件定义网络所带来的一些扩展性优势和特性。它将展示市场领先的 SDN 解决方案之一 Nuage 如何应用这些概念和原理,并讨论市场上其他 SDN 解决方案。
第三章,将 DevOps 引入网络运营,将详细说明自上而下和自下而上的 DevOps 网络倡议的利弊。它将为读者提供一些成功的策略和通常失败的策略的思考。此章节将帮助首席技术官(CTO)、高级经理和工程师,尤其是那些试图在公司网络部门启动 DevOps 模型的人,概述他们可以使用的不同策略,以实现他们期望的文化变革。
第四章,使用 Ansible 配置网络设备,将概述使用配置管理工具安装和推送配置到网络设备的好处,并讨论目前可用的一些开源网络模块及其工作原理。它将举例说明可以采用的一些流程,以维持设备配置。
第五章,使用 Ansible 编排负载均衡器,将描述使用 Ansible 编排负载均衡器的好处,以及在无需停机或人工干预的情况下将新软件版本推送到服务中的方法。它将举例说明可以采用的一些流程,以便编排不可变和静态服务器,探讨不同的负载均衡技术。
第六章,使用 Ansible 编排 SDN 控制器,将概述使用 Ansible 编排 SDN 控制器的好处。它将概述软件定义网络的好处,以及为什么自动化 SDN 控制器暴露的网络功能至关重要。这包括动态设置 ACL 规则,允许网络工程师提供网络即服务(NaaS),使开发人员能够自助满足其网络需求。它将讨论部署策略,如蓝绿网络,并探索一些可以用来实现 NaaS 方法的流程。
第七章,使用持续集成构建进行网络配置,将讨论如何转向一种将网络配置存储在源代码管理系统中的模式,以便于审计、版本控制和回滚变更。
它将探讨使用如 Jenkins 和 Git 等工具设置网络配置 CI 构建的工作流。
第八章,测试网络变更,将概述在将网络变更应用到生产环境之前,使用测试环境进行测试的重要性。它将探讨一些可用的开源工具,并详细介绍一些可以应用的测试策略,确保网络变更在应用到生产环境之前经过充分测试。
第九章,使用持续交付流水线部署网络变更,将展示读者如何使用持续集成和持续交付流水线将网络变更交付到生产环境,并通过相关测试环境进行验证。它将给出一些可以采用的流程示例,说明如何将网络变更轻松地与基础设施和代码变更一起放入部署流水线。
第十章,容器对网络的影响,专用容器技术,如 Docker,以及容器编排引擎,如 Kubernetes 和 Swarm,越来越受到迁移到微服务架构的公司的青睐。因此,这改变了网络需求。本章将探讨容器的运作方式及其对网络的影响。
第十一章,网络安全,将探讨这种方法如何使安全工程师在审计网络时的工作变得更加轻松。它将分析软件定义网络中的可能攻击路径,以及如何将安全检查集成到 DevOps 模型中。
本书所需的内容
本书假设读者具备中级的网络知识、基础的 Linux 知识、基础的云计算技术知识以及广泛的 IT 知识。重点主要放在可以实施的特定流程工作流上,而非基础技术,因此这些思想和内容可以应用于任何组织,无论使用何种技术。
然而,尽管如此,在消化某些章节内容时,读者访问以下技术可能会有所帮助:
-
OpenStack
trystack.org/ -
Nuage VSP
nuagex.io/
本书适合的人群
本书的目标读者是希望自动化其工作中手动和重复部分的网络工程师,或者希望自动化所有网络功能的开发者和系统管理员。
本书还将为 CTO 或经理提供有价值的见解,帮助他们了解如何使其网络部门更加敏捷,并在其组织内部发起真正的文化变革。
本书还将帮助那些希望了解更多关于 DevOps、持续集成和持续交付的人,并了解它们如何应用于现实世界场景,以及一些可用的工具,以便于自动化。
约定
本书中有多种文本样式,用于区分不同类型的信息。以下是这些样式的几个例子及其含义的解释。
文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名将如下所示:“这些服务随后将绑定到lbvserver实体。”
任何命令行输入或输出都将如下所示:
ansible-playbook -I inevntories/openstack.py -l qa -e environment=qa -e current_build=9 playbooks/add_hosts_to_netscaler.yml
新术语和重要词汇以粗体显示。你在屏幕上看到的词语,例如在菜单或对话框中,出现在文本中如下:“点击 Google 上的搜索按钮。”
注意
警告或重要说明将以这样的框显示。
提示
提示和技巧如下所示。
读者反馈
我们始终欢迎读者的反馈。让我们知道你对本书的看法——你喜欢或不喜欢什么。读者反馈对我们非常重要,因为它帮助我们开发出你能从中获得最大收益的书籍。
如需发送一般反馈,请直接发送电子邮件至<feedback@packtpub.com>,并在邮件主题中注明书名。如果你对某个主题有专长,并有兴趣撰写或参与编写书籍,请参考我们的作者指南:www.packtpub.com/authors。
客户支持
既然你已经成为 Packt 书籍的自豪拥有者,我们提供了多项帮助你最大化利用购买的内容。
下载本书的彩色图片
我们还为你提供了一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图像。这些彩色图像将帮助你更好地理解输出的变化。你可以从www.packtpub.com/sites/default/files/downloads/DevOpsforNetworking_ColorImages.pdf下载该文件。
勘误
尽管我们已尽力确保内容的准确性,但错误仍然可能发生。如果您在我们的书籍中发现错误——可能是文本或代码中的错误——我们将非常感激您向我们报告。通过这样做,您不仅能为其他读者避免困惑,还能帮助我们改进后续版本的书籍。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表格链接,并填写勘误的详细信息。一旦您的勘误得到验证,我们将接受您的提交,并将勘误上传到我们的网站,或将其添加到该书标题下的现有勘误列表中。
若要查看之前提交的勘误,请访问www.packtpub.com/books/content/support并在搜索框中输入书名。所需信息将显示在勘误部分。
盗版
网络上的版权盗版问题在各类媒体中普遍存在。在 Packt,我们非常重视版权和许可证的保护。如果您在互联网上发现我们作品的任何非法复制品,请立即向我们提供该位置地址或网站名称,以便我们采取相应措施。
如果您发现涉嫌盗版的内容,请通过<copyright@packtpub.com>与我们联系,并提供盗版内容的链接。
我们感谢您在保护我们的作者和帮助我们为您提供有价值内容方面的帮助。
问题
如果您对本书的任何部分有问题,可以通过<questions@packtpub.com>与我们联系,我们将尽最大努力解决问题。
第一章:云计算对网络的影响
本章将探讨过去几年内私有数据中心中网络的变化以及如何演变。重点将放在公有云中的亚马逊网络服务(AWS)和私有云中的OpenStack的出现,以及它们如何改变开发人员使用网络的方式。它还将探讨 AWS 和 OpenStack 提供的现成网络服务,并展示它们提供的一些功能。最后,它将展示这些云平台如何将网络变成了类似基础设施的商品。
本章将涉及以下主题:
-
云计算方法概述
-
跨越树(Spanning Tree)网络与叶脊(Leaf-Spine)网络的区别
-
公有云引入后,网络发生的变化
-
亚马逊网络服务(AWS)网络方法
-
OpenStack 网络方法
云计算方法概述
云服务提供商市场目前已经饱和,存在多种不同的私有云、公有云和混合云解决方案,因此对于希望实施公有云、私有云或混合云解决方案的公司来说,选择不再是问题。
因此,选择云解决方案有时会是一个令人生畏的任务,因为市场上有众多不同的选择。
公有云与私有云之间的竞争仍处于起步阶段,尽管公有云被认为非常流行,但只有大约 25%的行业在使用公有云,解决方案如亚马逊网络服务、微软 Azure 和谷歌云占据了市场的大部分份额。然而,这仍意味着云市场有 75%的市场份额尚未被占领,因此云计算市场在未来几年可能会经历多次迭代。
那么,为什么许多公司最初考虑使用公有云,公有云与私有云和混合云又有什么不同呢?
公有云
公有云本质上是一组数据中心和基础设施,通过互联网公开提供给消费者。尽管名字中带有“云”,但它并非魔法或虚无缥缈的东西。亚马逊网络服务(Amazon Web Services)推出公有云的初衷是,在一年中忙碌的时期,他们可以将空闲的服务器租借给其他公司使用。
公有云资源可以通过图形用户界面(GUI)或通过一组 API 端点以编程方式访问。这使得公有云的最终用户能够创建基础设施和网络,以托管他们的应用程序。
企业使用公有云有多种原因,例如配置速度快,并且使用公有云资源的成本相对较低。一旦提供了信用卡信息,最终用户就可以自由创建自己的基础设施和网络,并在其上运行应用程序。
这种基础设施可以根据需要弹性地扩展和缩减,当然,所有这些都需要一定的费用,通过信用卡支付。
公有云已经变得非常流行,因为它解决了一些与影子 IT相关的历史性障碍。开发者不再受到官僚化和缓慢的内部 IT 流程强加的限制。因此,许多企业将公有云视为跳过这些障碍、以更灵活的方式工作的途径,使他们能够更频繁地将新产品推向市场。
当企业将其运营迁移到公有云时,他们是在迈出大胆的一步,停止托管自己的数据中心,而是使用一个公开的公有云服务提供商,如 Amazon Web Services、Microsoft Azure、IBM BlueMix、Rackspace 或 Google Cloud。
随后,依赖于公有云的正常运行时间和服务等级协议(SLA),这对一个成熟的企业来说可能是一个巨大的文化转变。
已经迁移到公有云的企业可能会发现,他们不再需要庞大的内部基础设施团队或网络团队,所有基础设施和网络都由第三方公有云提供,因此在某些情况下,这可能被视为放弃内部 IT。
公有云证明了对于许多初创公司来说是一个非常成功的模式,因为它提供的灵活性,初创公司可以迅速推出产品,利用软件定义的构件,而无需建立自己的数据中心,保持产品专注。
然而,运行所有企业基础设施在公有云中的拥有总成本(TCO)是一个备受争议的话题,如果没有正确的管理和维护,这可能是一个昂贵的模式。关于公有云与私有云 TCO 的辩论仍在继续,一些人认为公有云是一个很好的短期解决方案,但随着时间的推移,成本的增长意味着它可能不是与私有云相比的可行长期解决方案。
私有云
私有云实际上只是虚拟化解决方案(如 VMware、Hyper-V 和 Citrix Xen)最初带来的好处的延伸,这些虚拟化解决方案曾是虚拟化市场的基石。私有云的世界已经不再仅仅提供虚拟机,而是提供软件定义的网络和存储。
随着公有云的推出,如 Amazon Web Services,私有云解决方案已试图通过在当前基础设施上加一个软件定义层来提供类似的功能。这个基础设施可以像公有云一样通过图形界面(GUI)或通过 API 编程方式进行控制。
私有云解决方案,如 Apache CloudStack 和开源解决方案如 OpenStack,已被创建来弥合私有云和公有云之间的差距。
这使得厂商可以通过在现有硬件和网络之上叠加软件定义的构件,获得在自有数据中心内运行私有云操作的灵活性。
然而,私有云的主要好处在于这可以在公司自有数据中心的安全性范围内完成。并非所有企业都能出于合规性、常规性或性能原因使用公共云,因此一些企业在特定工作负载上仍然需要私有云。
混合云
混合云通常可以被视为多个云的结合体。这使得企业能够通过网络结构无缝地在多个云之间运行工作负载。企业可以根据成本或性能指标来选择工作负载的部署位置。
混合云通常可以由私有云和公共云组成。因此,举个例子,一个企业可能有一套需要在特定繁忙时期进行扩展的 Web 应用,这些应用更适合运行在公共云中,因此它们被部署在那里。然而,该企业还需要一个高度受监管、符合 PCI 标准的数据库,后者更适合部署在私有的本地云中。因此,真正的混合云为企业提供了这类选择和灵活性。
混合云的真正运作前提是根据不同的用例使用不同的云,其中每匹马(应用工作负载)需要跑特定的赛道(云)。因此,有时可以使用厂商提供的平台即服务(PaaS)层来跨多个云部署工作负载,或者使用不同的配置管理工具或容器编排技术来协调跨云的应用工作负载部署。
软件定义
公共云、私有云或混合云的选择实际上取决于企业,因此没有绝对的对错答案。随着公司文化和流程在未来几年内的发展,它们可能会使用混合云模型。
如果一个企业正在使用公共云、私有云或混合云,那么所有实现方式的共同主题就是它们都朝着软件定义的运营模式发展。
那么,软件定义到底是什么意思呢?简而言之,软件定义意味着在硬件上运行一个软件抽象层。这个软件抽象层允许对硬件进行图形化或编程化控制。因此,像基础设施、存储和网络这样的构件可以被软件定义,从而帮助简化操作、提高可管理性,尤其是在基础设施和网络扩展时。
在运行私有云时,需要对现有的数据中心进行修改,以使其准备好成为私有云;有时,这一点非常重要,因此私有数据中心需要进化以满足这些需求。
跨树和叶脊网络的区别
在考虑私有云时,传统上,公司的私有数据中心已实现基于生成树协议(STP)的 3 层二层网络,这对于现代的软件定义网络并不十分适用。因此,我们将深入了解什么是 STP 以及现代的叶脊网络架构。
生成树协议
STP 的实现为网络架构师提供了多种实现选项,但也为网络增加了一层复杂性。实施 STP 可以让网络架构师确信它能够防止网络中发生二层环路。
典型的 3 层基于 STP 的二层网络表示如下:

-
核心层为数据中心的其他部分提供路由服务,并包含核心交换机
-
聚合层提供与相邻接入层交换机的连接,并位于生成树核心的顶部
树的底部是接入层;这是裸金属(物理)或虚拟机连接到网络并使用不同 VLAN 进行分段的地方。
使用二层网络和 STP 意味着网络的接入层将使用遍布整个网络的 VLAN。这些 VLAN 位于接入层,虚拟机或裸金属服务器连接在此。通常,这些 VLAN 按应用类型分组,防火墙用于进一步隔离和保护它们。
传统网络通常被划分为以下几种组合:
-
前端:通常包含需要外部访问的 Web 服务器
-
业务逻辑:通常包含有状态服务
-
后端:通常包含数据库服务器
应用程序通过这些防火墙之间的隧道进行通信,使用特定的访问控制列表(ACL)规则,这些规则由网络团队提供服务,并由安全团队进行管理。
在二层网络中使用 STP 时,所有交换机都通过选举过程来确定根交换机,根交换机会授予具有最低桥接 ID 的交换机,桥接 ID 包括交换机的桥接优先级和 MAC 地址。
一旦选举完成,根交换机成为生成树的基础;生成树中的所有其他交换机被视为非根交换机,它们将计算到根交换机的最短路径,然后阻止任何冗余链路,从而形成一条清晰的路径。计算最短路径的过程称为网络收敛。(更多信息请参阅以下链接:etutorials.org/Networking/Lan+switching+fundamentals/Chapter+10.+Implementing+and+Tuning+Spanning+Tree/Spanning-Tree+Convergence/)
Network architects designing the layer 2 Spanning Tree network need to be careful about the placement of the root switch, as all network traffic will need to flow through it, so it should be selected with care and given an appropriate bridge priority as part of the network reference architecture design. If at any point, switches have been given the same bridge priority then the bridge with the lowest MAC address wins.
Network architects should also design the network for redundancy so that if a root switch fails, there is a nominated backup root switch with a priority of one value less than the nominated root switch, which will take over when a root switch fails. In the scenario, the root switch fails the election process will begin again and the network will converge, which can take some time.
The use of STP is not without its risks, if it does fail due to user configuration error, data center equipment failure or software failure on a switch or bad design, then the consequences to a network can be huge. The result can be that loops might form within the bridged network, which can result in a flood of broadcast, multicast or unknown-unicast storms that can potentially take down the entire network leading to long network outages. The complexity associated with network architects or engineers troubleshooting STP issues is important, so it is paramount that the network design is sound.
Leaf-Spine architecture
In recent years with the emergence of cloud computing, we have seen data centers move away from a STP in favor of a Leaf-Spine networking architecture. The Leaf-Spine architecture is shown in the following diagram:

In a Leaf-Spine architecture:
-
Spine switches are connected into a set of core switches
-
Spine switches are then connected with Leaf switches with each Leaf switch deployed at the top of rack, which means that any Leaf switch can connect to any Spine switch in one hop
Leaf-Spine architectures are promoted by companies such as Arista, Juniper, and Cisco. A Leaf-Spine architecture is built on layer 3 routing principle to optimize throughput and reduce latency.
Both Leaf and Spine switches communicate with each other via external Border Gate Protocol (eBGP) as the routing protocol for the IP fabric. eBGP establishes a Transmission Control Protocol (TCP) connection to each of its BGP peers before BGP updates can be exchanged between the switches. Leaf switches in the implementation will sit at top of rack and can be configured in Multichassis Link Aggregation (MLAG) mode using Network Interface Controller (NIC) bonding.
MLAG 最初与STP一起使用,使得两个或更多交换机绑定在一起,模拟成一个交换机,作为冗余使用,从而在 STP 中显示为一个交换机。在发生故障时,这提供了多个上行链路作为冗余,因为交换机是对等的,并且可以绕过禁用冗余路径的需求。Leaf 交换机之间通常会配置内部边界网关协议(iBGP)以实现容错。
在 Leaf-Spine 架构中,Spine 交换机不会与其他 Spine 交换机连接,Leaf 交换机也不会直接与其他 Leaf 交换机连接,除非使用 MLAG 网卡绑定在机架顶部进行绑定。Leaf-Spine 架构中的所有链接都被设置为无环转发。Leaf-Spine 架构通常配置为实现等成本多路径(ECMP),允许在交换机上配置所有路由,从而可以访问层 3 路由结构中的任何 Spine 交换机。
ECMP 意味着 Leaf 交换机的路由表已配置了指向每个 Spine 交换机的下一跳。在 ECMP 配置中,每个 Leaf 节点都有多条与每个 Spine 交换机等距离的路径,因此如果某个 Spine 或 Leaf 交换机故障,只要还有其他活跃路径连接到相邻的 Spine 交换机,就不会受到影响。ECMP 用于负载均衡流量,并支持通过多条路径路由流量。与 STP 相比,STP 会在网络收敛时关闭除一条路径外的所有路径。
通常,为了实现高性能,Leaf-Spine 架构在 Leaf 交换机上使用 10G 接入端口,映射到 40G 的 Spine 端口。当设备端口容量成为问题时,可以通过将新 Leaf 交换机连接到网络中的每个 Spine 交换机,并将新配置推送到每个交换机,来添加新的 Leaf 交换机。这意味着网络团队可以轻松地横向扩展网络,而无需管理或中断交换协议,也不会影响网络性能。
后续会展示 Leaf-Spine 架构中使用的协议图示,Spine 交换机通过 BGP 和 ECMP 与 Leaf 交换机连接,Leaf 交换机位于机架顶部,并使用 MLAG 和 iBGP 配置以实现冗余:

Leaf-Spine 架构的优势如下:
-
网络中的一致性延迟和吞吐量
-
所有机架的一致性性能
-
网络一旦配置完成,复杂性会大大降低
-
通过在机架顶部添加新的 Leaf 交换机,可以简单地扩展新机架。
-
所有机架之间的一致性性能、订阅和延迟
-
东西向流量性能优化(虚拟机到虚拟机的通信),以支持微服务应用
-
解决 VLAN 扩展问题,控制广播和故障域
Leaf-Spine 拓扑的一个缺点是它在数据中心中消耗的电缆数量。
OVSDB
现代交换机已经开始采用开源标准,这样它们就可以使用相同的可插拔框架。虚拟交换机的开源标准是Open vSwitch,它源于需要提出一个开放标准,使虚拟交换机能够将流量转发到同一物理主机和物理网络上的不同虚拟机。Open vSwitch 使用Open vSwitch 数据库(OVSDB),该数据库具有标准的可扩展架构。
Open vSwitch 最初在虚拟化管理程序层面部署,但现在也被用于容器技术,这些技术为网络提供了 Open vSwitch 实现。
以下超管程序目前将 Open vSwitch 作为其虚拟交换技术:
-
KVM
-
Xen
-
Hyper-V
Hyper-V 最近已开始支持使用 Cloudbase (cloudbase.it/) 创建的 Open vSwitch 实现,Cloudbase 在开源领域做出了出色的工作,这也证明了微软的商业模式在近年来如何发展并拥抱开源技术和标准。谁能想到呢?现在,微软的技术可以原生运行在 Linux 上。
Open vSwitch 交换OpenFlow数据,在虚拟交换机和物理交换机之间进行通信,并且可以通过编程扩展以适应供应商的需求。在下面的图示中,你可以看到 Open vSwitch 的架构。Open vSwitch 可以在使用 KVM、Xen 或 Hyper-V 虚拟化层的服务器上运行:

ovsdb-server 包含 OVSDB 架构,保存虚拟交换机的所有交换信息。ovs-vswitchd 守护进程与任何控制与管理集群通信,控制与管理集群可以是任何可以使用 OpenFlow 协议通信的 SDN 控制器。
控制器使用 OpenFlow 在虚拟交换机上安装流状态,OpenFlow 决定当虚拟交换机接收到数据包时应采取哪些操作。
当 Open vSwitch 接收到一个它从未见过并且没有匹配流条目的数据包时,它会将该数据包发送给控制器。控制器随后根据流规则决定如何处理此数据包,是阻止它还是转发它。在 Open vSwitch 上,可以配置服务质量(QoS)和其他统计信息。
Open vSwitch 用于在虚拟化管理程序的交换机级别配置安全规则并提供 ACL 规则。
Leaf-Spine 架构允许轻松构建覆盖网络,这意味着云环境和租户环境可以轻松地连接到第 3 层路由结构。硬件Vxlan 隧道端点(VTEPs)的 IP 地址与每个 Leaf 交换机或 MLAG 模式下的一对 Leaf 交换机关联,并通过虚拟可扩展局域网(VXLAN)与安装在虚拟化管理程序上的每个 Open vSwitch 连接到每个物理计算主机。
这使得由厂商提供的 SDN 控制器,例如思科(Cisco)、诺基亚(Nokia)和瞻博网络(Juniper),能够构建一个覆盖网络,通过 Open vSwitch 创建到物理虚拟化主机的 VXLAN 隧道。如果有新的计算节点扩展,新的 VXLAN 隧道会自动创建,之后 SDN 控制器可以在 Leaf 交换机上创建新的 VXLAN 隧道,因为它们与 Leaf 交换机的硬件VXLAN 隧道终端(VTEP)建立了对等连接。
现代交换机厂商,如 Arista、思科、Cumulus 等,使用 OVSDB,这使得 SDN 控制器能够在控制与管理集群层级进行集成。只要 SDN 控制器使用 OVSDB 和 OpenFlow 协议,它们就可以与交换机无缝集成,并且不受特定厂商的限制。这为最终用户在选择交换机厂商和 SDN 控制器时提供了更大的选择空间,因为它们使用相同的开放标准协议进行通信。
公有云引入后网络领域发生的变化
毋庸置疑,2006 年推出的 AWS 的出现彻底改变并塑造了网络格局。AWS 使公司能够在 AWS 平台上快速开发其产品。AWS 为最终用户创造了一套创新的服务,使他们能够管理基础设施、负载均衡,甚至数据库。这些服务引领了 DevOps 理念的实现,允许用户按需弹性地扩展和收缩基础设施。开发人员不再受到基础设施等待时间的限制,可以更高效地进行产品开发。AWS 丰富的技术功能集允许用户通过点击门户来创建基础设施,或者更多的高级用户通过配置管理工具(如Ansible、Chef、Puppet、Salt或平台即服务(PaaS)解决方案)来编程创建基础设施。
AWS 概述
2016 年,AWS 的虚拟私有云(VPC)保护一组 Amazon EC2 实例(虚拟机),这些实例可以通过 VPN 连接连接到任何现有网络。这个简单的构造改变了开发人员希望和期望的网络消费方式。
2016 年,我们生活在一个以消费为主导的社会,手机让我们能即时访问互联网、电影、游戏,或是各种不同的应用程序来满足我们的一切需求,换句话说,我们生活在即时满足的时代,因此不难理解 AWS 对最终用户的吸引力。
AWS 允许开发人员通过 AWS 门户的图形用户界面,通过几次点击,选择不同的规格(CPU、RAM 和磁盘)来在他们自己的个人网络中配置实例(虚拟机),或者通过简单的 API 调用或使用 AWS 提供的 SDK 进行脚本编写。
那么现在有一个合理的问题,为什么开发人员在 AWS 可用的情况下,仍然需要在本地数据中心等待长时间才能处理基础设施或网络工单?这个问题其实不难回答。解决方案肯定是将其迁移到 AWS,或者创建一个能够提供相同敏捷性的私有云解决方案。然而,答案并非总是如此简单,下面是反对使用 AWS 和公有云的一些理由:
-
不知道数据实际上存储在哪里以及在哪个数据中心
-
无法将敏感数据存储在远程地点
-
无法保证所需的性能
-
高昂的运行成本
所有这些问题对于一些受高度监管、需要符合 PCI 合规性或必须满足特定监管标准的企业来说,都是实际的障碍。这些问题可能会阻碍一些企业使用公有云,因此,像大多数解决方案一样,并不是“一个解决方案适用于所有”。
在私有数据中心,有一个文化问题,即团队被设置为在孤岛中工作,并没有为成功的敏捷业务模型做准备,因此,很多时候,使用 AWS、微软 Azure 或谷歌云只是对破碎的运营模型的一个快速修复。
工单系统,作为破碎的内部运营模型的典型代表,并不是一个与速度相匹配的概念。提交给相邻团队的 IT 工单可能需要几天或几周才能完成,因此在虚拟或物理服务器提供给开发人员之前,请求会被排队等待。此外,对于网络变更也同样如此,例如对 ACL 规则的简单修改,由于工单积压,可能需要很长时间才能实施。
开发人员需要能够随时扩展服务器或原型化新功能,因此,长时间等待 IT 工单处理会妨碍新产品推向市场或现有产品的 bug 修复。在内部 IT 中,信息技术基础架构库(ITIL)的某些从业者将每周处理的工单数量作为成功的主要指标,这表明他们完全忽视了开发人员的客户体验。一些操作需要转交给开发人员,这些操作传统上是由内部 IT 或影子 IT 负责的,但在业务层面需要对操作流程进行调整,才能推动这些变化。
简而言之,AWS 改变了开发人员的期望以及对基础设施和网络团队的期望。开发人员应该能够像在手机上修改应用程序一样迅速满足自己的需求,摆脱公司内部 IT 操作模型带来的拖延。
但是对于可以使用 AWS 的初创公司和企业来说,若不受监管要求的限制,它就省去了雇佣团队去安装服务器、配置网络设备和支付数据中心运营成本的需求。这意味着他们可以通过输入信用卡信息来启动可行的业务并在 AWS 上运行,就像在亚马逊或 eBay 上购买新书一样简单。
OpenStack 概述
对 AWS 的反应在竞争者中引起了恐慌,因为它打乱了云计算行业,并促使了Cloud Foundry和Pivotal等 PaaS 解决方案的出现,为混合云提供了一个抽象层。
当市场遭遇颠覆时,它会引发反应,由此催生了新的私有云的构思。2010 年,由 Rackspace 和 NASA 共同发起了一项名为 OpenStack 的开源云软件计划,因为 NASA 无法将其数据存储在公共云中。
OpenStack 项目旨在帮助组织提供基于标准硬件运行的云计算服务,并直接模仿 AWS 提供的模式。与 AWS 的主要区别在于,OpenStack 是一个开源项目,领先的供应商可以使用它将 AWS 类似的能力和敏捷性带到私有云中。
自 2010 年成立以来,OpenStack 已发展成为超过 500 家会员公司的一部分,这些公司通过 OpenStack 基金会积极推动社区发展,其中包括全球最大的 IT 供应商的铂金会员和黄金会员。
OpenStack 基金会的铂金会员包括:

OpenStack 是一个开源项目,这意味着它的源代码是公开的,其底层架构可以供分析使用,不像 AWS 那样像一个魔法盒子,外表光鲜亮丽,但我们并不了解它是如何在内部运作的。
OpenStack 主要用于在私有云中提供基础设施即服务(IaaS)功能,它使得普通的 x86 计算、集中存储和网络功能可以被终端用户自助服务,无论是通过 Horizon 仪表板,还是通过一套常用的 API。
许多公司现在正在实施 OpenStack 来建立自己的数据中心。与自己独立完成不同,一些公司正在使用不同供应商提供的社区上游项目的加固发行版。已经证明,使用供应商加固的 OpenStack 发行版,可以大大提高 OpenStack 实施成功的可能性。对于一些公司来说,实施 OpenStack 最初可能会觉得很复杂,因为它是一个公司可能尚不熟悉的新技术。使用知名供应商的专业服务支持时,OpenStack 实施不太可能失败,并且它可以为企业解决方案(如 AWS 或 Microsoft Azure)提供一个可行的替代方案。
如 Red Hat、HP、Suse、Canonical、Mirantis 等供应商为客户提供不同的 OpenStack 发行版,并附带不同的安装方法。尽管源代码和功能相同,这些 OpenStack 供应商的商业模式是将 OpenStack 加固以便企业使用,而他们对客户的差异化服务是专业服务。
有许多不同的 OpenStack 发行版可供客户选择,以下供应商提供 OpenStack 发行版:
-
Bright Computing
-
Canonical
-
HPE
-
IBM
-
Mirantis
-
Oracle OpenStack for Oracle Linux,或称 O3L
-
Oracle OpenStack for Oracle Solaris
-
Red Hat
-
SUSE
-
VMware 集成 OpenStack(VIO)
OpenStack 供应商将支持构建、持续维护、升级或客户所需的任何定制服务,所有这些都将反馈给社区。OpenStack 作为开源项目的优势在于,如果供应商为客户定制了 OpenStack,并创造了真正的差异化或竞争优势,他们不能将 OpenStack 分支或单独销售此功能。相反,他们必须将源代码贡献回上游开源 OpenStack 项目。
这意味着所有竞争供应商都在推动 OpenStack 的成功,并从彼此的创新工作中受益。然而,OpenStack 项目不仅仅是为了供应商,任何人都可以贡献代码和功能,推动项目向前发展。
OpenStack 维持一个发布周期,每六个月会创建一个上游发布版本,并由 OpenStack 基金会进行管理。需要注意的是,许多公共云服务,如 AT&T、RackSpace 和 GoDaddy,也基于 OpenStack,因此它不仅限于私有云,它无可否认地已成为 AWS 公有云的私有云替代方案,并且现在广泛用于 网络功能虚拟化(NFV)。
那么 AWS 和 OpenStack 在网络方面是如何工作的呢?AWS 和 OpenStack 都由一些必需的和可选的项目组成,所有这些项目集成在一起,形成其参考架构。必需的项目包括计算和网络,这是任何云解决方案的基础,而其他项目则是可选的附加组件,用于增强或扩展功能。这意味着最终用户可以根据自己的兴趣挑选项目,形成个人化的组合。
AWS 的网络方法
在讨论完 AWS 和 OpenStack 后,首先我们将探讨 AWS 的网络方法,然后再看看使用 OpenStack 的替代方法,并对这两种方法进行比较。在 AWS 中首次设置网络时,AWS 中的租户网络是通过 VPC 实例化的,VPC 在 2013 年之后废弃了 AWS 经典模式;但 VPC 到底是什么?
亚马逊 VPC
VPC 是新客户访问 AWS 时的默认设置。VPC 也可以通过允许 AWS 云扩展私有数据中心来连接到客户的网络(私有数据中心),以提高灵活性。将私有数据中心连接到 AWS VPC 的概念使用了 AWS 所称的客户网关和虚拟私有网关。简单来说,虚拟私有网关只是两个冗余的 VPN 隧道,它们从客户的私有网络实例化。
客户网关暴露来自客户站点的一组外部静态地址,这些地址通常是网络地址转换穿越(NAT-T),以隐藏源地址。UDP 端口4500应该在私有数据中心的外部防火墙中可访问。一个客户网关设备可以支持多个 VPC。

VPC 提供了一个隔离的视图,展示了 AWS 客户在 AWS 公有云中配置的所有内容。不同的用户账户可以使用 AWS 身份与访问管理(IAM) 服务设置到 VPC 上,并可以设置自定义权限。
以下是一个 VPC 示例,展示了与一个或多个安全组映射并连接到不同子网的实例(虚拟机),这些子网通过 VPC 路由器连接:

VPC通过将构件集成到软件中,大大简化了网络操作,并允许用户执行以下网络功能:
-
创建映射到子网的实例(虚拟机)
-
创建应用于实例的域名系统(DNS)条目
-
分配公共和私有 IP 地址
-
创建或关联子网
-
创建自定义路由
-
应用与关联的 ACL 规则的安全组
默认情况下,当一个实例(虚拟机)在 VPC 中实例化时,它将被放置在默认子网中,或者如果指定了自定义子网,则会放置在自定义子网中。
所有 VPC 在创建时都会有一个默认路由器,路由器可以添加额外的自定义路由,路由优先级也可以设置为将流量转发到特定的子网。
亚马逊 IP 地址分配
当一个实例在 AWS 中启动时,它将自动由动态主机配置协议(DHCP)分配一个必需的私有 IP 地址,并且还会分配一个公共 IP 和 DNS 记录,除非另有规定。私有 IP 地址用于 AWS 中的虚拟机之间的东西-东西流量路由,当虚拟机需要与同一子网上的相邻虚拟机进行通信时,而公共 IP 地址则通过互联网可用。
如果需要为实例分配一个持久的公共 IP 地址,AWS 提供了弹性 IP 地址功能,每个 VPC 账户最多可使用五个弹性 IP 地址,任何失败的实例的 IP 地址可以快速映射到另一个实例。需要注意的是,使用 AWS 时,公共 IP 地址的 DNS 生存时间(TTL)传播可能需要长达 24 小时。
在吞吐量方面,AWS 实例支持 最大传输单元 (MTU) 为 1,500,这可以传递给 AWS 中的实例,因此在考虑应用性能时需要考虑这一点。
亚马逊安全组
AWS 中的安全组是一种将许可访问控制列表(ACL)规则分组的方式,因此不允许显式拒绝。AWS 安全组充当实例的虚拟防火墙,可以与一个或多个实例的网络接口相关联。在 VPC 中,您可以将网络接口与最多五个安全组相关联,并为每个安全组添加最多 50 条规则,每个 VPC 的最大安全组数量为 500 个。AWS 账户中的 VPC 默认具有一个默认安全组,如果没有指定其他安全组,将自动应用此默认安全组。
默认安全组允许所有出站流量和来自同一 VPC 中其他使用默认安全组的实例的所有入站流量。默认安全组无法删除。自定义安全组在首次创建时不允许任何入站流量,但允许所有出站流量。
与安全组相关联的许可访问控制列表(ACL)规则控制入站流量,并可以通过 AWS 控制台(GUI)添加,如后文所示,或者可以通过 API 进行编程添加。与安全组相关联的入站 ACL 规则可以通过指定类型、协议、端口范围和源地址来添加。请参阅以下截图:

亚马逊区域和可用区
VPC 可以访问共享计算的不同区域和可用区,这决定了 AWS 实例(虚拟机)将部署在哪个数据中心。AWS 中的区域是完全隔离的地理区域,其中可用区是该特定区域中的独立位置,因此,可用区是区域的一个子集。
AWS 为用户提供了将资源放置在不同位置以实现冗余的能力,因为有时特定区域或可用区的健康状况可能会出现问题。因此,AWS 鼓励用户在部署生产工作负载时使用多个可用区。用户还可以选择在多个区域之间复制他们的实例和数据。
在每个独立的 AWS 区域内,存在子可用区。每个可用区通过低延迟链接与同区域的其他可用区相连。不同区域之间的所有通信都是通过公共互联网进行的,因此使用地理上距离较远的区域时会产生延迟。托管跨区域发送数据的应用时,还应考虑数据加密。
亚马逊弹性负载均衡
AWS 还允许在 VPC 中配置 Elastic Load Balancing (ELB) 作为附加服务。ELB 可以是内部的也可以是外部的。当 ELB 为外部时,它允许通过关联的 DNS 条目创建一个面向 Internet 的入口点,并在不同实例之间进行负载均衡。安全组会被分配给 ELB 以控制需要使用的访问端口。
下图展示了一个弹性负载均衡器,正在对 3 个实例进行负载均衡:

OpenStack 的网络架构
在考虑了 AWS 网络之后,我们将探索 OpenStack 的网络架构,并查看其服务是如何配置的。
OpenStack 部署在数据中心的多个控制节点上,这些控制节点包含所有 OpenStack 服务,可以安装在虚拟机、裸机(物理)服务器或容器上。在生产环境中部署时,OpenStack 控制节点应以高度可用和冗余的方式托管所有 OpenStack 服务。
不同的 OpenStack 供应商提供不同的安装程序来安装 OpenStack。一些来自最著名的 OpenStack 发行版的安装程序示例包括 RedHat Director(基于 OpenStack TripleO)、Mirantis Fuel、HP 的 HPE 安装程序(基于 Ansible)和 Canonical 的 Juju,它们都可以安装 OpenStack 控制节点,并用作 OpenStack 工作流管理工具,帮助扩展 OpenStack 云上的计算节点。
OpenStack 服务
安装在 OpenStack 控制节点上的核心 OpenStack 服务的详细说明如下:
-
Keystone 是 OpenStack 的身份服务,允许用户访问,发放令牌,并可以与 LDAP 或 Active Directory 集成。
-
Heat 是 OpenStack 基础设施的编排配置工具。
-
Glance 是 OpenStack 的镜像服务,用于存储虚拟机或裸机服务器的所有镜像模板。
-
Cinder 是 OpenStack 的块存储服务,允许集中式存储卷的配置,并可以将其附加到虚拟机或裸机服务器上,之后可以进行挂载。
-
Nova 是 OpenStack 的计算服务,用于配置虚拟机,并使用不同的调度算法来决定将虚拟机放置在哪些可用的计算节点上。
-
Horizon 是 OpenStack 的仪表板,用户可以通过它查看运行在租户网络中的虚拟机或裸机服务器的状态。
-
Rabbitmq 是 OpenStack 的消息队列系统。
-
Galera 是用于存储 OpenStack 数据的数据库,它存储所有 Nova(计算)和 Neutron(网络)数据库中的虚拟机、端口和子网信息。
-
Swift 是 OpenStack 的对象存储服务,可以作为一个冗余的存储后端,在多个服务器上存储对象的复制副本。Swift 与传统的块存储或文件存储不同;对象可以是任何非结构化数据。
-
Ironic 是 OpenStack 的裸金属配置服务。最初是 Nova 代码库的一个分支,它允许将镜像部署到裸金属服务器,并使用 IPMI 和 ILO 或 DRAC 接口来管理物理硬件。
-
Neutron 是 OpenStack 的网络服务,包含 ML2 和 L3 代理,并允许配置网络子网和路由器。
就 Neutron 网络服务而言,Neutron 架构在结构上与 AWS 非常相似。
注意
关于 OpenStack 服务的有用链接可以在以下位置找到:
docs.openstack.org/admin-guide/common/get-started-openstack-services.html
www.youtube.com/watch?v=N90ufYN0B6U
OpenStack 租户
一个项目,在 OpenStack 中通常被称为租户,提供一个团队在 OpenStack 云中所部署的所有资源的隔离视图。然后,可以通过 Keystone 身份服务为一个项目(租户)设置不同的用户帐户,Keystone 可以与 轻量目录访问协议(LDAP)或 Active Directory 集成,支持可定制的权限模型。
OpenStack Neutron
OpenStack Neutron 执行 OpenStack 中的所有网络功能。
以下网络功能由 OpenStack 云中的 Neutron 项目提供:
-
创建与网络映射的实例(虚拟机)
-
使用内建的 DHCP 服务分配 IP 地址
-
DNS 条目从命名服务器应用到实例
-
分配私有 IP 地址和浮动 IP 地址
-
创建或关联网络子网
-
创建路由器
-
应用安全组
OpenStack 被设置为其 模块化第二层(ML2)和 第三层(L3)代理,这些代理配置在 OpenStack 控制节点上。OpenStack 的 ML2 插件允许 OpenStack 与使用 Open vSwitch 或 Linux Bridge 的交换机厂商集成,并充当一个与交换机厂商无关的插件,因此厂商可以创建插件,使其交换机与 OpenStack 兼容。ML2 代理在 hypervisor 上运行,通过 远程过程调用(RPC)与计算主机服务器进行通信。
OpenStack 计算主机通常使用一个 hypervisor 部署,该 hypervisor 使用 Open vSwitch。大多数 OpenStack 厂商发行版在其参考架构中默认使用 KVM hypervisor,因此这一组件由所选的 OpenStack 安装程序在每个计算主机上进行部署和配置。
OpenStack 中的计算主机连接到 STP 三层模型的接入层,或者在现代网络中连接到 Leaf 交换机,VLAN 与每个单独的 OpenStack 计算主机相连接。租户网络随后用于提供租户之间的隔离,并使用 VXLAN 和 GRE 隧道连接第二层网络。
Open vSwitch 在 KVM hypervisor 上的内核空间运行,并通过使用从交换机推送流数据的 OpenStack 安全组管理防火墙规则。 neutron L3 代理允许 OpenStack 在租户网络之间进行路由,并使用在租户网络内部部署的 neutron 路由器来完成此操作,没有 neutron 路由器,网络将彼此隔离以及其他所有内容。
配置 OpenStack 网络
在 Project(租户)网络中使用 neutron 设置简单网络时,将配置两个不同的网络,即内部网络和外部网络。内部网络用于实例之间的东西流量。如下所示在适当的网络名称下使用地平线仪表板创建:

子网名称和子网范围随后在子网部分指定,如下截图所示:

最后,在网络上启用 DHCP,并选择性配置任何名为分配池(指定子网中可用地址范围的名称)以及任何名为DNS 名称服务器,如下所示:

还需要创建外部网络,以便从 OpenStack 外部访问内部网络,当由管理员用户创建外部网络时,需要选择设置外部网络复选框,如下一截图所示:

然后在 OpenStack 中创建路由器以路由数据包到网络,如下所示:

创建的路由器随后需要与网络关联;通过为私有网络上的路由器添加接口来实现,如下截图所示:

创建的外部网络随后需要设置为路由器的网关,如下截图所示:

这样就完成了网络设置;内部和外部网络的最终配置如下所示,显示了一个连接到内部和外部网络的路由器:

在 OpenStack 中,通过选择部署实例时选择私有网络 NIC 将实例配置到内部私有网络。 OpenStack 有一个公共 IP 地址池(浮动 IP)的分配约定,用于需要在 OpenStack 外部可路由的实例。
为设置一组浮动 IP 地址,OpenStack 管理员将使用来自外部网络的分配池来设置分配池,如下截图所示:

与 AWS 类似,OpenStack 使用安全组来设置实例之间的防火墙规则。与 AWS 不同,OpenStack 支持传入和传出的 ACL 规则,而 AWS 允许所有的出站通信,OpenStack 可以同时处理传入和传出的规则。根据需要创建定制的安全组,以便对 ACL 规则进行分组,如下所示:

然后可以针对安全组创建传入和规则。SSH 访问被配置为针对父安全组的 ACL 规则,该规则被推送到 Open VSwitch 内核空间中的每个虚拟化主机,如下图所示:

一旦项目(租户)拥有两个网络,一个内部网络和一个外部网络,并且配置了适当的安全组,实例就可以在私有网络上启动。
通过在 Horizon 中选择启动实例并设置以下参数来启动实例:
-
可用区
-
实例名称
-
规格(CPU、RAM 和磁盘空间)
-
镜像名称(基础操作系统)

然后选择私有网络作为实例的NIC,并在网络选项卡下进行配置:

这意味着当实例启动时,它将使用 OpenStack 的内部 DHCP 服务从分配的子网范围中选择一个可用的 IP 地址。
还应该选择一个安全组来管理实例的 ACL 规则;在这个例子中,选择了 testsg1 安全组,如下图所示:

一旦实例已配置完成,可以从外部网络关联一个浮动 IP 地址:

然后,从外部网络浮动 IP 地址池中选择一个浮动 IP 地址,并将其与实例关联:

浮动 IP 地址将 OpenStack 部署在内部公网 IP 地址上的实例通过 NAT 映射到外部网络的浮动 IP 地址,从而允许实例从 OpenStack 外部访问。
OpenStack 区域和可用区
与 AWS 一样,OpenStack 在实例创建时也使用区域和可用区。OpenStack 中的计算主机(虚拟化主机)可以被分配到不同的可用区。
在 OpenStack 中,可用区只是计算资源的虚拟划分。可用区可以进一步细分为主机聚合。需要注意的是,一个计算主机只能分配给一个可用区,但可以是同一可用区中多个主机聚合的一部分。
Nova 使用一个名为Nova 调度器规则的概念,规定了实例在资源配置时如何在计算主机上进行部署。Nova 调度器规则的一个简单例子是 AvailabilityZoneFilter 过滤器,意味着如果用户在配置时选择了一个可用性区,那么实例将只会被部署到该可用性区下的任意计算实例上。
另一个例子是 AggregateInstanceExtraSpecsFilter 过滤器,意味着如果一个自定义的 flavor(CPU、RAM 和磁盘)被标记为某个键值对,且一个主机聚合被标记为相同的键值对,那么如果用户使用该 flavor 部署,AggregateInstanceExtraSpecsFilter 过滤器将会把所有实例放置在该主机聚合下的计算主机上。
这些主机聚合可以分配给特定团队,这意味着团队可以选择性地决定与哪些应用共享其计算资源,同时也可以用来防止“噪声邻居”问题。OpenStack 提供了多种过滤器,允许以不同的顺序应用来决定实例调度。OpenStack 使得云操作员可以创建一个传统的云模型(有大量竞争资源的计算),也可以创建更为定制化的使用场景,在这些场景中需要为特定应用工作负载隔离计算资源。
以下示例显示了带有组的主机聚合,并展示了一个名为1-Host-Aggregate的主机聚合,归类在名为DC1的可用性区下,包含两台计算主机(hypervisors),它们可以分配给特定团队:

OpenStack 实例资源配置工作流。
当在 OpenStack 中配置实例(虚拟机)时,将执行以下高级步骤:
-
Nova 计算服务将使用从 glance 镜像服务中选择的镜像发出请求以创建新的实例(虚拟机)。
-
Nova 请求可能会先通过RabbitMQ排队,然后才会被处理(RabbitMQ 使得 OpenStack 能够处理多个同时的资源配置请求)。
-
一旦新实例的请求被处理,该请求将在 Nova Galera 数据库中写入一个新行。
-
Nova 将查看在 OpenStack 控制节点上定义的 Nova 调度器规则,并使用这些规则将实例部署到一个可用的计算节点(KVM hypervisor)。
-
如果找到一个符合 Nova 调度器规则的可用 hypervisor,则资源配置过程将开始。
-
Nova 将检查所选 hypervisor 上是否已经存在镜像。如果不存在,镜像将从 hypervisor 转移并从本地磁盘启动。
-
Nova 将发出一个 Neutron 请求,这将创建一个新的 VPort 并将其映射到 Neutron 网络。
-
然后,VPort 信息将被写入 Nova 和 Neutron 数据库中的 Galera,以将实例与网络关联。
-
Neutron 将发出 DHCP 请求,从它所关联的子网中分配一个私有 IP 地址给实例。
-
随后,将分配一个私有 IP 地址,并且实例将开始在私有网络上启动。
-
随后,将联系 neutron 元数据服务以检索云初始化信息,并在启动时从指定的命名服务器为实例分配 DNS 条目(如果已指定)。
-
一旦 cloud-init 运行完毕,实例将准备就绪。
-
然后,可以为实例分配浮动 IP,以通过网络地址转换(NAT)访问外部网络,使实例能够公开访问。
OpenStack LBaaS
像 AWS 一样,OpenStack 也提供负载均衡即服务(LBaaS)选项,允许将传入请求均匀地分配到指定的实例,使用虚拟 IP(VIP)。LBaaS 所支持的功能和特性取决于所使用的厂商插件。
OpenStack 中流行的 LBaaS 插件包括:
-
Citrix NetScaler
-
F5
-
HaProxy
-
Avi networks
这些负载均衡器向 OpenStack LBaaS 代理暴露不同程度的特性。利用 OpenStack 的 LBaaS 的主要驱动因素是,它允许用户将 LBaaS 作为负载均衡解决方案的中介,用户可以通过 OpenStack API 或通过 Horizon GUI 配置负载均衡器。
LBaaS 允许在 OpenStack 的租户网络中设置负载均衡。使用 LBaaS 意味着,如果用户出于某种原因希望使用新的负载均衡厂商而不是现有厂商,只要他们使用 OpenStack LBaaS,这一过程就变得更加简单。由于所有调用或管理都是通过 LBaaS 的 API 或 Horizon 进行的,因此不需要修改用于配置和管理负载均衡器的编排脚本,也不会绑定到每个厂商的自定义 API 中,负载均衡解决方案就成为了一种商品化的服务。
总结
在本章中,我们介绍了一些现代数据中心中使用的基本网络原理,特别关注了 AWS 和 OpenStack 云技术,这两者是当前最流行的解决方案之一。
阅读完本章后,你应该已经了解了 Leaf-Spine 与 Spanning Tree 网络架构的区别,理解了 AWS 网络架构,并对如何在 OpenStack 中配置私有网络和公共网络有了基本的了解。
在接下来的章节中,我们将基于这些基础网络结构,探讨如何使用配置管理工具以编程方式控制它们,并利用这些工具自动化网络功能。但首先,我们将关注一些软件定义网络控制器,这些控制器可用于进一步扩展 OpenStack 在私有云中相较于 neutron 的功能,以及它们带来的一些特性和优势,帮助简化网络运维管理。
注意
亚马逊内容的有用链接包括:
www.youtube.com/watch?v=VgzzHCukwpc
www.youtube.com/watch?v=jLVPqoV4YjU
OpenStack 内容的有用链接包括:
wiki.openstack.org/wiki/Main_Page
www.youtube.com/watch?v=Qz5gyDenqTI
www.youtube.com/watch?v=Li0Ed1VEziQ
第二章:软件定义网络的出现
本章将讨论开放协议的出现,这些协议帮助了软件定义网络(SDN)解决方案。它将重点介绍 Nuage VSP SDN 解决方案,这是诺基亚(前身为阿尔卡特朗讯)提供的 SDN 平台,允许用户创建虚拟覆盖网络。我们将了解 Nuage VSP 在扩展性方面相对于 AWS 和 OpenStack 的开箱体验所提供的一些优势和特点。它将阐述这些网络解决方案为什么成为著名复杂私有云网络的必需品,通过简化网络结构并通过提供一套可编程 API 和 SDK 来帮助网络自动化。
本章将详细讨论以下主题:
-
为什么 SDN 解决方案是必要的
-
Nuage SDN 解决方案的工作原理
-
OpenStack 与 Nuage VSP 平台的集成
-
Nuage VSP 软件定义对象模型
-
Nuage VSP 如何支持 Greenfield 和 Brownfield 项目
-
Nuage VSP 的多播支持
为什么 SDN 解决方案是必要的
SDN 解决方案是必要的,因为它们使企业能够简化网络操作,同时还可以实现网络功能的自动化。它与 DevOps 倡议和使网络操作更灵活的需求非常契合。
SDN 的副产品是,它使得网络功能变得像在虚拟机监控器上创建新虚拟机一样精确且可重复。
来自供应商的 SDN 解决方案由一个集中式控制器组成,该控制器被实现为网络的神经中枢。SDN 控制器在很大程度上依赖于Open vSwitch 数据库(OVSDB),这是一种可编程的开放标准模式,利用 OpenFlow 协议,直接与交换机集成,用于路由网络中的数据包,并将 ACL 策略应用于特定的虚拟机、物理服务器或容器。
只要交换机能够支持 OVSDB 和 OpenFlow,就可以与常见的 SDN 控制器集成。目前市场上有各种各样的 SDN 控制器:
-
CISCO ACI
-
诺基亚 Nuage VSP
www.nuagenetworks.net/products/virtualized-services-platform/ -
Juniper Contrail
-
VMWare NSX
-
Open Daylight
-
MidoNet Midokura
SDN 控制器为企业做以下事情:
-
为网络功能提供一个易于使用的解决方案,SDN 控制器将网络功能从硬件设备中抽象出来,而是暴露图形用户界面(GUI)和 API 端点,可以通过编程方式进行修改以控制网络操作。
-
SDN 控制器适用于 DevOps 模型,例如为开发人员提供自服务的网络操作,允许持续交付网络功能并增加团队间的协作。
-
提供更高的网络配置可见性,并通过易于理解的软件构造进行描述。
-
通过使用开放的网络标准提供更好的基础设施集成,这使得公司在选择集成的交换机厂商时有了更多选择。
-
允许在私有数据中心应用相同的策略,并跨私有和公有云进行应用。这使得将不同工作负载分配到不同云服务提供商的目标成为现实,并使得混合云的安全治理对于安全团队来说更加容易。
AWS 的出现无疑影响了网络厂商,使他们的解决方案更加注重软件方法,而非硬件,这反过来简化了网络操作,并使网络更容易扩展。
厂商现在已采用并实现开放协议,以允许集中管理网络功能,并使网络运营商能够使用 SDN 控制器管理整个网络。
企业正在使用软件定义网络(SDN)来最大化其网络性能,并创建可重复的网络操作工作流,就像虚拟化技术帮助基础设施团队自动化服务器配置和管理一样。
然而,根据我的个人经验,私有云中的软件定义网络被用于大规模运行 OpenStack。许多大型公司(如 Walmart、Ebay、PayPal、Go Daddy 以及我的公司 Paddy Power Betfair)不断采用 OpenStack 项目,这意味着公司正在转向 SDN 解决方案,以便达到必要的扩展目标并简化网络操作。
Nuage SDN 解决方案如何工作
市场领先的 SDN 解决方案之一是 Nuage SDN(VSP)平台,它是诺基亚的 SDN 解决方案(前身为阿尔卡特朗讯),因此我们将探索这种市场领先的 SDN 解决方案是如何工作的。
Nuage VSP 平台包含三个主要组件——VSD、VSC 和 VRS。
-
虚拟化服务目录(VSD):这是整个平台的策略引擎,提供图形用户界面,并暴露一个 restful API 供网络工程师使用和与网络功能进行交互。
-
虚拟化服务控制器(VSC):这是 Nuage 的 SDN 控制器,使用 OpenFlow 和 OVSDB 管理协议将交换和路由信息分发给虚拟机监控器、裸金属服务器或容器。
-
虚拟路由与交换(VRS):这是 Nuage 定制版本的 Open vSwitch,安装在计算节点(虚拟化主机)上。
![Nuage SDN 解决方案的工作原理]()
Nuage VSP 可以与 OpenStack、CloudStack 和 VMWare 私有云平台或公共云解决方案(如 AWS)集成。Nuage 创建了一个覆盖网络,能够在隔离的租户网络中保护虚拟机、裸金属服务器和容器,因此根据需要部署的工作负载类型,具有高度的灵活性。
虚拟机当然是在物理虚拟化主机上作为虚拟抽象进行部署的,容器可以在虚拟机或物理服务器上运行。容器用于通过 Linux 命名空间和控制组隔离特定的进程或资源,这些命名空间和控制组在操作系统级别划分资源,因此虚拟机和容器的网络要求非常不同。容器因其可移植性而被使用,可以在虚拟机或裸金属(物理)服务器上运行。另一个优点是它们被 Linux 操作系统封装,多个容器可以在虚拟机或物理服务器上运行。
Nuage 还支持通过虚拟化主机或物理机在基础网络中路由多播流量,并将其泛洪到租户网络中的特定虚拟或物理机器,从而实现租户网络之间的多播。这在云解决方案中一直是一个问题,但 Nuage 提供了针对这一问题的解决方案。
Nuage VSP 的 SDN 控制器(VSC)通过硬件 VTEP(由交换机在网络的接入或叶层暴露)与交换机通过 OVSDB 集成。VSC 被冗余部署,并通过多路径边界网关协议(MP-BGP)与彼此通信,并将 VXLAN 封装程序编程到交换机上,因为它们是硬件 VTEP 识别的。
VSD 组件在一个包含三台 VSD 服务器的活动集群中设置,这些服务器通过可行的负载均衡器解决方案进行负载均衡。负载均衡器提供一个虚拟 IP(VIP),通过轮询模式对三台 VSD 服务器进行负载均衡。
VSD 的 VIP 提供 Nuage VSP 平台的图形用户界面,并作为 API 入口点,允许通过 REST 调用程序化控制覆盖网络。对 Nuage VSD GUI 执行的任何操作都会触发一个 REST API 调用到 VSD,因此 GUI 和 REST API 执行的是相同的程序化调用,所有操作都通过 REST API 公开。
Nuage VSD 管理第二层和第三层的域、区域、子网和 ACL 策略。VSD 使用可扩展消息和存在协议(XMPP)将策略信息传递给 VSC,VSC 使用 OpenFlow 将流信息推送到计算主机(虚拟化主机)上的定制版 Open vSwitch(VRS),以为应用程序创建防火墙策略。
Nuage VSP 还允许裸金属服务器通过将 OpenFlow 数据推送到虚拟化服务网关(VSG)并将路由信息泄漏到覆盖网络中,连接到覆盖网络。
以下图表概述了 VSP 平台协议集成:

将 OpenStack 与 Nuage VSP 平台集成
私有数据中心网络可能非常复杂,因此使用标准的 OpenStack Neutron 来满足所有用例可能无法提供所需的所有功能。需要注意的是,Neutron 中的功能随着每个新的 OpenStack 版本的发布而快速成熟,因此未来 Neutron 可能会与专用的 SDN 控制器一样功能丰富。
Neutron 通过提供 REST API 扩展,便于与 SDN 控制器集成,因此如果需要提供非常丰富的网络功能,SDN 控制器可以轻松地用来扩展 Neutron 提供的基础网络功能。
SDN 解决方案的使用帮助 OpenStack 实现了大规模扩展,因为它将 OpenStack 的网络方面从集中式的 L3 代理移开,转而将请求发送到专用的 SDN 控制器,并实现分布式防火墙功能。
这意味着一个 OpenStack 云可能会横向扩展支持的计算实例数量,而无需担心与当前 Neutron 网络架构相关的瓶颈或扩展问题。
OpenStack 是最受欢迎的私有云解决方案之一,Nuage VSP 平台通过 Nuage 插件与 OpenStack 集成。Nuage 插件安装在每个高可用(HA)OpenStack 控制器上。
在控制器上,Neutron ML2 和 L3 代理都被关闭,取而代之的是 Nuage 插件。下图展示了 OpenStack Neutron 的 SDN 控制器框架架构,其中 SDN 控制器通过 REST API 调用与 OpenStack Neutron 进行通信:

VSD,作为 Nuage 策略引擎,通过设置网络分区与 OpenStack 集成,网络分区可用于将一个 Nuage VSP 映射到 OpenStack 云,并通过 REST API 调用与 Neutron 进行通信。
通过使用网络分区,多个 OpenStack 实例可以映射到单一的 Nuage VSP。网络分区是一种方式,用来告诉 Nuage VSP 平台将哪个 OpenStack 实例映射到其子网,并等待发出 VPort 命令,这些命令表示 OpenStack nova 计算服务已经配置了需要由 Nuage ACL 策略管理的虚拟机实例。
当 Nuage VSP 与 OpenStack 集成时,OpenStack 厂商安装程序需要原生支持 Nuage,或者安装程序需要稍作定制,以便在 OpenStack 控制器上安装 Nuage 插件。每个部署在 OpenStack 云中的计算节点(虚拟化主机)上也需要安装 Nuage 版本的 OpenvSwitch(VRS)。
Nuage 插件通过以下工作流程与 OpenStack 控制器和 KVM 计算进行集成:

当发出一个 neutron 命令到 OpenStack 时,Nuage 插件使用 REST API 调用与 Nuage VSD 通信,告知已创建新的网络或在该网络上创建了新的 VPort,这得益于 neutron 的 SDN 控制器可插拔 REST API 架构。
Nuage VSD 策略引擎然后与 VSC 通信,通过 XMPP 推送流数据。VSC(SDN 控制器)随后将流数据(OpenFlow)管理到 Nuage VRS(Open vSwitch),并且 Nuage VRS 使用预定义的防火墙策略保护 OpenStack 虚拟机或物理服务器。
防火墙策略可以是 OpenStack 安全组或 Nuage ACL 规则,具体取决于选择了 OpenStack 管理模式还是 Nuage VSD 管理模式。
Nuage 或 OpenStack 管理的网络
Nuage OpenStack 插件可以在两种操作模式下使用,以管理在 OpenStack 中配置的网络:
-
Nuage VSD 管理模式
-
OpenStack 管理模式
Nuage VSD 管理模式允许 Nuage 成为网络配置的主控;这使得 Nuage VSP 平台可以提供丰富的功能集来管理 OpenStack 环境中的网络。网络功能通过 VSD 直接配置,使用 Nuage REST API 通过 GUI 或直接 API 调用进行,并与 OpenStack 子网一对一映射。
另一种操作模式是 OpenStack 管理模式,该模式不需要在 VSD 上进行直接配置。所有命令通过 neutron 发出;但是,功能仅限于 OpenStack neutron 支持的命令。
所有在 Nuage 中创建的网络都在 OpenStack 中以一对一的映射方式复制,其中 Nuage VSD 在 VSD 管理模式下作为主控,而 OpenStack neutron 在 OpenStack 管理模式下作为配置主控。
在 OpenStack 管理模式下,所有的 ACL 规则由 OpenStack 安全组控制,而在 VSD 管理模式下,ACL 规则由 Nuage VSD 控制,并且安全组被禁用。
Nuage 通过设置网络分区与 OpenStack 集成。通过网络分区,单个 Nuage VSP 平台可以映射到多个 OpenStack 实例。网络分区是将 OpenStack 云映射到 Nuage 组织实体的方式。
使用 Nuage VSP 平台并命名组织为Company时,每当在组织下创建一个子网时,它会在创建时被分配一个唯一的nuage_subnet_uuid。为了将组织和 Nuage 子网映射到 OpenStack Neutron,发出以下命令:
neutron subnet-create "Subnet Application1" 10.102.144.0/24 --nuagenet nuage_subnet_uuid --net-partition "Company" --name "Subnet Application1"
一旦通过 Nuage VSP 平台和 OpenStack 建立了网络分区,防火墙策略会通过 Nuage VRS 在计算主机(虚拟化服务器)上得到保障。当在 Nuage 管理的子网中创建新实例时,会触发以下工作流:
Nuage 或 OpenStack 管理的网络
-
一个实例被添加到一个由 Nuage VSP 平台拥有的 OpenStack 网络和子网中。
-
一个占位符 VPort(虚拟机 ID,MAC 地址)由Nuage 插件在请求的第三层域内创建于VSD上。
-
Nova 服务在Hypervisor上创建虚拟机。这被VRS(虚拟机 ID,MAC 地址)检测到。
-
VRS查询VSC,然后VSC查询VSD以从占位符 VPort 中检索相关的网络信息。
-
VSD根据虚拟机 ID、MAC 地址与其创建的 VPort 进行匹配,并将虚拟机与正确的网络服务关联。
-
策略通过VSD通过VSC下载到VRS,使用 OpenFlow,所需的流将动态创建。
Nuage VSP 软件定义对象模型
由于 Nuage 在软件中创建了覆盖网络,它需要一个简单的对象模型来让网络管理员进行管理。Nuage VSP 软件定义对象模型提供了一个网络的图形化层级结构,使得覆盖结构能够被轻松查看和审计。
对象模型概览
-
组织:它管理所有的第三层域。对象模型概览
-
第三层域模板:在创建子第三层域之前,需要一个第三层域模板。第三层域模板用于管理所有子第三层域将传播的整体默认策略。如果在模板级别更新了第三层域模板,那么该更新会立即在其下已创建的所有第三层域上实施。对象模型概览
-
第三层域:这可以用来划分不同的环境,以便用户无法从第三层测试域下部署的子网跳跃到相邻的第三层生产域。对象模型概览
-
区域:一个区域在应用层面上划分防火墙策略,因此每个微服务应用可以有自己的区域,并且每个第三层域可以有各自的 Ingress 和 Egress 策略。对象模型概览
-
第三层子网:这是虚拟机或裸金属服务器被部署的地方。
在此示例中,我们看到子网应用 1和子网应用 2,如下所示:
对象模型概览
Nuage VSD 中的层级结构如下所示:
-
创建了名为 Company 的一个组织。
-
创建了名为 Test 和 Production 的两个层 3 域在公司之下。
-
Test 层 3 区域具有 Application1 和 Application2 的区域,Application1 和 Application2 区域下各有 1 个子网。
-
Production 层 3 区域具有 Application1 和 Application2 的区域,Application1 下只有 1 个子网。Application2 区域目前没有子网。
![对象模型概述]()
出于安全和合规目的,向安全审计人员展示 开发 和 生产 环境之间的分隔非常重要。通常情况下,开发 环境不会应用与生产环境一样严格的控制。生产应用可以使用最小权限的约定进行安全保护,以最大程度地减少访问并降低安全漏洞的可能性。
Nuage VSP 平台可以使用其层 3 域模板结构设置环境之间的分隔。域模板可以设置默认的 拒绝所有 策略在入口和出口级别。这是所有策略中优先级最高的策略,将明确拒绝所有数据包无论协议是入站还是出站连接,除非对该特定应用程序的策略明确允许。默认的 拒绝所有 是应用于应用程序的 ACL 规则列表中的底部策略。
域模板上的 出口安全策略 显示为以下的 底部策略:

出口安全策略 的内容显示为具有最高可能优先级,如下所示:

同样,入口的明确禁用被应用到域模板作为 底部策略:

虽然域模板上的 入口安全策略 明确禁用如下所示:

应用于域模板 Company L3 Domain Template 的默认入口和出口策略如下图所示,显示应用于所有子层 3 域,例如 Production 和 Test。
域模板 Company L3 Domain Template 被显示链接到子层 3 域 Production 和 Test,显示从域模板继承的出口策略:

同样,域模板 Company L3 Domain Template 被链接到子层 3 域 Production 和 Test,显示从域模板继承的入口策略:

需要注意的是,由于使用 OpenFlow 将策略推送到 VRS,Nuage 中的入口和出口的 ACL 规则遵循以下原则:
-
出口:这是一个数据包从 VRS 流向子网或区域。
-
入口:这是一个数据包从子网或区域流向 VRS。
举个例子,一个出口 ACL 规则将指定来自 VRS 的任何出口流量从端口 80 将被转发到 子网 Application1:

在这个示例中,一个入口 ACL 规则将指定任何入口流量可以从端口 80 离开 子网 Application1 并转发到 VRS:

如果应用程序所有者遵循这样的原则:他们的应用程序部署所在的第 3 层子网,总是作为源或目的出现在各自应用程序策略的 ACL 规则中,那么一个应用程序的 ACL 规则将只存在于该自包含的策略中。如果遵循这一概念,它使得每个应用程序的 ACL 规则能够封装在独立的策略中,在第 3 层域内,这反过来意味着,安全团队审计这些规则将变得更加简便。这也意味着应用程序遵循最小权限原则,仅开放必要的端口以便应用程序之间通信,并且对那些不符合规则的流量施加显式丢弃。
显示了两项策略,分别适用于两个应用程序,Application1 和 Application2,它们分别有入口和出口的独立策略,默认入口策略指定对任何未显式允许的流量进行显式丢弃。
入口安全策略如下所示:

出口安全策略如下所示:

Nuage VSP 平台的第 3 层域模板允许使用区域进行第二级分段,因此传统的网络被划分为三个区域,其中应用程序将部署在以下层级:
-
前端
-
业务逻辑
-
后台
随着微服务架构的崛起,每个应用程序的配置文件并不总是适应这三种广泛的配置文件。有时,应用程序既可以是前端应用程序,也可以是业务逻辑应用程序,那么这种微服务应用程序应该如何放置在传统的三层架构中呢?
与可以在区域级别应用的前端、业务逻辑和后台分隔策略不同,应用程序之间在每个子网间的有意义微分段成为可能。那么,这如何在 Nuage 中实现呢?
如果一个应用程序希望与另一个应用程序进行通信,它将拥有一个 ACL 规则,指定子网到区域的通信,以便在第 3 层域中相邻子网上的应用程序之间进行东西向通信。Nuage 通过允许应用程序进行子网到区域的通信来实现这一点。

为了允许这种通信,Application1可以具有 ACL 策略,允许Application2区域允许流量进入22端口的子网,实现东西向通信,因此无论使用多少不同的子网,Application1都将始终能够与位于Application2区域下的任何应用程序进行通信。

在安全策略方面,这使得开发和安全团队能够通过查看应用程序策略了解哪些应用程序正在相互通信以及它们使用的端口。

Nuage VSP 平台如何支持绿地和棕地项目
覆盖网络通常作为新的网络(绿地)站点进行设置,但单独的全新网络是没有用的,除非计划进行一次性的大规模迁移,将所有应用程序从遗留网络迁移到新网络。
如果选择阶段性应用程序迁移,仅将部分应用程序迁移到新网络中,那么新的覆盖网络将需要与遗留网络进行通信,并要求在棕地环境中运行。
棕地环境通常意味着应用程序会分阶段迁移到新平台,而不是一次性全部迁移,这有助于增加对新网络及其相关技术的信心。在将应用程序迁移到新平台时,通常需要在新网络中对迁移后的应用程序进行性能测试,之后才会将现有遗留网络的实时流量转移到迁移到新覆盖网络中的应用程序。
阶段性迁移的一个主要要求是要连接回遗留网络,以便处理托管在其中的应用程序依赖关系。这种连接是必要的,以便迁移后的应用程序能够有效运行。
Nuage VSP 平台使用其虚拟化服务网关(VSG)提供新覆盖网络和遗留网络之间的连接。两台 Nuage VSG 在虚拟底盘模式下冗余连接,并连接到位于遗留网络中路由器上的接口。VSG 根据从连接路由器接口的 VLAN 进入的数据包的目标 IP 执行路由表查找;然后它更新目标 MAC 地址为下一个跳跃地址,并将数据包转发到相应的 VXLAN 段。所有数据包都通过基础网络从遗留网络路由到 VSG。
这将新覆盖网络和遗留网络通过 VXLAN 终结于 VSG 进行连接。
以下是 Nuage VSD 中的一对活动 VSG:

Nuage VSG 通过将路由泄露到覆盖网络来允许与传统网络进行通信。每个 VSG 将使用 BGP 会话接收并通告 IPv4 路由,当使用叶脊拓扑结构并使用 iBGP 时,此 BGP 会话将在 VSG、VSC 和叶交换机之间建立。
VSG 必须将其本地系统 IP 通告给传统网络中的路由器,并且所有从本地网络接收到的路由将随后通过下层网络泄露到覆盖网络中的选定层 3 域。
在 Nuage VSP 平台中,泄露路由所需的设置是创建一个GRThubDomain层 3 域。在这个示例中,主机接口连接到传统网络中的前端、业务逻辑和后端路由器:

然后,Nuage VSP 平台允许将新创建的GRThubDomain与Production或Test层 3 域相关联,通过将泄露域与它们相关联。
在下面的示例中,GRThubDomain与Production层 3 域相关联。
在 Nuage GUI 中,泄露域通过以下图标显示,显示的是一个名为GRThubDomain的泄露域:

具有关联泄露域的生产域在 Nuage GUI 中显示如下:

泄露域的关联允许 Nuage VSP 平台通过下层网络将路由从传统网络泄露到新覆盖网络中,这意味着覆盖网络中的应用程序可以与传统网络中的应用程序进行通信,只要它们具有适当的 Ingress 和 Egress ACL 策略。
如前所述,Test和Production层 3 域有一个Deny All规则,用于 Ingress 和 Egress,这是公司 L3 域模板的一部分。因此,尽管所有路由都泄露到覆盖网络中,但除非明确说明,否则它们会被 VRS 丢弃。
Nuage VSP 平台具有应用 ACL 规则的能力,针对从外部传统网络泄露的路由,使用一种名为网络宏的概念。在 Nuage VSP 平台中,网络宏只是外部网络范围的一个花哨名称。
如果一个应用程序,Application3就是其中之一,位于传统网络中,并且它的路由已经通过GRThubDomain泄露域并泄露到Test层 3 域中,那么可以设置一个网络宏来描述所需的范围,并通过 Nuage ACL 规则隔离与之的连接。
在此实例中,网络范围10.58.11.0/24是Application3所在的范围,它是GRThubdomain中的前端范围的一部分,并已泄漏到覆盖网络中。Application3的网络宏在 Nuage 中显示如下:

然后,可以配置一个出站 ACL 策略,通过创建一个网络宏到子网的 ACL 规则,允许Application3的网络宏与Subnet Application1在端口8080上进行通信。
允许Application3 网络宏与Subnet Application1通过端口8080通信的出站安全策略如下所示:

创建后,ACL 列表将更新,显示新的网络宏ACL:

这使得 Nuage VSP 能够锁定策略,并且覆盖网络仅允许来自传统网络的特定流量,就像它在同一第 3 层域内的子网或区域之间控制 ACL 策略一样。网络宏也可以用于在多个云技术以及不同数据中心之间进行路由,因此它们是连接网络并控制网络之间策略的强大方式。
多个网络宏可以组合成一个网络宏组,这样可以通过一个 ACL 规则控制多个范围。然后,这些范围在 VRS 的 OpenFlow 级别上被展开。Nuage 在 3.x 版本中每个 VPort 的 ACL 规则数量限制为 100,因此目前每个实例(虚拟机)只能应用 100 个 ACL 规则,因此在组合网络宏时需要特别小心。在 Nuage 平台的 4.x 版本中,ACL 规则的数量已增加到 500 个。
以下是一个网络宏组的示例,然后可以在出站 ACL 规则中使用前端服务 网络宏组,而不是为Application3和Application4指定单独的策略:

允许前端服务 网络宏组与Subnet Application1之间通过端口8080连接的出站安全策略:

实施前端服务网络宏的 ACL 可以在此找到:

Nuage VSP 的多播支持
Nuage VSP 平台具有在以下 Nuage VSD 实体之间路由多播的能力:
-
第 2 层和第 3 层域
-
区域
-
子网
-
附加到虚拟机的 VPorts
多播可以路由到覆盖网络,这是 Nuage VSP 平台的独特功能。在 Nuage 中,通过在底层二层网络上配置专用 VLAN,并将其附加到计算节点上,将多播流量路由到覆盖网络。这使得底层网络上的计算节点(虚拟化管理程序)可以使用按机架分配的专用 VLAN 来发送和接收多播流量。
为了在底层网络上路由多播流量,Nuage VRS 将复制多播数据包,并以受控的方式将其泄漏到覆盖网络中。这样可以避免覆盖网络被不必要的多播流量洪泛,如果不加以控制,可能会对覆盖网络性能造成影响。这使得 Nuage 的多播设置具有高度的可扩展性,因为它只将多播流量引导到覆盖网络中需要的地方。
Nuage VSP 使用专用 VLAN 用于计算节点(虚拟化管理程序)的多播发送和接收。每个 VLAN 可以在每个虚拟化管理程序上进行配置,以便支持有多播需求的应用程序。
每个虚拟化管理程序都会为多播发送和接收分配一个 VLAN 和唯一的 IP 地址,这取决于虚拟化管理程序所在的机架,以便使用相应的交换机。
端口通道映射是 Nuage VSD 中用于将多播从底层网络泄露到覆盖网络的实体。如果多播需要在覆盖网络中从子网到子网路由,则需要端口通道映射。如果多播仅在同一子网中使用,则不需要端口通道映射,多播将在一个隔离的三层子网内工作,无需通过虚拟化管理程序上的 VLAN 路由流量。
在以下示例中,使用多播通道映射来为应用程序 2创建多播范围,该应用程序广播多播。这将通过虚拟化管理程序上的底层 VLAN,将多播从子网应用程序 2路由到 Nuage VRS,并将其洪泛到子网应用程序 1。
多播通道映射图标如下所示:

以下场景描述了一个应用程序在覆盖网络中将多播流量从一个三层子网路由到另一个子网的工作流程。
应用程序 1将部署在一个三层域下,属于自己的区域,位于一个/26 微子网中,并且在该子网下,两个虚拟机将连接到两个虚拟端口(VPort)。在 Nuage 中,虚拟机可以设置为多播的发送方或接收方,或者两者兼有:

在此实例中,应用程序 1是多播的发送方,想要将多播流发送到应用程序 2,该应用程序部署在一个三层域下,属于自己的区域,位于一个/26 微子网中,并且在该子网下,只有一台虚拟机将连接到一个虚拟端口。
所以需要在Application1上设置一个端口通道映射,并将其与每个Application1的 VPort 关联,这样 Nuage 就知道Application1是组播的发送方。
Application2将配置其 VPort 并设置端口通道映射,以便接收组播。
当Application1的两台虚拟机广播组播流量时,Nuage 现在知道将组播流量路由到与端口通道映射中指定的匹配组播范围相符的超管上,Application1部署于此。
Nuage 将使用发送者 VLAN 在超管二层域上传输组播。
每个超管的接收 IP 上的接收 VLAN 将会接收到组播的传输。
如果在超管上的任何虚拟机上指定了端口通道映射,并且匹配了已配置的Multicast Ranges,如Application2所做的那样,那么 Nuage VRS 将复制组播数据包,并将它们泄漏到覆盖网络中,传递给Application2。
这就是 Nuage 如何使用基础网络和发送者与接收者 VLAN 将组播流量泄漏到覆盖网络的方式。
总结
本章中,我们介绍了 Nuage VSP SDN 解决方案提供的一些高级网络功能,并简要介绍了市场上其他可用的 SDN 解决方案。阅读本章后,你应该已经熟悉了 Nuage SDN 控制器,并理解了 SDN 控制器能为 OpenStack 和私有云带来的丰富功能。
鉴于程序化 SDN 控制器、AWS 和 OpenStack 解决方案带来的优势,我们现在将转向关注在组织内实现这些令人振奋的技术所需的文化变革。仅仅实施新技术而不改变操作模型是不够的,人员和流程是成功 DevOps 模型的关键。
网络工程师的角色正在经历多年来最大的变革,因此企业不能仅仅实现新技术并期望更快的交付,而不处理人员和文化问题。首席技术官有责任通过实施包括网络功能的 DevOps 转型,为其网络团队的成功奠定基础,同时网络团队也需要学习新技能,如编程,以通过草根倡议推动自动化。
注意
关于 Nuage Networks 实际应用案例的有用链接如下:
www.youtube.com/watch?v=_ZfFbhmiNYo
www.youtube.com/watch?v=aKa2idHhk94
www.youtube.com/watch?v=OjXII11hYwc
第三章:将 DevOps 引入网络运维
本章将重点转向人员和流程,而不是技术。DevOps 的初衷是打破开发与运维团队之间的壁垒,并改变公司运营模式。它将重点介绍解锁 IT 员工、帮助他们以更高效的方式工作的方法,但这些思维方式如今已被扩展到质量保证测试、安全性,甚至网络运维。本章将主要关注网络工程师的角色演变,这一角色与之前的运维工程师一样正在发生变化,网络工程师需要学习新技能,以便在行业朝着完全程序化控制的运营模型发展时,依然能保持现有的价值。
本章将探讨两种不同的角色:CTO / 高级经理与工程师,详细讨论可以用来促进所需文化变革的一些举措,这些变革对于实现整个组织的 DevOps 转型至关重要,或者至少帮助某个单独的部门通过自动化所有工作来改善其内部流程。
本章将涵盖以下主题:
-
启动行为变革
-
自上而下的 DevOps 倡议针对网络团队
-
针对网络团队的自下而上的 DevOps 倡议
启动行为变革
网络的 OSI 模型包含七个层级,但广泛建议在 OSI 模型中增加一个名为“用户层”的第八层,负责管理终端用户如何与网络进行集成和互动。显然,人与技术相比,更难以掌握和管理,因此不存在一刀切的解决方案来应对大量的人员问题。OSI 的七层结构如下图所示:

启动文化变革和行为变革是组织将面临的最困难任务,而且这不是一蹴而就的。要改变行为,首先必须有明显的商业利益。重要的是要先概述这些文化变革将为组织带来的好处,这将使经理或变革推动者能够为实施所需的变革提供商业正当性。
文化变革以及应对人员和流程的挑战是众所周知的困难,因此,将工具与人员和流程分开,专注于人员和流程的管理是任何 DevOps 项目或倡议成功的关键。文化变革需要经过精心规划,并成为公司的一项倡议。在最近一项由 Gartner 进行的研究中,数据显示,选择错误的工具并不是云项目失败的主要原因,失败的主要原因是未能改变操作模型:

实施 DevOps 的原因
在实施 DevOps 时,常常会流传一些误解,比如 DevOps 只适用于初创公司,它对某个特定团队没有任何价值,或者它只是一个流行词和潮流。
如果正确实施,DevOps 项目的可量化收益是不可否认的。这些收益包括对以下方面的改进:
-
变更的速度
-
平均解决时间
-
提升的正常运行时间
-
部署次数的增加
-
团队间的跨技能培训
-
消除单一故障点的风险
IT 行业中的任何团队都会从这些改进中受益,因此团队实际上不能不采用 DevOps,因为这无疑会改善他们的业务功能。
通过实施 DevOps 项目,能够促进可重复性、衡量和自动化。实施自动化自然提高了变更的速度,增加了团队在任何给定一天内可以进行的部署次数,并改善了产品上市时间。部署过程的自动化使得团队能够快速将修复推送到生产环境,同时也让组织能够将新产品和新功能迅速推向市场。
自动化的副产品是,基础设施问题的平均解决时间也会变得更快。如果基础设施或网络变更是自动化的,那么它们的应用效率要远高于人工执行。人工变更取决于实施变更的工程师的速度,而不是能够更精确地衡量的自动化脚本。
实施 DevOps 还意味着需要有效地进行衡量和监控,因此在所有基础设施和网络的各个部分拥有有效的监控至关重要,因为这意味着根本原因分析的速度得以提升。有效的监控有助于促进平均解决时间的缩短,因此当生产问题发生时,可以比让大量工程师登录控制台和服务器进行调试问题更快地找到问题的根源。
相反,一个良好实施的监控系统可以提供快速的通知,定位问题的根源,并消除因初步根本原因导致的任何警报,使问题能够高效地得到解决。
然后,监控会交给可重复的自动化流程,这些自动化流程可以将本地修复推送到生产环境。这个过程提供了一个高度精确的反馈循环,流程会日益改进。如果遗漏了警报,它们理想情况下会随着时间推移被纳入监控系统,成为事件事后分析的一部分。
有效的监控和自动化会导致更快的平均解决时间,从而带来更满意的客户,并改善产品的正常运行时间。利用自动化和有效的监控也意味着团队的所有成员都有机会看到流程如何运作以及修复和新功能是如何推送出去的。
这将减少对关键个人的依赖,消除巴士因子问题——即某个关键工程师需要做团队中的大部分工作,因为他是最熟练的个体,且所有系统知识都掌握在他脑中。
使用 DevOps 模型意味着非常高技能的工程师可以将他们的才华用来帮助跨技能其他团队成员,并创建有效的监控系统,帮助任何团队成员执行他们通常手动完成的根本原因分析。这将深厚的知识融入监控系统中,因此,监控系统,而非工程师本身,将成为发生问题时的首选参考点,或者理想情况下,监控系统将成为警报源,及时提醒事件,避免客户问题。为了提高跨技能,工程师理应帮助编写自动化流程,这样他们就不是唯一能够完成特定任务的团队成员。
实施 DevOps 以改善网络的原因
那么,DevOps 的一些好处如何适用于传统的网络团队呢?今天独立的网络团队常见的抱怨包括以下几点:
-
反应性工作
-
慢,通常通过工单系统进行协作
-
使用管理员终端执行手动操作
-
缺乏前期测试
-
手动错误导致网络中断
-
一直处于应急模式
-
日常流程中缺乏自动化
网络团队像之前的基础设施团队一样,通常习惯于在独立的团队中工作,通过工单系统或使用不够理想的流程与大组织中的其他团队互动。这种工作方式既不流畅也不优化,正是这种情况促使了 DevOps 倡议的诞生,旨在打破开发和运维团队之间的壁垒,但其范围已扩大。
网络团队似乎最初并未被纳入 DevOps 运动,但软件交付只能以最慢的组件速度运作。最慢的组件最终会成为整个交付过程的瓶颈或障碍。这个最慢的组件通常会成为一个独立团队中的明星工程师,因为他无法手动处理足够的工单来跟上需求,从而成为“巴士因子”(bus factor)。如果该工程师休假或生病,工作就会被阻塞,整个公司对他依赖过大,无法高效运作。
如果一个团队的运作方式与其他部门不同,那么所有其他部门的工作效率都会受到影响,因为该部门的工作不够灵活。简单来说,大多数公司中网络团队存在的原因是为开发团队提供服务。开发团队需要部署网络,这样他们才能测试产品更改,并将产品部署到生产环境中,一旦部署到生产环境,业务就能开始通过这些产品盈利。
网络对访问控制列表(ACL)策略、负载均衡规则以及为新应用程序提供新子网的变更,若需要数天、数月甚至数周才能完成,就不能再被视为成功。网络直接影响变更速度、平均修复时间、正常运行时间以及部署次数,这些都是成功 DevOps 倡议的四个关键绩效指标。因此,企业需要将网络纳入 DevOps 模型,否则这些可量化的收益将受到制约。
考虑到 AWS、Microsoft Azure、OpenStack 和软件定义网络(SDN)能够快速地在私有和公有云中配置网络功能,现在网络团队不再适应他们的运营流程并学习新技能已经不可接受。但有一个前提是,网络的演变非常迅速,他们需要支持和时间来完成这一过程。
如果实施了云解决方案,但运营模型没有改变,那么组织将无法感受到任何真正的可量化收益。云项目传统上并不是因为技术失败,而是因为现有的运营模型阻碍了它们的成功。如果公司不改变其运营模型,并允许最终用户使用 API 自助服务其请求,那么构建一个全新的 OpenStack 私有云——具备用于管理计算、网络和存储的开放可扩展 API——将毫无意义。
如果网络工程师仍在使用图形界面(GUI)进行指点、点击和复制粘贴,那么这并不能带来真正的业务价值,因为复制粘贴最慢的网络工程师就是瓶颈。公司完全可以继续使用现有的技术和流程,因为采用手动流程的私有云解决方案并不会加速市场发布的时间,也不会缩短从失败中恢复的时间。
然而,云不应成为贬低内部网络员工的借口,因为公司中现有的运营模型通常不是由当前的员工设计或设置的,而是继承下来的。迁移到公有云并不能解决公司网络团队的运营敏捷性问题,它只是一种权宜之计,掩盖了更深层次的文化挑战。
然而,更智能的工作方式结合自动化、测量和监控的使用,能帮助网络团队完善内部流程,并促进他们与开发和运营人员的日常协作。文化变革可以通过两种方式启动:一种是来自工程师的自下而上的草根倡议,另一种是来自高层管理的自上而下倡议。
面向网络团队的自上而下 DevOps 倡议
自上而下的 DevOps 倡议是指 CTO、总监或高级经理需要从公司获得支持,以对操作模型进行改变。这些改变是必要的,因为现有的操作模型被认为不够理想,并且无法像竞争对手一样快速交付软件,从而导致新产品或重要修复的推迟,影响市场的及时交付。
当从自上而下的管理层进行 DevOps 转型时,如果要对操作模型进行重大更改,必须先与相关团队进行一些基础工作,因为这种大规模的变动往往会导致现场员工的不安或压力。
在实施操作变革时,高层管理人员需要获得现场员工的支持,因为他们每天将会在这一模型下工作。让团队获得支持是非常重要的一环,否则,公司将面临员工不满的局面,这最终意味着最优秀的员工将离开。
在实施新的操作流程时,让高层管理人员与员工积极互动,并从一开始就透明处理任何担忧是非常重要的,而不是去参加一个外部管理会议,然后带着一个强制性的计划回来,这种情况太常见了。
管理层应对团队进行调查,以了解他们每天是如何运作的,喜欢当前流程的哪些方面,以及他们在哪些方面感到困惑。改变操作模型的最大障碍是误解现有的操作模型。所有的倡议理想情况下应该是由团队主导,而不是强加的。所以让我们重点关注一些可以帮助的具体自上而下的倡议。
分析成功的团队
一种方法是管理层查看组织内其他团队的运作情况,特别是那些流程运作良好且采用增量敏捷方式交付的团队。如果组织内没有团队以这种方式运作,可以联系其他公司。
询问是否可以参观其他公司的一天运营方式。大多数公司会很高兴将成功的项目作为案例在会议或聚会中展示,因为他们喜欢展示自己的成就,所以寻找那些已经克服了类似文化挑战的公司应该不难。参加一些 DevOps 会议并看看谁在发言,接触这些发言人,他们无疑会乐意提供帮助。
管理团队应首先与高效能团队安排一次会议,并进行问答环节,重点关注以下几点,如果是外部供应商,那么一次简单的介绍电话也可以。
在初次会议中需要提出的一些重要问题如下:
-
哪些流程通常运作得很好?
-
他们每天实际上使用什么工具?
-
工作是如何分配的?
-
他们如何跟踪工作进展?
-
团队结构是什么?
-
其他团队是如何向该团队提出请求的?
-
工作是如何优先排序的?
-
他们如何处理中断?
-
会议是如何组织的?
不要重新发明轮子,如果组织中的某个团队已经有一个经过验证的模板并且运行良好,那么这个团队在帮助推动网络团队的文化变革中也可能是无价的。如果将焦点放在外部团队作为传播者上,会稍微更具挑战性,因为这会带来一些借口,比如说他们公司因为 x、y、z 的原因,所以更容易做到。
当组织中的本地团队作为传播者时,一个好的策略是将一名网络工程师嵌入该团队几周,观察并反馈其他团队如何运作并记录他们的发现。这是至关重要的,确保网络工程师理解现场的流程。
灵活性同样重要,因为只有部分成功团队的流程可能适用于网络团队,因此不要期望两个团队的工作方式完全相同。团队的整体和个人的差异意味着每个团队都是不同的,因此应专注于目标,而不是严格的流程执行。如果团队通过稍微不同的方式达成相同的结果,只要工作可以追踪且对管理层可见,并且能够轻松报告,就不应该成为问题。
确保优先考虑节奏,选择特定的变革推动者,以确保团队对新流程感到舒适,因此,赋予网络团队的变革推动者选择工作方式的权力,通过与团队互动创建新流程,同时让他们负责最终的工具选择。然而,在选择任何工具之前,重要的是从流程开始,并就新的操作模型达成一致,以防止工具推动流程,这在 IT 领域是一个常见错误。
绘制活动图
一个好的建议是使用活动图作为视觉辅助工具,帮助理解团队互动如何运作以及如何改进。
这里展示了一个典型的开发活动图,包含手动交接给质量保证团队的流程:

使用活动图作为视觉辅助工具非常重要,因为它能够突出不理想的业务流程。在这个例子中,我们看到一个开发团队的活动图。这个流程是不理想的,因为它在本地测试和同行评审阶段没有包括质量保证团队。相反,它有一个正式的 QA 交接阶段,这个阶段出现在开发周期的后期,这种做法很不理想,因为它促成了开发和 QA 的孤岛效应,这是 DevOps 反模式。
更好的方法是让质量保证工程师负责创建测试任务和创建自动化测试,而开发团队负责编码任务。这将允许开发同行评审流程在开发生命周期的早期由质量保证工程师审查和测试开发人员的代码,并确保每段编写的代码在提交之前具有适当的测试覆盖率。
流程中的另一个缺点是,它未考虑到质量保证团队或客户在生产中发现的软件缺陷,因此将这些工作流引入活动图中也很有用,以展示所有潜在的反馈循环。
如果在整体活动图中漏掉了反馈循环,那么可能会导致流程流失,因此捕捉在映射工具前可以促进流程的所有排列组合是非常重要的。
每个团队都应考虑缩短互动时间的方法,以帮助减少解决时间并提高工作能够流经整体流程的速度。
管理层应该在他们的日程中安排一些时间与开发、基础设施、网络和测试团队会面,并绘制出他们认为各自团队流程的图示。保持高层次,这应该是一个简单的活动泳道,利用从接受工作开始到团队进行工作交付的过程。
每个团队绘制出初始方法后,应专注于优化它,并去除他们不喜欢的流程部分,并讨论团队如何改进流程的方式。可能需要多次迭代才能有效绘制出这一过程,所以不要急于此过程,应该将其视为每个团队的学习经验。
最终的活动图通常会以优化的方式结合管理和技术功能,以展示整体流程。在此阶段不要使用业务流程管理(BPM)软件,简单的白板足以保持简单和非正式。
在活动图中使用两层是一个良好的做法,因此第一层可以是一个简单的方框,仅写着同行评审,然后引用一个嵌套的活动图,概述团队的同行评审过程。两者都需要精细化,但业务流程的嵌套层应由各个团队决定,因为这些是特定于他们需求的,所以在这个层面给团队所需的灵活性非常重要。
将这两个层次分开是很重要的;否则,活动图的整体顶层将过于复杂,无法从中提取任何真正的价值,因此尽量减少顶层的复杂性,因为这将需要与其他团队的流程集成。这个活动不需要包含团队特定的细节,比如内部团队的同行评审流程如何操作,因为这将始终是该团队主观的;这应该包括在内,但将是一个不会被分享的嵌套层次活动。
另一个团队应该能够查看团队的顶层活动图并理解流程而无需解释。有时首先绘制高效团队的顶层活动图可以很有用,以展示一个集成的、连贯的业务流程应该是什么样子。
这将帮助那些在这些概念上有些困难的团队,并允许他们使用那个团队的活动图作为指南。这可以作为参考点,并展示这些团队如何解决他们的跨团队互动问题,并促进一个或多个团队在没有摩擦的情况下互动。这个练习的主要目的是连接业务流程,使它们不再在团队之间孤立,以便为集成的计划和执行尽可能地整合工作。
一旦每个团队完成了他们的个人活动图并将其优化到团队希望的方式,流程的第二阶段可以开始。这涉及将每个团队的顶层活动图分层,以创建一个集成的流程。
团队应该将这个分层练习作为借口来讨论次优的流程以及整个业务流程应该如何从头到尾看起来。利用这个会议来消除团队之间的感知瓶颈,完全忽略现有工具以及当前工具的约束,整个练习应该集中在流程而非工具上。
一个受工具约束的次优流程流程的良好示例是顶层活动图上的一个阶段,表示使用工单系统提出工单。应将其细分为以人为中心的工作,请求变更的人实际需要什么?
开发者的日常工作包括编写代码和构建优秀的功能和产品,所以如果一个新功能需要网络变更,那么网络应被视为该功能变更的一部分。因此,网络变更所需的时间需要作为该功能的规划和估算的一部分考虑,而不是作为一个单独的请求,当其作为事后想法被动执行时,会阻碍变更的速度。
当参与度高时,这通常是一次非常成功的练习,最好利用每个团队中的高级工程师和经理参与组合活动图层练习,更初级的工程师参与各自团队特定活动图练习。
更改网络团队的运营模式
活动图工作结束后,网络团队的操作模型应该理想地与整个业务完全融合。一旦新的操作模型与所有团队达成一致,就可以开始实施它。
需要注意的是,因为现场团队创建了操作模型并完成了协同活动图,它应该由所有相关方签署作为新的业务流程。因此,这消除了管理层强制模型的问题,因为使用该模型的人们参与了其创建。操作模型可以随着时间的推移进行迭代和改进,但互动不应该发生大的变化,尽管可能会增加最初遗漏的新互动点。然后,可以存储并更新业务流程的主副本,这样新加入公司的员工就知道如何与其他团队进行互动。
从短期来看,新的方法可能会使开发估算变慢,因为网络功能尚未实现自动化,因此当开发人员的功能需要网络更改时,估算会变得更高。
这通常只是对现实的更真实反映,因为最初的估算没有考虑到网络更改,这些更改后来成为了阻塞因素,尽管它们是票据,但一旦报告出来,就可以随着时间的推移进行优化和改进。
一旦整体活动图已合并并与所有团队达成一致,重要的是要记住,如果流程得到了妥善优化,图表上不应该有一大堆高层次的操作。如果互动过于冗长,任何变更都会需要几个小时来遍历活动图上的每一个步骤。
后面提到的活动图展示了一个协同的业务流程,其中工作从单一的路线图定义,产生适用于所有团队的用户故事。新的用户故事,作为工作单元,将由跨职能团队(包括开发人员、基础设施、质量保证和网络工程师)进行估算。每个团队将审查用户故事,确定完成功能所需的跨职能任务。
用户故事随即成为冲刺的一部分,跨职能团队一起工作,确保它在检查之前具备运行所需的一切。经过同行评审后,功能或更改将交给自动化流程,将代码、基础设施和网络更改交付到生产环境。
已检查的功能会经过单元测试、质量保证、集成和性能测试质量关卡,这些关卡将包括质量保证团队在检查前编写的任何新测试。一旦通过每个阶段,自动化流程将在按下按钮后被触发,将更改推送到生产环境。每个环境应用相同的网络更改,因此网络更改会先在测试环境中进行,然后再在生产环境中进行。
这一切依赖于将网络视为代码,意味着需要创建自动化的网络流程,以使网络团队能够像开发人员一样敏捷。

一旦达成一致的运营模式制定完毕,DevOps 转型才应开始。这将包括在每个阶段选择最合适的工具,以实现预期的结果,重点关注以下几个好处:
-
变更的速度
-
平均解决时间
-
提高正常运行时间
-
部署次数增加
-
跨团队技能共享
-
消除单点故障风险
每个公司的业务流程都不同,因此让各个部门参与其中,并获得所有管理者的支持,以确保这一活动的成功至关重要。
改变网络团队的行为
一旦新的运营模式在公司内建立起来,就要防止网络团队成为 DevOps 导向的持续交付模型中的瓶颈。
传统上,网络工程师习惯于操作命令行,并登录到网络设备的管理员控制台进行更改。基础设施工程师由于已经具备bash和PowerShell脚本编写经验,并且在 Linux 或 Windows 操作系统方面有扎实的基础,因此过渡到配置管理工具并不是一项艰巨的任务。
然而,最初说服网络工程师做出同样的转变可能会更为困难。让网络工程师向 API 编程并采用配置管理工具的过程可能最初看起来令人畏惧,因为这对入门门槛更高,但有经验的自动化工程师在场,可以帮助网络工程师顺利完成这一过渡。
保持耐心很重要,因此可以通过逐步设置一些自动化目标来改变网络团队的行为。这将鼓励正确的行为,并尝试给予奖励。可以通过提供培训或为团队购买特定的编码书籍来启动自动化计划。
还可以考虑举行一次初步的自动化黑客日;这将给网络工程师一天的时间,远离他们的日常工作,并尝试自动化一个他们每天都会重复执行的小流程。如果可能的话,可以将其设为强制性活动,要求工程师们参与,并安排其他团队替代网络团队的工作,这样他们就不容易分心。这是一个了解哪些网络团队成员可能愿意推广 DevOps 和自动化的好方法。如果某个特定的成员表现突出,可以与他们合作,帮助推动自动化计划向整个团队推广,使他们成为流程自动化的推动者。
建立一个内部的 DevOps 聚会,让各团队展示他们的自动化成就,也是推广网络团队自动化的好方法,并能保持动力。鼓励每个团队在每个季度展示他们所取得的有趣成果,并通过允许参与的团队从日常工作中抽出时间来参与,来激励他们。这样可以培养团队之间的社区感,展示他们是一个更大运动的一部分,这个运动为公司带来了真正的成本效益。这也有助于将团队的注意力集中在使公司变得更好的共同目标上,并在过程中打破团队之间的障碍。
必须避免的做法之一是让其他团队为网络团队编写所有的网络自动化。理想情况下,应该是网络团队自己发展并采纳自动化,因此赋予网络团队对网络自动化的所有权感非常重要。然而,这需要网络团队的全力支持,并且需要有纪律性,不能在出现问题时回归到手动任务。
为了顺利过渡,可以考虑从基础设施或开发团队中派一位自动化工程师加入网络团队,但这应该只是一个临时措施。重要的是选择一位受网络团队尊敬且具备网络知识的自动化工程师,因为没有人应该尝试自动化他们无法手动操作的网络流程,所以找一个精通网络的人员来帮助网络自动化至关重要,因为他们将负责培训网络团队,必须受到尊重。如果分配给网络团队的自动化工程师既不具备知识也不受尊重,那么这项计划可能会失败,因此必须谨慎选择。
重要的是要早期接受这样一个现实:向 DevOps 和自动化的过渡可能并不适合每个人,因此并不是每个网络工程师都能够走这条路。关键在于网络团队抓住机会,展现主动性和学习新技能的意愿。对于新的自动化倡议,任何破坏性或负面的行为都应该及早制止,因为它可能会对网络团队产生不良影响。
起初对新事物保持怀疑态度是可以理解的,但不尝试改变或学习新技能是不应该被容忍的,因为这会破坏团队的动态,应该对此进行监控,确保不会因为个别成员成为阻碍者或破坏者,导致自动化倡议失败或停滞不前。
每个组织都有其独特的文化,公司的变化速度将取决于新流程和新工作方式的文化接受度。在推动文化变革时,需要变革推动者,这些推动者可以来自内部 IT 员工或外部资源,具体取决于员工的变革能力和意愿。每个变革项目都是不同的,但确保有合适的人员参与,以及得到正确的管理层支持和背书,是成功的关键。
网络团队的自下而上的 DevOps 举措
自下而上的 DevOps 举措是指当工程师、团队领导或低层管理人员未必得到公司支持以改变操作模型时,他们意识到虽然不能对现有的操作模式进行整体性变革,但可以在自己的团队中运用 DevOps 思想,推动积极的变化,帮助团队更好地表现,并提高生产力。
在从自下而上的 DevOps 举措中实施时,有时会面临更多的困难和挑战,因为有些个人或团队可能不愿意改变自己的工作方式和操作方式,因为他们并没有必须改变的压力。但重要的是不要灰心丧气,尽力为业务做出最好的工作。
通过基层举措证明这一过程带来真正的业务好处,最终仍然有可能说服高层管理层实施 DevOps 举措。
在网络团队中推广 DevOps
尽量保持积极的态度,推动自下而上的举措有时可能会令人感到疲惫,但重要的是要适应各种挑战,不要太过于个人化。始终保持积极,先在自己的团队内部推广 DevOps 流程和正向行为的好处。首要的挑战是说服自己的团队,接受 DevOps 方法的优点,之后再尝试说服其他团队。
一种有效的做法是展示 DevOps 方法给其他公司带来的好处,比如 Google、Facebook 和 Etsy,重点讲述他们在网络领域所做的工作。个人可能会反驳,认为这些公司是独角兽企业,DevOps 之所以有效是因为它们的特殊性,因此要准备好接受挑战。寻找这些公司已经实施的、网络团队可以采纳的实际举措,这些举措也能真正适用于你的公司。
为了促进变革环境的形成,了解同事们的驱动力,是什么激励着他们?尝试根据个人的动机来调整说服策略,对工程师或经理的说服方式可能完全不同。一线工程师可能会受到以下因素的激励:
-
做更有趣的工作
-
发展技能和经验
-
帮助自动化繁琐的日常任务
-
学习受欢迎的配置管理技能
-
理解开发生命周期
-
学习编程
另一方面,经理可能更倾向于通过提供衡量关键绩效指标(KPI)来激励自己,使团队看起来更出色,例如:
-
实施变革所需时间
-
解决故障的平均时间
-
提高网络的正常运行时间
另一种促进参与的方法是邀请你的网络团队参加由前瞻性的网络供应商安排的 DevOps 聚会。他们可能会惊讶于大多数网络和负载均衡供应商现在都在积极推广自动化和 DevOps,而他们可能对此还不知情。这个领域的一些新创新可能足以改变他们的看法,并激发他们对一些新方法的兴趣,这样他们就能跟上行业的步伐。
寻求受人尊敬的经理或工程师的赞助
在让网络团队了解 DevOps 举措之后,下一步是将其推进到更高的层次。寻找网络团队中一个受人尊敬的经理或资深工程师,他们可能愿意尝试 DevOps 和自动化。重要的是要向此人推销这个“梦想”,阐明你对实施一些变革、帮助团队的热情,并表示你希望利用一些已经在其他成功公司中证明有效的最佳实践。
保持谦逊非常重要,尽量避免对同事大发牢骚或抛出泛化的 DevOps 术语,这可能会让人反感。始终要提出合理的论据并加以辩护,同时避免做出泛泛的陈述或概括。尽量避免让人觉得你在削弱经理或资深工程师的权威,相反,应该寻求他们的帮助,争取他们的支持和认可。此时,可能需要展开一些魅力攻势来说服经理或工程师这确实是一个好主意,但逐步推进请求可以帮助避免让人觉得请求毫无诚意。如果请求突然提出,可能会显得不真诚。可以尝试在午餐或饮品时分析情况,并判断他们是否对此感兴趣,因为如果对方固执己见,可能很难改变他们的态度,除非该举措来自上级。
一旦你鼓起勇气提出这个话题,接下来就是提出多个建议,说明在项目经理作为中介的帮助下,团队如何以不同的方式工作。请求在小范围内试行这个方法,并主动提出领导这一举措,同时请求他们的支持和背书。经理或资深工程师可能会对你的主动性印象深刻,并允许你继续推进这个想法,但他们可能会选择你执行的具体举措。因此,永远不要提出自己无法实现的建议,你可能只有一次机会,所以留下好印象至关重要。
尝试从一个小任务入手,这通常是一个痛点,并尝试自动化它。任何人都可以编写自动化脚本,但要尽量让自动化过程易于使用,找出团队在当前流程中喜欢的部分,并尝试将其融入其中。例如,如果他们经常看到命令行输出以特定方式显示,就编写自动化脚本,使输出仍然以相同的方式显示,这样流程就不会让他们感到完全陌生。
尽量避免将值硬编码到脚本中,而是将其提取到配置文件中,使自动化更具灵活性,这样它可能在不同的场景中再次使用。通过向工程师展示自动化的灵活性,能够鼓励他们更多地使用它,向团队中的其他人展示你如何编写自动化脚本,以及他们如何调整它来应用于其他活动。如果做得聪明,自动化将会被团队中的热情成员采纳,而你也将获得足够的动力,给赞助者留下深刻印象,从而推进更复杂的任务。
与网络团队一起自动化复杂问题
在通过自动化小的重复性任务建立信任之后,下一阶段的过程是解决一个更复杂的问题,这可以用来巩固未来在网络团队中使用自动化的地位。
这个过程的部分内容是让其他人有能力承担责任,并在未来主导自动化的工作,因此会花费更多的时间。至关重要的是,之前可能在初步自动化建设过程中故意避开的难合作工程师,这次必须参与进来。
这些工程师在这一阶段很可能完全没有涉及过自动化。这可能意味着团队中最有认证的成员和团队的领导者,没有人说过这会容易,但从长远来看,成功地说服最大的怀疑者相信 DevOps 和自动化的价值,将是值得的。在这个阶段,网络团队的自动化应该已经具备足够的可信度和动力,可以通过引用成功的使用案例来讨论这个话题。
在过程中涉及所有难以合作的个体,比起在过程结束时再向他们提出建议,要容易得多。如果难缠的高级工程师或经理在创建过程中参与其中并有所贡献,他们在同事面前更不可能驳回你的想法。
尽量保持尊重,即使你不同意他们的观点,但如果你认为自己是对的,也不要退缩或放弃。要以事实为基础,避免情绪化的争论,列出利弊,并记录任何担忧,不要忽视它们,你必须愿意妥协,但不能到贬低解决方案的程度。
实际上可能存在需要解决的真正风险,因此有效的观点不应被忽视或轻描淡写。如果你对某些问题不确定,或者感觉某些人态度不合理,尽量寻求你的赞助商的支持。
在实施复杂的自动化任务时,要作为团队而非个人进行工作,这对你自己以及其他人都是一种学习经历。尝试教网络团队使用配置管理工具,他们可能只是不敢尝试新事物,所以要采取温和的方法。可以适当暂停,尝试一些在线教程,让每个人熟悉工具,并尝试各种方法,以尽可能简单的方式解决问题。
尝试向网络工程师展示使用配置管理工具的简单性及其好处。不要使用复杂的配置管理工具,因为这可能让他们反感。目前大多数网络工程师不会编程,但这一点可能在未来几年发生变化。正如前面所说,基础设施工程师至少有一些 bash 或 PowerShell 的基础,这有助于他们入门,因此要选择他们喜欢的工具,并提供选择。尽量避免强制使用他们不喜欢的工具。在使用自动化时,网络工程师最关心的问题之一是同行评审,因为他们天然不信任自动化是否有效。尝试建立一些门控流程来解决这些问题,自动化并不意味着不需要同行评审,因此要创建一个轻量级的流程来帮助。通过使用源代码控制显示差异,确保自动化易于评审,并教育网络工程师如何执行此操作。
编码最初可能是一个令人生畏的任务,因此建议每周做一些团队练习,进行编码或配置管理任务。作为一个团队共同完成。这样可以减轻威胁感,重要的是要听取反馈。如果大家达成共识,认为某些东西没有发挥作用或没有带来好处,那就寻找替代方法,找到一种适合整个团队的方式实现相同的目标。在发布任何新的自动化流程之前,先在预生产环境中进行测试,并与经验丰富的工程师一起进行同行评审,并尝试让它在多个测试案例下失败。新流程只有一次给人留下第一印象的机会,因此一定要确保它是成功的。
尝试在团队之间设立知识共享会议,讨论自动化,并确保每个人都知道如何手动执行操作,这样他们就能轻松调试未来可能出现的问题,或者扩展或修改自动化。确保输出和日志对所有用户都是清晰的,因为在生产环境中使用时,所有人都需要支持自动化。
总结
在本章中,我们介绍了实践中的措施,这些措施结合起来,将使 IT 人员能够在其组织中实施成功的 DevOps 模型。它不仅仅关注部门问题,还提倡使用一套实用的策略来改变约束团队的日常操作模式。它还强调了网络工程师需要学习新技能和技术,以充分利用新的操作模型,避免成为交付过程中的瓶颈。
本章提供了实际的真实世界示例,帮助高级管理人员和工程师提升自己公司的能力,强调团队间的合作,并指出如今网络部门需要自动化所有网络操作,以满足企业的交付节奏。
本章的关键要点是,DevOps 不仅仅适用于开发和运维人员,它同样可以应用于网络团队。重要的是,在启动 DevOps 计划之前,要花时间分析成功的团队或公司,专注于他们成功的原因,但高级管理层的支持是创建成功 DevOps 模型的关键。
你们公司自己的模型不会完全照搬其他公司的模型,所以尽量避免照搬照抄。调整模型,使其适应你们公司的实际情况,允许团队创建自己的流程,但不要强制规定流程。同时,也要允许变革推动者发起团队可以接受的变更。
尝试自动化所有操作工作,从小做起,一旦团队适应了新的工作方式,再逐步解决更大、更复杂的问题。始终记住,成功的变革不会一蹴而就。它只能通过持续改进的模式来实现。
在接下来的章节中,我们将探讨如何将自动化应用于网络,并重点关注配置管理工具,例如Ansible。这些配置管理工具可以提高网络工程师实施变更的速度,并确保所有的网络变更都是以相同的方式进行,从而减少出错的可能性。
注意
关于 DevOps 的有用链接如下:
www.youtube.com/watch?v=TdAmAj3eaFI
www.youtube.com/watch?v=gqmuVHw-hQw
第四章。使用 Ansible 配置网络设备
本章将重点关注当今市场上最受欢迎的几个网络供应商,即 Cisco、Juniper 和 Arista,并探讨这些市场领先供应商如何开发自己的专有操作系统来控制网络操作。本书的目的不是讨论哪家网络供应商的解决方案更好,而是探讨网络运营商如何利用现有的配置管理工具来管理网络设备,因为大多数网络供应商已经创建了用于以编程方式控制网络的 API 和 SDK。
一旦建立了每个操作系统的基础知识,我们将转向来自 Red Hat 的非常流行的开源配置管理工具 Ansible(www.ansible.com/)。
我们将探讨如何使用它来以编程方式配置网络设备并帮助网络运营。本章将展示可用于管理网络设备的实际配置管理流程。
本章将涵盖以下主题:
-
网络供应商的操作系统
-
Ansible 简介
-
当前用于网络自动化的 Ansible 模块
-
管理网络设备的配置管理流程
网络供应商的操作系统
市场领先的网络供应商,如 Cisco、Juniper 和 Arista,都开发了自己的操作系统,允许网络运营商通过命令行界面(CLI)向网络设备发出一系列命令。
每个供应商的 CLI 都是从他们专门的操作系统运行的:
-
Cisco IOS 和 Nxos
-
Juniper Junos
-
Arista Eos
所有这些操作系统都使得通过编程方式控制交换机、路由器和安全设备变得更加容易,因为它们试图简化操作网络设备。
在行业中 DevOps 的兴起也意味着不再可以不提供编程 API 或 SDK 来帮助自动化,现在网络供应商与配置管理工具(如 Puppet、Chef、Ansible 和 Salt)集成,以插入 DevOps 工具链。
Cisco IOS 和 Nxos 操作系统
当 Cisco IOS 操作系统发布时,它是首个提供一组命令行的操作系统,网络运营商可以使用这些命令行来改变网络状态。然而,它仍然存在一些挑战;它具有单片架构,意味着所有进程共享相同的内存空间,并且在并行进程之间没有保护,因此它不适合并行更新,但在当时它是明确的市场领导者。这改变了网络操作方式,意味着网络工程师需要分别登录到网络交换机和路由器上,使用其功能齐全的 CLI 进行更新。
当时,这大大减少了网络操作的复杂性,Cisco 规范化了数据中心中网络操作的方式。网络管理员将登录到设备,运行一系列行业标准的命令行来修改路由器或交换机,Cisco 还开设了认证项目,教授管理员如何操作设备并学习所有命令。
如今,在效率和成本削减对于企业生存至关重要且业务流程向更加灵活的方式转变的背景下,这种现代数据中心模型在网络工程师与网络设备的比例上存在明显的扩展问题,每个网络设备所需的网络工程师数量。
私有云的出现意味着每个网络工程师需要管理的网络设备数量急剧增加,因此自动化成为了以一致的方式管理大量设备的关键。如果一个企业的竞争对手通过自动化的运营模型能够更快地将产品推向市场,那么他们将能比进行手动更改的组织更快地推出产品。自动化已成为跟上网络快速变化所必需的条件。随着 IT 的变化和发展,自动化已成为促进这一演变的前提。
随着近年来网络市场的演变,Cisco 开发了一个新的操作系统 Nxos,使其能够与开源技术集成并支持自动化。Nxos 操作系统已部署在所有新的 Nexus 交换机和路由器上,这一操作系统通过集成开源协议(如 BGP、EVNP 和 VXLAN)将 Cisco 推向开放和模块化的标准,且这些设备甚至可以运行 LXC 容器,这是一种操作系统级虚拟化方法,用于在虚拟机或物理服务器上运行多个隔离的进程。
Cisco 还提供了一套 REST API,允许网络运营商运行原生 Linux 和 bash shell 来执行常规的服务器端管理命令。在 AWS 和 OpenStack 提供的编程 API 可以用来变更网络基础设施的时代,网络供应商需要适应才能生存,否则就可能被淘汰。因此,Cisco 将其交换机和路由器的配置和操作简化到与虚拟设备一样容易。
Nxos 操作系统允许使用 Red Hat 企业版 Linux rpm 包管理器来控制软件更新。这意味着,软件更新可以以行业标准的方式在 Nxos 上进行,就像通过基础设施系统管理员对 Linux 客户操作系统进行打补丁一样。因此,Cisco 网络设备现在对 Linux 系统管理员来说更加直观,并且对最终用户来说更像原生 Linux,这无疑使得它们的管理变得更简单。
Cisco Nxos 操作系统意味着网络变更的推送速度得以提升,因为运营人员可以使用他们自己的工具链和配置管理工具来自动化更新。Nxos 操作系统已经变得不那么依赖厂商,因此,使用网络产品和自动化其产品套件的门槛变得更低。
Juniper Junos 操作系统
Juniper Junos 操作系统驱动程序通过程序化控制来控制网络操作,Junos 操作系统的设计旨在提供 CLI,用户可以通过它执行以检索运行系统的相关信息。Junos 操作系统基于一个明确的层次模型,而不是使用一系列不相关的配置文件。层次模型还完整支持操作模式和配置模式。
直观地说,操作模式用于升级操作系统、监控系统以及检查 Juniper 设备的状态。而配置模式则允许网络管理员配置用户访问和安全性、接口、硬件以及设备上使用的协议集,这为安装系统的人员和操作系统的人员之间提供了清晰的角色分离。Junos 操作系统支持所有开放协议,如 BGP、VXLAN 和 EVPN,并且具备内建的前滚和回滚功能。
Juniper 提供了一款名为PyEZ的 Python 库,适用于 Junos 操作系统,并为 Windows 管理员提供了一个 PowerShell 选项,该选项利用了 Python 中封装的 PowerShell。Python 库 PyEZ 可以通过使用表格和视图来检索任何配置信息,这些表格和视图允许网络管理员根据 Junos 操作系统提供的运行时信息进行脚本编写。一旦通过利用 get() 方法的 Python 脚本提取了表格项,表格可以随后被视为 Python 字典并进行迭代,这使得用户可以在需要时执行复杂的脚本,从而允许网络管理员自动化所有网络操作。Junos PYEZ 库也完全可扩展,网络管理员可以使用其小部件系统添加他们认为合适的功能。
Arista EOS 操作系统
Arista EOS 操作系统基于开放标准,旨在促进网络功能的自动化。它依赖于集中式的CloudVision eXchange(CVX),CVX 服务器保存网络的集中状态。EOS 操作系统通过 Sysdb 来分离每个交换机上的功能控制,Sysdb 是 Arista EOS 操作系统的数据库。Arista Sysdb 是一个运行在用户空间的内存数据库,包含 Arista 交换机的完整状态。Sysdb 存储在设备内存中,因此如果 Arista 交换机重新启动或断电,所有与该交换机相关的信息将丢失。
CVX 服务器作为聚合器,管理从每个交换机的 Sysdb 中收集的所有状态信息,并根据 CVX 服务器集群启用的服务,将信息汇总到网络范围的数据库中。当交换机的 Sysdb 中发生状态变化时,变化会推送到 CVX 集中数据库,随后更新其配置并通知 CVX 上运行的代理程序。
Arista EOS 操作系统支持现代开放协议,如 MLAG、ECMP、BGP 和 VXLAN。它利用 VXLAN 等覆盖技术,使得应用能够在现代数据中心中部署并保持可移植性。Arista 大力推广在 ECMP 下使用 Leaf-Spine 架构,允许实现扩展模型;这一架构与现代云解决方案如 OpenStack 一致,并使其与 SDN 控制器解决方案保持独立。
Arista EOS 操作系统是一个基于 Linux 的操作系统,旨在被程序化控制。EOS 操作系统的主要驱动力是允许网络操作员使用一套结构化的 API,包括 eAPI、CLI 命令以及作为其 SDK 产品组合的一部分的 Python、Ruby 和 GO 库,来执行网络操作。
EOS 操作系统还支持智能系统升级(SSU),通过实时修补和升级的简化及更直观的方式,支持 Arista 设备的扩展,这有助于支持企业的 99.99% 在线时间目标。交换机现在可以由数据中心运营团队在数据中心安装并接线,然后交给 Arista 的零接触配置(ZTP)过程,自动化交换机初始化,零接触替换(ZTR)允许交换机在数据中心中进行更换。
Arista EOS 解决方案 CVX 产品可以通过门户自动化网络工作流任务,如果用户需要交换机和路由器的可视化视图,CVX 允许通过 OVSDB、eAPI 或 OpenFlow 与 SDN 控制器集成。像 Cisco 和 Juniper 一样,EOS API 由于提供了多种 SDK 选项,因此 Arista 产品可以通过配置管理工具(如 Puppet、Chef、Ansible 和 Salt)轻松管理,从而避免手动进行任何网络操作。
Ansible 简介
Ansible 主要是一个基于推送的配置管理工具,它使用一个 Ansible 控制主机,并且可以通过 SSH 连接到多个 Linux 客户操作系统以对其进行配置,最近还新增了 WinRM 支持,因此它现在也可以像配置 Linux 系统一样配置 Windows 客户机。由于 Ansible 可以同时连接到多个服务器,它帮助操作员通过允许他们在多个 Linux 或 Windows 服务器上同时执行统一的操作,从而简化了自动化重复任务的过程。Ansible 还可以作为一个集中式编排工具,连接到 API 端点并对 API 操作进行排序。
在这里,我们可以看到 Ansible 控制主机如何连接到服务器或充当集中式编排工具的示例:

Ansible 执行的每个操作都应该是幂等的,这意味着如果服务器上已经配置了期望的状态,Ansible 将检查来自 playbook 或角色的目标状态,如果服务器已处于正确状态,则不会采取任何操作。只有在状态与 playbook 或角色中指定的状态不同的情况下,操作才会被执行,从而改变服务器的状态。
Ansible 是一个基于 Python 的配置管理工具,它通过一个基于 Linux 的控制主机控制服务器,使用 YAML 文件来定义和描述期望的状态。Ansible 配备了一组丰富的可扩展模块,这些模块主要是用 Python 编写的,但也可以用任何用户希望的语言编写。Ansible 模块允许 Python SDK 或 REST API 被封装在 Ansible 的插件框架中,然后可以通过 Ansible 角色或 playbook 在易于使用的架构中进行调用。在深入了解更详细的示例之前,了解一些 Ansible 的术语是非常重要的。
Ansible 目录结构
Ansible 由一系列 YAML 文件组成,这些文件布局在一个可自定义的目录结构中。
在这个自定义结构中,Ansible 控制节点具有以下目录结构:
-
inventories文件夹包含 Ansible 库存 -
library文件夹包含任何自定义的 Python 插件 -
playbooks文件夹包含所有的 playbook -
roles文件夹包含所有的 Ansible 角色
总体目录结构如下所示:

这提供了所有 Ansible 组件的逻辑分组,随着 playbook 或角色的增多,这将非常有用。最好将 ansible 文件夹结构在源代码管理系统中进行版本控制,如 Git。Git 是一个分布式的开源版本控制仓库,旨在对开发代码进行版本控制,以提高速度和效率(en.wikipedia.org/wiki/Git)。。)
Ansible 库存
Ansible 库存文件实际上是一个在 YAML 文件中定义的 DNS 主机名或 IP 地址的集合。这允许 Ansible 连接到这些目标主机,并在服务器上执行特定命令。
Ansible 允许用户使用库存文件将服务器分组为特定类型或用例。例如,在网络术语中,当使用 Ansible 设置 Leaf-Spine 架构时,网络操作员可以为 Leaf 交换机创建一个组,为 Spine 交换机创建另一个组。这是因为配置每种交换机所需的运行手册命令不同,因此可以在执行时施加限制,只对特定组中的一小部分服务器执行命令。
以下图片展示了定义 Leaf 和 Spine 交换机的库存文件示例,显示了在库存文件中定义的两个组,一个是为 Leaf 交换机命名的leaf,另一个是为 Spine 交换机命名的spine,包含所有交换机的 DNS 条目:

相同的库存可以用简化的格式描述:

Ansible 模块
Ansible 模块通常是用 Python 编写的,或者也可以用其他编程语言编写。Ansible 模块的代码定义了一组操作,用于向客户操作系统添加或删除功能,或者如果用于编排,它也可以针对 API 执行命令。Ansible 模块可用于封装简单的命令行、API 调用或用户希望程序化编写的任何其他操作。模块是以可复用的方式设置的,以便在多个剧本或角色中使用,从而促进代码重用和操作标准化。
在 Ansible 模块中指定的代码被封装在 Ansible 的模块模板中,模块模板结构化了模块的布局。该模板推动了一组标准,因此每个模块在设计上都是幂等的,这意味着代码会首先检测系统的状态,然后判断是否需要在执行操作之前更改状态。
当 Ansible 执行状态更改时,控制台会以黄色输出标明。如果没有进行任何操作,它将显示绿色,表示操作成功运行,但没有更改状态,而红色的控制台输出则表示模块失败。
Ansible 模块公开了一组命令行参数,这些参数可以是必需的也可以是可选的,并且可以有默认值。遵循 Ansible 标准的模块是通过一个包含 present 或 absent 的状态变量创建的,作为命令行变量之一。当模块设置为present时,它将添加由剧本指定的功能;而当设置为absent时,它将移除指定的功能。所有模块通常都具有处理这两种用例的代码。
一旦编写了 Ansible 模块,它就会被放置在library文件夹中,这意味着它作为库对 Python 解释器可用,代码可以通过在 Ansible 的playbooks或roles中定义来使用。Ansible 提供了一组预打包的核心模块和附加模块,所有这些模块都可以通过编写一些 YAML 来描述所需的操作进行访问,所有模块都附带有文档,文档是模块的样板部分,并且可以在 Ansible 官网上找到。
核心模块由 Ansible 核心团队与软件供应商的联合项目维护,通常具有较高的质量。附加模块也可以具有良好的质量,但不是由供应商维护的,有时是由用户维护的,这些用户将模块提交回 Ansible,以帮助开源社区。
在下面的截图中,可以看到一个简单的核心yum模块,由yum:提供,它带有两个命令行变量name,用于指定要安装的 rpm,以及state,它决定是否在目标服务器上安装或移除该 rpm:

Ansible 角色
角色是 Ansible 中的进一步抽象层,也使用 YAML 文件定义。角色可以从剧本中调用;这旨在尽可能简化剧本。随着playbooks功能集的增加,它们可能变得杂乱且难以维护。如果将所有功能都放在一个文件中,剧本可能会变得很难管理。所以角色允许操作员创建最小化的剧本,然后从 Ansible 目录结构中拉取所有信息,从而决定需要在服务器上执行的配置步骤或本地运行的操作。
Ansible 角色试图剥离剧本中的可重复部分并将其分组,以便在需要时可以由多个剧本使用。角色是为了确定服务器配置文件应该是什么,而不仅仅是专注于多个临时指令,因此剧本可以命名为spine.yml,并且该剧本可以包含一组模块化的角色,用于定义特定 Spine 交换机的运行列表,执行此剧本时,它将在 Ansible 清单中指定的每个目标服务器上构建 Spine 交换机。如果设计得当,这些角色应该具有足够的模块化,以便在创建 Leaf 交换机时重复使用。
Ansible 剧本
Ansible 剧本是一个 YAML 文件,用来指示在 Ansible 清单文件中定义的特定主机集上执行的运行列表。剧本指定了一组有序的指令,从 Ansible 控制节点或在 Ansible 清单文件中指定的目标主机上本地执行命令。
Ansible 剧本可以用来创建一个运行列表,调用模块或特定的角色,指示应该在服务器上执行的操作。
在这个示例中,我们看到一个针对清单文件中spine主机的剧本,并执行多个roles来设置 Spine 服务器:

另一个可行的剧本可能完全不使用角色,直接调用 Ansible 的 yum 核心模块,在名为 server 的清单组上安装 apache 的 httpd-2.2.29 yum 包:

剧本还可以指定 when 条件,以决定是否根据前一个操作的输出执行剧本中的某个操作。register 命令用于存储任务的 JSON 输出,后续任务可以通过读取 JSON 结果并评估 when 条件来验证是否应当执行该任务。
从 2.x 版本开始,Ansible 剧本现在也可以使用块式恢复功能。因此,如果嵌套在块命令中的操作失败,则会触发剧本中的恢复部分。这对于清理失败的操作非常有用,使剧本更加健壮。
不应低估块式恢复操作的有用性,当需要将一个大数据库 dmp 文件复制到备份位置时,由于复制的数据量大,这个操作有时可能容易出错。所以,如果目标目录的磁盘空间太低,那么操作可能在中途失败,导致只有部分文件被复制,且服务器处于不可用状态,服务器也可能耗尽磁盘空间。因此,可以使用恢复命令立即清理复制的文件,这样在复制操作失败时,服务器就不会处于不良状态。恢复命令执行完成后,剧本将退出并报告错误,但保持在原始状态。
在以下示例中,我们可以看到一个剧本使用 copy: 模块将源文件 /var/files/db.dmp 复制到 /backups/db.dmp,如果原始命令失败,file: 模块将用于删除该文件:

执行 Ansible 剧本
在创建了剧本和清单文件,并使用了指定的文件夹结构后,可以通过指定 ansible-playbook 命令来执行它。
在以下示例中:
-
ansible-playbook告诉 Ansible 应该指定一个 YAML 剧本文件 -
-i标志用于指定清单文件 -
-l限制执行仅限于清单组(servers)下的服务器 -
-e在此示例中传递额外的变量到剧本,例如 production -
-v设置输出的详细程度:ansible-playbook –i inventories/inventory –l servers –e environment=production playbooks/devops-for-networking.yml -v
Ansible var 文件和 jinja2 模板
Ansible 的 var 文件只是另一种 YAML 文件,指定了一组变量,这些变量将在运行时通过 Ansible 的 include_vars 语句被替换到剧本中。
var 文件只是一种方式,用于分离剧本或角色在运行时所需的变量。这意味着可以在运行时传递不同的 var 文件,而无需将变量硬编码到剧本或角色中。
以下截图展示了一个 var 文件语法示例,内容为包含一个名为 cert_name 的定义变量的 common.yml var 文件:

以下示例展示了上面提到的 common.yml 变量和其他 environment.yml 变量,二者都被加载到 playbook 中。{{ environment }} 变量非常有用,因为它意味着可以从 ansible-playbook 命令行传递不同的值,通过在运行时使用 -e “environment=production” 选项来控制导入到 playbook 中的变量:

common.yml 中的 var 文件变量值 cert1 可以通过在 playbook 中指定 {{ cert_name }} 变量来使用:

Ansible 还具有利用 Python jinja2 模板的能力,这些模板可以在运行时进行转换,以使用一组 var 文件填充配置信息;例如,在前面的示例中,{{ environment }} 变量可以在运行时指定,以加载填充唯一环境信息的变量。使用模板模块转换后的 jinja2 模板将被参数化,使用在 environment.yml 文件中指定的变量。
在以下示例中,我们可以看到 Ansible 的 template: 模块作为角色的一部分被执行,复制一个 jinja2 模板 network_template.j2 并将其转换为 /etc/network.conf:

使用 Ansible 配置网络设备的前提条件
本章中 Ansible 入门 部分介绍的基本构建块与 Ansible 网络模块密切相关,并且适用于希望使用 Ansible 进行配置管理的网络团队。在开始之前,重要的是与网络供应商确认所使用的网络操作系统版本是否能够与 Ansible 一起使用。下一步是配置一个小型的预配服务器,将其用作 Ansible 控制主机,通常该服务器会创建在管理网络上,以便它能够适当地访问所有交换机。
配置服务器可以相对较小,因为它只需要通过 SSH 连接到基于 Linux 的网络操作系统。确保在网络设备上启用了 API 命令行。创建一个临时用户帐户在每个网络设备上也是一个好主意,这将允许你在 Ansible 控制主机上设置公钥,并使用临时帐户将创建的 id_rsa.pub 通过 安全复制 (SCP) 复制到网络设备上的 authorized_keys 文件夹。这将允许 Ansible 使用该私钥连接到所有主机,而无需处理密码。完成此设置活动后,可以从每个网络设备中删除临时密码,甚至可以使用 Ansible 作为第一步活动来完成此操作。
如果一切顺利,下一步将在配置服务器上创建 Ansible 文件夹结构,并填写 Ansible 清单文件,其中包含所有网络设备的 DNS 名称,最后安装 Ansible,当你准备开始执行 playbook 时即可使用。Ansible 现在由 Red Hat 以 rpm 格式打包,因此只要 Ansible 控制主机能够通过 CentOS 镜像或 Red Hat 企业 Linux 访问 Red Hat 仓库,就可以通过简单的 yum install 来安装 Ansible。当然,Ansible 也能在任何基于 Linux 的操作系统上运行,因为它仍然可以作为 PyPi 包在 Ubuntu 上安装。
Ansible Galaxy
如果网络操作员寻找起点而且不擅长编码,他们可以在 Ansible Galaxy 上查找示例,Ansible Galaxy 托管了由开源社区开发的角色,这些角色执行了许多复杂的命令。
网络工程师可以导航到 Ansible Galaxy 仓库:galaxy.ansible.com/。

Ansible Galaxy 拥有成千上万的 Ansible 角色,这些角色由开源社区开发。
一些可用的网络角色示例包括 Arista EOS 角色,它可以用于自动化 Arista 交换机设备。或者,Cisco EVPN VXLAN Spine 角色可以用于在 Cisco 设备上构建 Spine 交换机,或者 Juniper Junos 角色可以用于自动化 Juniper 网络设备。因此,针对各种技术和用例,提供了广泛的模块选择。
请查看以下有用的链接:
-
Arista EOS (
galaxy.ansible.com/arista/eos-system/) -
Juniper (
galaxy.ansible.com/Juniper/junos/)
用户可以浏览角色并搜索特定的网络厂商。在这个示例中,搜索 Arista 返回了 eos 角色,如下图所示:

每个返回的角色都有一个指向其对应 GitHub 仓库的链接:

Ansible Galaxy 是一个非常有用的工具,用户可以以角色(roles)作为起点,并根据自己的需求进行自定义。而不仅仅是从社区获取,任何可能对其他人有用的新角色都应该回馈到 Ansible 社区。
Ansible 核心模块可用于网络操作
自 Ansible 2.0 发布以来,Ansible 配置管理工具已经打包了来自 Arista、Citrix、Cumulus 和 Juniper 的一些核心网络模块。Ansible 可以用于编辑任何网络设备的配置,而不仅仅限于这些模块。Ansible Galaxy 拥有由开源社区开发的各种角色。
以下截图展示了 Ansible 2.x 网络模块的一个子集,重点展示了 Junos(Juniper)、Eos(Arista)、Nxos(Cisco)和 Ios(Cisco):

Ansible 2.x 旨在通过为所有模块提供一组标准化的操作,简化网络模块的使用,使网络工程师感觉更加直观。由于许多网络工程师不熟悉配置管理工具,模块间的标准化简化了初次使用的门槛。当网络工程师看到他们日常使用的命令作为 playbook 或角色的一部分时,Ansible 可以首先作为调度工具使用,然后再深入使用更复杂的模块。
网络工程师在初次使用配置管理工具时的主要担忧之一是不信任系统或不了解其背后的运作方式。因此,能够轻松阅读 playbook 或角色,并查看正在执行的操作,有助于建立对工具的信心,并使其更容易被接受。
完全可以预见,随着时间的推移,开源社区将构建出更复杂的网络模块,其中一些已经通过 Ansible Galaxy 中的角色提供,例如来自 Arista、Juniper 和 Cisco 的角色。然而,以下 Ansible 核心模块已经标准化,允许以相同的方式配置 Arista、Cisco 和 Juniper 网络设备。这些模块可以在任何 playbook 或角色中使用。
_command 模块
在 Ansible 2.x 中,主要与供应商的网络模块一起打包的模块是_command模块。这是 Ansible 的有意选择,因为网络工程师在初次使用配置管理工具时,使用原生网络命令更加直观。
该模块允许 Ansible 使用 SSH 连接到主机,因为网络设备的操作系统主要是基于 Linux 的操作系统。
_command 模块允许网络操作员通过从 Ansible 控制主机连接应用配置更改。Ansible 在此命令中使用的语法与网络操作员在网络设备上使用 CLI 执行的语法相同。
在下面的示例中,EOS 命令 show ip bgp summary 由 eos_command 执行,它连接到每个指定的 {{ inventory_hostname }},这是一个特殊的 Ansible 变量,会替换为清单文件中指定的主机组中每个节点的 DNS 名称。然后,它将命令的输出注册到 eos_command_output 变量中。

Junos 语法是相同的。在下面的示例中,执行了一个类似的网络命令,在 Junos 上显示接口,并将 JSON 输出捕获到 junos_command_output 变量中。

Cisco 示例显示的是 Nxos,但配置在 IOS 中也是相同的。nxos_command 命令执行 show version 命令,并将结果放入 nxos_command_output 变量中:

The _config module
_config 模块用于以确定性方式配置更新,可用于实现变更请求,通过批量执行多个命令。
此模块允许操作员以编程方式更新网络设备上的运行配置中的选定行或块。该模块将连接到设备,提取运行配置,然后以完全可预测的方式推送批量更新。
在下面的示例中,Arista 交换机的配置将通过该模块加载。如果运行配置与现有状态不匹配,no spanning-tree vlan 4094 命令将在 EOS 操作系统上执行,从而在交换机上实现所需的最终状态。

The _template module
_template 模块用于利用 jinja2 模板文件更新配置。可以从网络设备的运行配置中提取该模板,进行更新,然后再推送回设备。
_template 模块的另一个使用场景是,允许网络管理员从一个网络设备中提取运行配置到 jinja2 模板,然后将其应用于其他交换机,以传播相同的更改。
_template 模块只会推送增量更改,除非指定强制命令作为命令行变量,这将执行覆盖操作。
在下面的示例中,eos_config jinja2 模板被推送到 Arista 设备上,并且如果 jinja2 模板中有配置变更,它会对配置进行增量更新。

配置管理流程,用于管理网络设备
DevOps 主要关注的是人和流程,因此,仅仅专注于一些单独的 playbook 或角色示例来操作交换机或防火墙,并不能帮助网络工程师解决他们每天遇到的现实网络挑战。在明确项目的实际目标后,选择正确的工具来促进流程也很重要。工具的选择应在业务需求明确之后,而不是反过来。
网络工程师可以像输入命令到 Ansible playbook 一样,轻松地将这些命令输入到网络操作系统中,因此,重要的是要考虑使用像 Ansible 这样的配置管理工具能为业务带来哪些真正的价值。
单独实现一个新工具并不能真正帮助网络团队提升效率,但在 Ansible 中创建的用于管理 Arista、Juniper 和 Cisco 的模块,是简化和标准化流程与方法的促进工具。然而,真正的关键区别在于将这些模块包裹和利用起来的流程。
Ansible 可以以多种方式帮助网络操作,但最好尝试将任务归类为以下几类:
-
期望状态
-
变更请求
-
自助服务操作
期望状态
第一天的 playbook 应该用于设置网络的期望状态,利用一组角色和模块来构建全新的网络设备,并控制网络的预期状态。一个第一天的 playbook 示例可能是网络工程师第一次配置使用 Arista Leaf 和 Spine 交换机的 Leaf-Spine 架构,刚开始时这可能看起来是个相当复杂的任务。但其中的优点是,整个底层网络的状态可以在 Ansible 中进行描述,同样的道理也适用于防火墙或任何其他设备。
在 Leaf-Spine 网络中,活动将包括配置多个 Leaf 和 Spine 交换机,因此,创建一组角色来抽象常见操作,并在 playbook 中调用它们是可取的,因为相同的配置将需要在多个服务器上执行。
网络工程师将从设置 Ansible 控制主机开始,如 Ansible 先决条件部分所述。接着,他们将创建自己的清单文件,用于配置 Leaf-Spine 架构中的网络设备。
网络工程师应定义他们计划配置的所有网络设备的清单。在以下示例中,我们看到两个主机组,包含两个 spine 交换机和四个 leaf 交换机:

网络操作员还需要指定他们希望在 spine.yml playbook 中执行的角色,如以下屏幕截图所示,首先使用期望的配置构建 Spine 交换机。
在以下的操作手册示例中,我们看到该操作手册针对 Spine 主机组,并对服务器执行 common、interfaces、bridging、ipv4 和 bgp 角色:

执行的角色执行以下配置:
-
通用角色:此角色用于配置 Spine 上的 IP 路由表。
-
接口角色:此角色用于配置 Spine 上的接口。
-
桥接角色:此角色用于配置 Spine 上的所有必要 VLAN 和交换端口。
-
ipv4 角色:此角色用于配置 Spine 的 IP 接口。
-
bgp 角色:此角色用于配置 BGP 协议,使交换机能够相互连接。
所有这些可重用的角色将用于配置 Arista Spine 交换机,并大量使用 eos_command 模块。
类似地,许多相同的模块可以用于在 leaf.yml 操作手册中配置 Leaf 交换机,该操作手册针对库存中的 Leaf 主机组,并执行 common、interfaces、bridging、ipv4、bgp、ecmp 和 mlag 角色,如下图所示:

执行的角色用于执行以下配置:
-
通用角色:此角色用于配置 Spine 上的 IP 路由表。
-
接口角色:此角色用于配置 Spine 上的接口。
-
桥接角色:此角色用于配置 Spine 上的所有必要 VLAN 和交换端口。
-
ipv4 角色:此角色用于配置 Spine 的 IP 接口。
-
bgp:此角色用于配置 BGP 协议,使交换机能够相互连接。
-
ecmp:此角色用于确保在 Leaf-Spine 拓扑中配置了等成本多路径。
-
mlag:此角色用于通过 mlag 在机架顶部配置交换机的冗余。
这表明,如果角色保持足够精细,角色可以被重用,var 文件提供必要的配置更改给角色,因此避免任何硬编码值是非常重要的。
Leaf-Spine 架构是一个从第一天开始的操作手册,但为什么网络工程师要花费大量时间设置这个架构,而它只会使用一次呢?当然,这是一种常见的误解,因为操作手册和角色描述了整个网络的期望状态,一旦初步的角色被写好,之后它们可以在任何时候用来修改网络的期望状态。
Ansible 操作手册和角色还可以以相同的方式用于构建第二个数据中心,作为灾难恢复解决方案,帮助在数据中心重新配置 IP 时修改状态,或者在数据中心扩展更多的 Spine 和 Leaf 交换机。
以最后一个例子为例,在扩展数据中心方面,这就像是向 Ansible 清单中添加更多 Spine 或 Leaf 交换机一样简单。一旦附加的 Arista 交换机在数据中心运维团队完成机架和布线后被零接触配置。
网络操作员然后只需要对var文件做小幅更新,以指定需要使用的 VLAN,并更新清单。
在下面的示例中,通过修改清单文件,基础设施扩展到 15 个 Spine 交换机和 44 个 Leaf 交换机:

尽管这是一个相当极端的扩展示例,但它应该突显投资于自动化的意义和好处。因为这样的扩展会让网络工程师花费数周的时间,而一旦初始角色搭建完成,Ansible 可以在几分钟内执行相同的操作。
这真的是值得投资的,这也意味着交换机的建设方式与其他交换机一致,从而减少了人工错误,并使网络变更的交付更加精确。有些人认为自动化是关于速度的,但在网络领域,它应该真正关注一致性。
相同的spine.yml和leaf.yml剧本也可以在扩展过程中对现有交换机执行,因为 Ansible 本质上是幂等的,意味着只有在配置发生变化时,状态变更才会被推送到交换机。如果角色不是幂等的,那么被调用的模块就是问题所在。
这种幂等性意味着相同的第一天剧本(site.yml)调用spine.yml和leaf.yml,可以在现有交换机上运行,不会改变任何配置,并且可以在不单独指定变化交换机的情况下重复使用。需要注意的是,所有 Ansible 变更在投入生产前应先在测试环境中进行测试。
变更请求
尽管有了自动化,网络工程师仍然需要一个单独的手动变更请求流程,对吧?简单的答案是否定的,手动变更会破坏在第一天的剧本中描述的期望状态。今后的所有网络变更都应该通过相同的配置机制进行推动;不应该存在单独的工作流或临时命令。
在流程外进行变更只会破坏用于维护期望状态的 Ansible 剧本和角色,从而破坏自动化。需要注意的是,利用网络自动化是一种全或无的方法,必须由所有团队成员采纳,且不能在流程外进行任何更改,否则会破坏可重复性和可靠性变更的模型。如果功能缺失,第一天的剧本应该扩展以纳入这些变更。
自助服务操作
使用 Ansible 进行网络操作时,典型的瓶颈之一是网络工程师不愿意让开发团队自己进行网络变更,因此这为网络团队带来了瓶颈,因为通常公司里开发人员的数量多于网络工程师。
这种不情愿是因为网络变更传统上较为复杂,而开发人员的专长是开发代码和创建应用程序,而不是登录到网络设备上为他们的应用程序进行防火墙配置更改。
然而,如果网络工程师创建了一个自助服务剧本,定义了一组安全的工作流操作,那么开发人员可以使用它以安全的方式与网络设备进行交互,这就打开了一个全新的机会,去消除瓶颈。
这使得网络工程师处于主题专家(SME)角色,通过架构设计和运用他们的网络经验来创建体现网络最佳实践的网络自动化,以服务开发团队的需求。
这意味着网络工程师不再执行手动操作,如在开发人员提交工单时手动打开防火墙端口。当然,这是一种角色变化,但自动化的方法正是行业发展的方向。
以防火墙请求为例,开发团队创建了一个新的应用程序,并需要一个测试环境来部署它。在配置测试环境时,它需要网络,网络工程师会询问开发人员需要在防火墙中打开哪些端口。
开发人员暂时不知道如何回答这个问题,因为他们还没有完成应用程序的最终版本,并希望在测试环境中逐步开发它。因此,每当需要打开新端口时,就意味着需要一个新的网络工单来打开开发团队发现的增量端口。这不是网络工程师或开发人员时间的最佳使用方式,因为这会导致双方的不满。网络工程师的时间应该更好地用于优化网络或增加改进的警报,而不是处理工单来打开防火墙端口。
相反,可以使用 Ansible 创建一个自助服务文件。开发人员可以创建一个 jinja2 模板,并将其提交到源代码管理中,列出用于通过 template: 模块进行防火墙变更的配置文件。该模板展示了现有的防火墙条目,并可供开发人员添加新的条目并提交拉取请求,以便在防火墙上打开端口。
网络工程师随后审查变更并批准或拒绝它。经过批准后,Ansible 可以自动触发,将变更推送到测试环境;这确保了配置的有效性。
在以下示例中,我们看到的是一个剧本,它用更新后的 jinja2 firewall.j2 模板替换了 firewall.config 文件,然后从新的模板中重新加载防火墙配置:

这使得网络团队能够启用自助服务模型。这加快了网络变更的速度。它还消除了网络团队作为瓶颈的角色,并推动他们为网络变更创建适当的测试和控制。
自助服务并不意味着网络工程师不再需要。这意味着他们成为流程的守门人,而不再是每天应对接连不断的临时请求。
总结
在本章中,我们探讨了如何使用 Ansible 进行网络设备的服务器端配置管理,并查看了一些行业领先的网络厂商,如 Arista、Cisco 和 Juniper,这些厂商已经改变了他们的运营模式,采用了适合自动化的开放标准和协议。
阅读本章后,您应该已经熟悉来自 Cisco、Juniper 和 Arista 的网络操作系统。了解了 Ansible 配置管理工具及其概念,如 Ansible Inventory、Ansible Modules、Ansible Playbooks、Ansible Roles、Ansible 变量文件和 Jinja2 模板。读者还应熟悉 Ansible Galaxy,这是用于网络自动化的核心 Ansible 模块,以及通过 Ansible 管理网络设备的方法。
本章让读者了解了可以使用像 Ansible 这样的工具来自动化网络工程师日常执行的网络操作的用例。同时,它也应当让读者了解到如何通过利用配置管理工具来改进网络自动化。
本章的主要收获是,像 Ansible 这样的配置管理工具现在本地支持网络操作,并且像 Cisco、Juniper 和 Arista 等厂商已经创建了模块来促进网络操作的自动化。现在没有理由不开始自动化网络操作,因为这些方法得到了领先网络厂商的完全支持,他们明白 SDN 操作是网络操作的未来。
我们已经见证了 Ansible 是一个非常灵活的工具。它的主要优点之一是能够编排 API 并帮助安排软件发布。负载均衡应用程序是软件开发发布过程中的一个基础组成部分,因此在下一章中,我们将探讨能够帮助编排负载均衡器的配置管理原则,帮助网络团队轻松维护复杂的负载均衡解决方案。
注意
Ansible 网络自动化的有用链接:
www.youtube.com/watch?v=7FphWEFQbac
www.youtube.com/watch?v=VYEVjKvMKqU
Cisco 的有用链接:
pynet.twb-tech.com/blog/automation/cisco-ios.html
Juniper 的有用链接:
www.juniper.net/documentation/en_US/junos15.1/topics/concept/junos-script-automation-overview.html
Arista 的有用链接:
www.arista.com/en/products/eos/automation
www.arista.com/docs/Manuals/ConfigGuide.pdf
第五章:使用 Ansible 编排负载均衡器
本章将重点介绍一些当今流行的负载均衡解决方案,以及它们在负载均衡应用程序方面的策略。
随着云解决方案的出现,如 AWS、Microsoft Azure、Google Cloud 和 OpenStack,我们将探讨这些技术对负载均衡的影响,特别是分布式负载和集中式负载均衡策略。本章将展示可用于通过 Ansible 编排负载均衡器的实际配置管理过程,以帮助自动化应用程序的负载均衡需求。
本章将涵盖以下主题:
-
集中式和分布式负载均衡器
-
流行的负载均衡解决方案
-
负载均衡不可变和静态服务器
-
使用 Ansible 编排负载均衡器
集中式和分布式负载均衡器
随着微服务架构的引入,允许开发团队更频繁地对生产环境中的应用程序进行更改,开发者不再仅仅需要按季度发布软件。
随着持续交付(Continuous Delivery)和 DevOps 的推进,应用程序现在每周、每天,甚至每小时都会发布,且通常只更新和发布其中一个或部分微服务。
组织发现微服务架构更易于管理,因此逐渐摒弃了构建单体应用程序的方式。微服务应用程序将较大的应用程序拆分成更小的、可管理的模块。这使得应用程序功能可以更频繁地发布给客户,因为业务在每次发布时不需要重新部署整个产品。这意味着只需重新部署一个小的微服务即可发布一个新功能。由于发布过程更为频繁且持续进行,因此它更容易被理解,通常是完全自动化的,并最终得到负载均衡。
微服务架构对于跨多个办公室或国家的庞大企业也有益处,因为不同的团队可以拥有不同的微服务,并独立发布它们。
这当然意味着开发团队需要一种方式来测试依赖管理,并且要确保充分测试,以保证微服务在发布时不会破坏其他微服务。
结果是,开发者需要创建模拟和存根服务,以便在不部署完整生产环境的情况下有效测试微服务应用程序对多个软件版本的兼容性。
创建微服务架构是企业的一大思维转变,但这是保持竞争力的必要措施。发布单体应用程序通常对企业来说既困难又耗时,而采用季度发布周期的企业最终会被能够以更快、更精细的方式发布功能的竞争对手超越。
微服务架构的使用意味着,由于环境的动态性,能够在测试环境中使用与生产环境相同的负载均衡变得更加重要。
因此,测试环境的负载均衡配置必须尽可能接近生产环境。可以使用配置管理工具来控制负载均衡器的期望状态。
责任的委托也需要审查,以支持微服务架构,因此,部分负载均衡配置的控制应移交给开发团队,而不是向网络团队提出请求,这样既能使其易于管理,又不妨碍开发团队。这当然是一种文化变革,需要高级管理层的支持,以推动操作模型的必要变革。
使用微服务应用时,负载均衡的要求将随着应用程序的开发或规模的扩大而演变,因此,重要的是这些方面要提供给开发人员进行自助请求,而不是等待集中式网络团队来进行负载均衡的更改。
由于向微服务架构的转变,网络和负载均衡的领域也需要不断发展,以支持这些需求,许多供应商创建了 PaaS 解决方案来处理跨混合云的应用程序部署和负载均衡。
现成的 PaaS 解决方案是对于那些可能不太懂技术且无法使用配置管理工具(如 Chef、Puppet、Ansible、Salt 等)创建自己部署管道的公司来说的一个不错选择,帮助他们将应用程序部署到云环境中。
无论是采用哪种部署方式,自建还是现成的 PaaS 解决方案。在考虑公有云、私有云和混合云时,微服务和单体应用仍然需要得到支持。
因此,网络和负载均衡需要具备适应性,以支持不同的工作负载。虽然组织的最终目标是实现微服务架构,但大多数公司现实中必须采用混合方式,兼顾集中式和分布式负载均衡方法,以支持单体应用和云原生微服务。
集中式负载均衡
传统上,负载均衡器作为外部物理设备安装,设计非常复杂,并且使用非常昂贵的设备。负载均衡器会配置为为 Web 内容提供服务,并在昂贵的物理设备上终止 SSL 请求。
负载均衡器将有复杂的配置来通过上下文切换将请求路由到应用程序,且请求会直接传递给静态后端服务器。
这对单体配置来说是最优的,因为应用程序通常是自包含的,并且遵循三层模型:
-
前端 Web 服务器
-
业务逻辑层
-
数据库层
这并不需要大量的东西向流量,因为流量是南北向的,穿越了前端、业务逻辑和数据库。网络设计的目的是最小化处理请求并将其返回给最终用户所需的时间,并且每次都由核心网络提供服务。
分布式负载均衡
随着微服务架构的发展,应用程序的运行方式发生了一定变化。应用程序不再是自包含的,而是需要与同一租户网络内或跨多个租户的依赖微服务应用程序进行通信。
这意味着数据中心内的东西向流量大大增加,并且数据中心中的流量不再像以前那样始终通过核心网络。
微服务应用程序的集群被实例化并在租户网络内进行负载均衡,使用 x86 软件负载均衡解决方案,微服务集群的虚拟 IP(VIP)暴露给需要使用它的相邻微服务。
随着虚拟机、容器和软件定义覆盖网络的日益普及,这意味着软件负载均衡解决方案现在被用来在租户网络内部对应用程序进行负载均衡,而不再需要回到集中式的负载均衡解决方案。
因此,负载均衡供应商不得不适应并生产虚拟化或容器化版本的物理设备,以与开源软件负载均衡解决方案竞争,而这些解决方案通常与微服务一起使用。
常见的负载均衡解决方案
随着应用程序从单体架构转向微服务架构,负载均衡的需求无疑发生了变化。今天,我们看到有向开源负载均衡解决方案的转变,这些解决方案与虚拟机和容器紧密集成,用于在 AWS 中的 VPC 之间或 OpenStack 中的租户网络之间提供东西向流量,而不是依赖于集中式物理设备。
现在,开源负载均衡解决方案已经由Nginx和HAProxy提供,帮助开发人员对他们的应用程序进行负载均衡,或使用 AWS 的弹性负载均衡功能:
aws.amazon.com/elasticloadbalancing/
几年前,Citrix NetScalers(www.citrix.com/products/netscaler-adc/)和 F5 Big-IP(f5.com/products/big-ip)解决方案在企业负载均衡领域拥有垄断地位,但随着众多新解决方案的出现,负载均衡领域发生了显著变化。
新兴的负载均衡初创公司,如 Avi Networks (avinetworks.com/),专注于 x86 计算和软件解决方案,以提供负载均衡解决方案,这些解决方案旨在支持现代微服务应用程序和单体应用程序,支持分布式和集中式负载均衡策略。
本书的目的是讨论哪种负载均衡供应商解决方案最好;没有一刀切的解决方案,选择的负载均衡解决方案将取决于组织所需的流量模式、性能和可移植性。
本书不会深入探讨性能指标;它的目标是探讨当前各供应商提供的不同负载均衡策略以及可以用来完全自动化和编排负载均衡器的配置管理方法,这将帮助网络团队实现负载均衡网络操作的自动化。
Citrix NetScaler
Citrix NetScaler 提供一系列产品来满足组织的负载均衡需求。Citrix 提供多种不同的产品供最终用户使用,如 MPX、SDX、VPX,以及最近推出的 CPX 设备,每种产品的许可证费用根据其支持的吞吐量提供灵活的定价。
MPX 和 SDX 是 NetScaler 的硬件设备,而 VPX 是虚拟化的 NetScaler,CPX 是容器化的 NetScaler。
所有这些产品根据所购买的许可证支持不同的吞吐量(www.citrix.com/products/netscaler-adc/platforms.html)。
Citrix NetScaler 系列产品共享相同的 API 和代码集,因此软件完全一致。NetScaler 提供 REST API 以及 Python、Java 和 C# Nitro SDK,暴露所有可以在 GUI 中进行操作的 NetScaler 功能。所有 NetScaler 产品允许以编程方式控制需要设置的 NetScaler 对象和实体,以控制 MPX、SDX、VPX 或 CPX 上的负载均衡或路由。
NetScaler MPX 设备是一个集中式的物理负载均衡设备,用于处理大量的每秒事务数(TPS);MPX 具有众多安全特性,并且符合有害物质限制(RoHS)和联邦信息处理标准(FIPS),因此该解决方案可以被需要遵守特定监管标准的高监管行业所使用。
MPX 通常用于进行 SSL 卸载;它支持大量的 SSL 吞吐量,这对于需要高性能的应用程序非常有用,因此 SSL 卸载可以在硬件设备上完成。
MPX 可以通过第 4 层负载均衡和第 7 层上下文切换将流量引导到不同的租户网络,或者将流量引导到第二层负载均衡级别。
NetScaler SDX 设备也是一种集中式物理设备,用于处理高 TPS(每秒事务数)。SDX 允许多个 VPX 设备作为 HA 对在 SDX 上设置并部署,从而提高吞吐量和可靠性。
NetScaler 还支持 全局服务器负载均衡(GSLB),它允许在多个 VPX HA 对之间分配负载,采用扩展模型,并利用 CNAME 将流量引导到多个 HA 对:

VPX 可以安装在任何 x86 虚拟化平台上并作为虚拟机设备使用,此外还推出了新的 CPX,它将 NetScaler 放入 Docker 容器中,因此可以在租户网络内部署,而不是在集中式模型中设置。所有设备都允许分配和使用 SSL 证书。
每个 NetScaler 设备,无论是 MPX、SDX、VPX 还是 CPX,都采用相同的 IP 对象模型和代码,其中定义了以下显著的实体来执行应用负载均衡:
-
服务器:NetScaler 上的服务器实体将虚拟机或裸机服务器的 IP 地址绑定到服务器实体。这意味着一旦绑定到其他 NetScaler 实体,该 IP 地址就成为负载均衡的候选者。
-
监控器:NetScaler 上的监控器实体附加到服务或服务组,并提供用于监控附加服务器实体健康状况的健康检查。如果健康检查结果不正常(例如简单的网页 ping),则服务或服务组将被标记为不可用,NetScaler 将不会将流量引导到该服务。
-
服务组:服务组是 NetScaler 实体,用于将一个或多个服务器绑定到
lbvserver实体;服务组可以与一个或多个监控器关联,以对关联的服务器进行健康检查。 -
服务:服务实体用于将一个服务器实体和一个或多个监控健康检查绑定到
lbvserver实体,该实体指定用于检查服务器的协议和端口。 -
lbvserver:
lbvserver实体确定负载均衡策略,如轮询或最少连接,并与服务组实体或多个服务实体连接,暴露一个虚拟 IP 地址,供终端用户访问 Web 应用程序或 Web 服务端点。 -
gslbvserver:当需要在 NetScaler 设备之间进行 DNS 负载均衡时,使用
gslbvserver实体来指定gslb域名和 TTL。 -
csvserver:
csvserver实体用于提供从 gslbvserver 域或 lbvserver IP 地址到其他 lbvservers 的第七层上下文切换。这用于通过 NetScaler 设备路由流量。 -
gslbservice:
gslbvservice实体将gslbvserver域绑定到一个或多个gslbservers实体,从而在 NetScaler 设备之间分配流量。 -
gslbserver:
gslbserver实体是启用了 gslb 的 NetScaler 设备的 IP 地址。
通过利用服务器、监视器、服务组/服务和 lbvserver 的组合,可以实现简单的负载均衡。通过 gslbvserver 和 csvserver,上下文切换允许复杂路由和弹性要求。
F5 Big-IP
F5 Big-IP 套件基于 F5 自有的定制 TMOS 实时操作系统,该操作系统是自包含的并运行在 Linux 上。TMOS 包含一系列操作系统和固件,所有这些都运行在 BIG-IP 硬件设备或 BIG-IP 虚拟实例中。BIG-IP 和 TMOS(甚至 TMM)可以根据使用案例互换使用。
TMOS 是每个 F5 设备的核心,允许流量检查。它根据流量类型做出转发决策,功能类似防火墙,只允许预定义的协议通过 F5 系统。
TMOS 还具有 iRules,它是使用 F5 自有的 工具命令语言(TCL)编写的程序化脚本,使用户能够创建由特定事件触发的独特功能。这可以用于内容交换流量或重新排序 HTTP cookies;TCL 完全可扩展和可编程,能够执行众多操作。
F5 Big-IP 解决方案主要是硬件负载均衡解决方案,提供多种物理硬件设备,客户可以根据其吞吐量要求购买,硬件设备可以集群在一起以实现冗余。
F5 Big-IP 套件提供了多种产品,提供负载均衡、流量管理,甚至防火墙服务。
F5 Big-IP 套件提供的主要负载均衡服务如下:
-
Big-IP DNS: F5 的全球负载均衡解决方案。
-
Local traffic manager: F5 Big-IP 套件的主要负载均衡产品。
F5 Big-IP 解决方案与 Citrix NetScaler 类似,采用对象模型允许负载均衡被程序化定义和虚拟化。F5 允许将 SSL 证书与实体关联。
以下本地流量管理器对象实体允许 F5 Big-IP 进行应用负载均衡:
-
Pool members: 池成员实体映射到虚拟或物理服务器的 IP 地址,并且可以绑定到一个或多个池。池成员可以关联健康监视器。
-
Monitor: 监视器实体返回特定池成员的状态,并充当健康检查功能。
-
Pool: 池实体是一个逻辑分组,包含已关联的池成员集;池也可以与健康监视器以及 服务质量(QoS)相关联。
-
虚拟服务器:虚拟服务器实体与一个或多个池关联,虚拟服务器决定负载均衡策略,例如轮询或最少连接。F5 解决方案也提供基于容量或最快连接的负载均衡解决方案。利用 iRules 的第七层配置文件可以针对虚拟服务器进行配置,并用于暴露 IP 地址以访问池成员。
-
iRules:iRules 使用编程语言 TCL,用户可以基于事件(如切换到不同池)编写特定的负载均衡规则。
-
速率类别:速率类别实现了速率整形,用于控制特定负载均衡操作的带宽消耗,以限制吞吐量。
-
流量类别:流量类别实体用于根据特定事件调节流量流向。
Avi Networks
Avi Networks 是一家相对较新的初创公司,但他们拥有一款非常有趣的负载均衡产品,真正体现了软件定义的理念。这是一款企业级软件负载均衡解决方案,包含可以部署在 x86 计算平台上的 Avi Controller。Avi 是一种纯软件解决方案,将分布式 Avi 服务引擎部署到租户网络中,并与 AWS VPC 及 OpenStack 租户进行集成:

Avi Networks 解决方案提供自动化的负载均衡服务配置功能,支持在 x86 虚拟化平台上进行自动扩展,根据用户配置的利用率规则,灵活地根据负载均衡需求进行扩展。
Avi Networks 解决方案支持多个或隔离的租户,并且拥有一个实时应用监控和分析引擎,可以定位网络中延迟的发生位置及数据包的路由来源地。
Avi 还支持丰富的图形界面,显示负载均衡实体,用户可以直观地查看负载均衡情况,同时还支持抗 DDoS 防护。
所有通过 GUI 或 API 发出的命令都使用相同的 REST API 调用。Avi Networks 解决方案支持 Python 和 REST API。Net Networks 对象模型有许多实体,类似于 NetScalers 和 F5,能够定义负载均衡。
-
健康监测配置文件:健康监测池配置文件实体指定池服务器的健康检查,使用健康属性进行监控。
-
池:池实体指定虚拟或物理服务器的 IP 地址,以服务器列表的形式呈现,并具有关联的健康监测配置文件;如果池出现故障,还可以通过数据脚本指定事件。一个或多个池与虚拟服务实体绑定。
-
自定义策略:自定义策略允许用户以编程方式指定虚拟服务的策略。
-
应用配置文件:应用配置文件实体允许将每个应用程序建模,并为其指定相关的 HTTP 属性、安全性、DDoS、缓存、压缩和 PKI 属性,这些都作为与虚拟服务关联的应用配置文件的一部分。
-
分析配置文件:分析配置文件利用 Avi 分析引擎,捕获威胁、指标、健康评分、延迟阈值以及失败代码,这些都映射到虚拟服务实体。
-
TCP/UDP 配置文件:TCP/UDP 配置文件管理是否使用 TCP 或 UDP,并设置任何 DDoS L3/L4 配置文件。
-
SSL 配置文件:SSL 实体管理虚拟服务实体将使用的 SSL 密码套件。
-
PKI 配置文件:PKI 配置文件实体绑定到虚拟服务实体,并指定虚拟服务的证书颁发机构。
-
策略集:策略集实体允许用户设置安全团队为每个虚拟服务设置针对请求和响应的策略。
-
虚拟服务:虚拟服务实体是负载均衡服务器池的入口点 IP 地址,并与所有配置文件关联,用于定义应用池的负载均衡,同时绑定到 TCP/UDP、应用、SSL、SSL 证书、策略和分析配置文件。
Nginx
Nginx (www.nginx.com/) 支持商业版和开源版。它是一个基于 x86 的软件负载均衡解决方案。Nginx 可以作为 HTTP 和 TCP 负载均衡器使用,支持 HTTP、TCP,甚至 UDP,还可以支持 SSL/TLS 终结。
Nginx 可以通过使用 keepalived 设置冗余模式,以便在一个 Nginx 负载均衡器发生故障时,能够无缝切换到备份服务器,并且零停机时间。
Nginx Plus 是商业版,功能比开源版更完整,支持主动健康检查、会话持久性和缓存等功能。
Nginx 的负载均衡是通过在 nginx.conf 文件中声明语法来设置的。其工作原理是简化负载均衡配置。与 NetScalers、F5 和 Avi Networks 不同,它不使用对象模型来定义负载均衡规则,而是通过声明式语法将负载均衡的虚拟或物理机器描述为后端服务器。
在以下简单示例中,我们看到三台服务器,10.20.1.2、10.20.1.3 和 10.20.1.4,所有的负载均衡都使用 Nginx 声明式语法在端口 80 上进行,并且它通过 http://www.devopsfornetworking.com/devops_for_networking 提供服务:

默认情况下,Nginx 会使用轮询负载均衡方法来负载均衡服务器,但它也支持其他负载均衡方法。
Nginx 的 least_conn 负载均衡方法会将请求转发到当前连接数最少的后端服务器,而 Nginx 的 ip_hash 负载均衡方法则意味着用户可以将相同的源地址绑定到同一目标后端服务器,以便整个请求过程中保持一致。
这对于某些应用程序非常有用,它们要求所有请求在事务处理过程中绑定到同一服务器上,即使用粘性会话。
然而,专有版本的 Nginx Plus 支持一种额外的负载均衡方法,名为 least_time,该方法基于后端服务器的活动连接数计算最低延迟,并根据这些计算结果适当地转发请求。
Nginx 负载均衡器在进行负载均衡时始终使用权重系统;默认情况下,所有服务器的权重为 1。如果服务器的权重设置为 1 以外的值,除非后端的其他服务器无法处理请求,否则该服务器不会接收请求。此功能在对后端服务器进行流量限制时非常有用。
在以下示例中,我们可以看到后端服务器配置了最少连接数的负载均衡方法。服务器 10.20.1.3 的权重为 5,这意味着只有当 10.20.1.2 和 10.20.1.4 达到最大负载时,才会将请求发送到 10.20.1.3 后端服务器:

默认情况下,Nginx 使用轮询负载均衡时,不会停止向未响应的服务器转发请求,因此需要利用 max_fails 和 fail_timeouts 进行处理。
在以下示例中,我们可以看到服务器 10.20.1.2 和 10.20.1.4 的 max_fail 计数为 2,并且 fail_timeout 为 1 秒;如果超过这个值,Nginx 将停止将流量引导到这些服务器:

HAProxy
HAProxy (www.haproxy.org/) 是一款开源的 x86 软件负载均衡器,具有会话感知功能,并可以提供 4 层负载均衡。HAProxy 负载均衡器还可以根据请求的内容进行 7 层上下文切换,并支持 SSL/TLS 终止。
HAProxy 主要用于 HTTP 负载均衡,并可以通过使用 keepalived 配置和两台 Apache 配置以冗余方式进行设置,这样如果主服务器出现故障,备份服务器将成为主服务器,以确保终端用户服务不中断。
HAProxy 使用声明式配置文件来支持负载均衡,而不是采用专有负载均衡解决方案(如 NetScaler、F5 和 Avi Networks)所采用的对象模型。
HAProxy 配置文件包含以下声明式配置部分,以允许设置负载均衡:
-
后端:后端声明可以包含一个或多个服务器;后端服务器可以以 DNS 记录或 IP 地址的形式添加。可以在 HAProxy 服务器上设置多个后端声明。还可以选择负载均衡算法,如轮询或最少连接数。
在以下示例中,我们看到两个后端服务器
10.11.0.1和10.11.0.2,使用轮询算法在端口80上进行负载均衡:![HAProxy]()
-
检查:检查可以避免用户在服务器因某种原因变得不可用时手动将其从后端移除,从而减少停机时间。HAProxy 的默认健康检查总是尝试使用默认端口和 IP 建立与服务器的 TCP 连接。如果服务器无法提供请求,HAProxy 会自动禁用该服务器以避免停机。服务器只有在通过健康检查后才会重新启用。如果后端所有服务器都未通过健康检查,HAProxy 会将整个后端报告为不可用。
可以通过使用
{health-check}选项对后端服务器进行多种健康检查;例如,在以下示例中,即使端口443正在进行负载均衡,tcp-check也可以检查端口8080的健康状况。![HAProxy]()
-
访问控制列表(ACL):ACL 声明用于检查头信息并根据头信息将流量转发到特定的后端服务器。HAProxy 中的 ACL 将尝试根据条件触发动作。
-
前端:前端声明允许 HAProxy 负载均衡器支持不同类型的流量。
在以下示例中,HAProxy 将接受端口
80上的 http 流量,使用 ACL 只匹配以/network开头的请求,并且当匹配/web-network的 ACL 时,它将被转发到high-perf-backend:![HAProxy]()
负载均衡不可变和静态基础设施
随着 AWS 和 OpenStack 等公共和私有云解决方案的出现,已转向使用不可变基础设施,取代传统的静态服务器。
这引发了关于 宠物与牲畜 的争论,或者正如 Gartner 定义的那样,双模式 (www.gartner.com/it-glossary/bimodal/)。
Gartner 表示需要采取两种不同的策略,一种用于新的微服务,牲畜,另一种用于传统基础设施,宠物。牲畜是指一旦完成任务或出现问题就会被淘汰的服务器,通常生命周期为一个发布周期。相对地,宠物是指那些会有数月或数年正常运行时间并会由运维人员进行修补和照顾的服务器。
Gartner 将宠物定义为模式 1,将牲畜定义为模式 2。据说,牲畜方法更适合无状态的微服务云原生应用,而宠物则是指任何单体应用,或者是包含数据的应用,比如数据库。
很多人认为,不可变基础设施和像 OpenStack 和 AWS 这样的解决方案更倾向于牲畜,而单体应用和数据库仍然作为宠物,仍需要一个适用于长期运行服务器的平台。
就个人而言,我觉得宠物与牲畜的辩论是一个非常懒散的争论,令人有些疲惫。与其将应用程序划分为两类,不如把应用程序看作是一个软件交付问题,这就变成了无状态的读取应用和有状态的应用,后者涉及缓存和数据。云原生微服务应用仍然需要数据和状态,因此我对这种区分感到困惑。
然而,毫无争议的是,负载均衡器是不可变基础设施的关键,因为至少有一个版本的应用程序始终需要向客户或其他微服务公开,以确保该应用程序在任何时候都没有停机并保持运行状态。
静态和不可变服务器
在历史上,企业通常会使用运维团队执行以下服务器操作:
-
安装机架和电缆
-
提供固件更新
-
配置 RAID 配置
-
安装操作系统
-
打补丁操作系统
这一切发生在将服务器提供给开发人员之前。静态基础设施仍然可以存在于云环境中;例如,由于需要在本地磁盘上持久化大量数据,数据库通常仍作为静态的物理服务器部署。
静态服务器指的是一组通常会包含状态的长期运行服务器。
另一方面,不可变服务器意味着每次虚拟机发生变化时,都会部署一个新的虚拟机,配备新的操作系统和新发布的软件,彻底删除旧的内容。不可变基础设施意味着不会对服务器状态进行就地更改。
这避免了进行就地升级的痛苦,并确保雪花服务器配置成为过去,过去每台服务器尽管有最好的意图,但在一段时间后总会有轻微的偏离其期望状态。
发布软件时,有多少次软件只在五台机器中的四台上正常工作,浪费了数小时或数天的时间来调试为什么某个软件升级在特定服务器上无法正常工作。
不可变基础设施从已知状态构建服务器,推动相同的配置到质量保证、集成、性能测试和生产环境。
云基础设施的部分组件可以完全不可变,以此来获取这些优势。操作系统就是其中一个候选对象;与其进行就地修补,不如创建一个单一的金镜像,并使用自动化工具(如 Packer)进行完全自动化的补丁更新。
需要缓存层的应用程序本质上更有状态,因此缓存需要始终可用,以便为其他应用程序提供服务。这些缓存应用程序应该以集群的形式部署,并进行负载均衡,滚动更新将确保始终有一个版本的缓存数据可用。该缓存层的新软件版本应该在销毁之前的版本之前同步缓存数据。
另一方面,数据是持久的,因此可以存储在持久存储中,然后由操作系统挂载。当进行不可变的滚动更新时,操作系统层可以在发布过程中将数据挂载到持久或共享存储上。
可以将操作系统和数据分开,从而使所有虚拟机无状态。例如,可以利用 OpenStack Cinder(wiki.openstack.org/wiki/Cinder)将持久数据存储在可以附加到虚拟机上的卷中。
考虑到所有这些使用场景,大多数应用程序可以通过适当的配置管理设计为不可变的部署,甚至是单体应用程序,只要它们不是单点故障。如果某些应用程序是单点故障,它们应该被重新架构,因为发布软件不应导致停机。尽管应用程序是有状态的,但每个状态可以分阶段更新,从而保持一个总体的不可变基础设施模型。
蓝绿部署
蓝绿部署过程并不是一个新概念。在云解决方案崭露头角之前,生产服务器通常会有一组由蓝色(无实时流量)和绿色(提供客户流量)服务器组成的服务器集群,这些服务器会交替使用。这些通常被称为蓝绿服务器,每次发布时会进行交替。
简单来说,蓝绿模型意味着,当需要进行软件升级时,蓝色服务器会被升级到最新的软件版本。升级完成后,蓝色服务器将成为新的绿色服务器,实时流量将切换到新升级的服务器上。
切换实时流量通常是通过将 DNS 条目切换到指向新升级服务器来完成的。因此,一旦 DNS 生存时间(TTL)传播完成,最终用户的请求就会由新升级的服务器来处理。
这意味着,如果软件发布出现问题,可以通过将 DNS 条目切换回指向上一个软件版本来实现回滚。
典型的蓝绿部署过程如下所述:
Release 1.1 将部署在服务器 1、2 和 3 上,并通过负载均衡器向客户提供服务,并设置为绿色(上线):

Release 1.2 将部署在服务器 4、5 和 6 上,然后打上最新的补丁版本,升级到最新的发布版本并进行测试。准备好后,运维团队将切换负载均衡器,将 4、5 和 6 号服务器设置为新的生产发布版本,如后续所示,而之前的绿色(上线)部署将变为蓝色,反之亦然:

当运维团队进行下一个发布时,服务器 1、2 和 3 将被打上最新的版本,升级到 Release 1.3(从 Release 1.1 升级),进行测试,准备好后,运维团队将使用负载均衡器将流量引导到新版本,使 Release 1.2 为蓝色,Release 1.3 为绿色,如下图所示:

传统上,这是使用静态服务器进行蓝绿部署的过程。
然而,在使用不可变模型时,与使用长寿命的静态服务器(例如服务器 1、2、3、4、5 和 6)不同,在发布成功后,服务器将被销毁,如此处所示,因为它们已经完成了使命:

下次需要服务器 4、5 和 6 时,不是进行就地升级,而是会从云环境中的黄金基础镜像创建三台新虚拟机。这些黄金镜像已经打好最新的补丁,因此全新的服务器 7、8 和 9 会在销毁旧服务器后部署 Release 1.4,如后续所示。
一旦服务器 7、8 和 9 上线,服务器 1、2 和 3 将被销毁,因为它们已经完成了使命:

使用 Ansible 协调负载均衡器
在 第四章,使用 Ansible 配置网络设备 中,我们介绍了 Ansible 的基本概念,以及如何使用 Ansible 控制主机、playbooks 和角色进行网络设备的配置管理。然而,Ansible 还有许多不同的核心操作可以帮助协调负载均衡器,我们将在本章中详细讨论。
委托
Ansible 委托是一种强大的机制,意味着从 playbook 或角色中,Ansible 可以通过 SSH 或 WinRM 连接到清单文件中指定的目标服务器,或者从 Ansible 控制主机上交替执行命令。
下图展示了这两种替代连接方法,Ansible 控制主机要么通过 SSH 登录到机器配置它们,要么直接从 Ansible 控制主机运行 API 调用:

这两种选项都可以通过相同的角色或剧本执行,使用 delegate_to,这使得剧本和角色非常灵活,因为它们可以结合 API 调用和服务器端配置管理任务。
委托的一个示例可以在后面找到,那里使用了 Ansible 附加的 HAProxy 模块,并使用 delegate_to 来触发一个协调操作,该操作禁用库存文件中的所有后端服务:

利用 serial 控制滚动百分比
为了在不打断服务的情况下发布软件,最好采用零停机时间的方法,因为它不需要维护窗口来安排更改或发布。Ansible 支持 serial 选项,它将百分比值传递给剧本。
serial 选项允许 Ansible 遍历库存,并仅对一部分机器执行操作,完成必要的剧本后,再移动到库存的下一部分。需要注意的是,Ansible 将库存传递为一个无序的字典,因此处理的库存百分比将不是按特定顺序进行的。
使用 serial 选项,Ansible 可以采用蓝绿策略,因此需要将机器从负载均衡器中移除并进行升级,然后再投入使用。与增加机器数量不同,三个机器是足够的,如下图所示,所有这些机器都运行 版本 1.4:

使用以下 Ansible 剧本,结合 delegate_to 和 serial,可以通过滚动更新升级每台服务器:

该剧本将执行以下步骤:
-
serial 30%表示一次只有一个服务器进行升级。因此,服务器 7 将通过在 Ansible 控制主机上使用本地delegate_to操作来从 HAProxy 的backend_nodes池中移除,禁用该服务,然后执行yum更新,升级服务器版本并安装新的application1发布 版本 1.5,如下所示:![利用 serial 控制滚动百分比]()
-
服务器 7 将再次启用,并通过本地
delegate_to操作将其重新投入负载均衡器中。serial 命令将继续作用于server 8,在 HAProxy 上禁用它,然后执行yum更新,升级服务器版本并安装新的application1发布 版本 1.5,如下所示:![利用 serial 控制滚动百分比]()
-
滚动更新将启用负载均衡器上的服务器 8,然后序列命令将切换到服务器 9,在 HAProxy 上禁用该服务器,然后执行 yum 更新,这将升级服务器并安装新的
application1版本1.5,根据需要在本地服务器和远程服务器之间交替执行,如下所示:![使用序列控制滚动百分比]()
-
最后,剧本将通过在负载均衡器上启用服务器 9来完成,所有服务器将使用 Ansible 升级到版本 1.5,具体如下:
![使用序列控制滚动百分比]()
动态库存
在处理云平台时,仅使用静态库存有时并不够。了解已部署在资源中的服务器库存,并根据特征或配置文件选择其中的子集是非常有用的。
Ansible 有一个增强功能,称为动态库存。它允许用户使用 Python 脚本查询他们选择的云平台;这将作为自动发现工具,可以连接到 AWS 或 OpenStack,并返回 JSON 格式的服务器库存。
这允许 Ansible 将此 JSON 文件加载到剧本或角色中,以便进行迭代。同样,静态库存文件也可以通过变量传递。
动态库存适用于相同的命令行结构,而不是传递以下静态库存:
ansible-playbook –i inevntories/inevtontory –l qa –e current_build=9 playbooks/add_hosts_to_netscaler.yml
然后,可以传递 OpenStack 云提供商的动态库存脚本openstack.py:
ansible-playbook –i inevntories/openstack.py –l qa –e environment=qa playbooks/devops-for_networking.yml
动态库存脚本可以设置特定限制。在前述情况下,返回的唯一服务器库存是质量保证服务器,这是通过–l qa限制来控制的。
在使用 Ansible 配置不可变服务器时,可以利用静态库存文件来启动新的虚拟机,而静态库存则可以在虚拟机已经创建后查询资源并执行附加操作。
标签元数据
在 Ansible 中使用动态库存时,元数据变得非常重要,因为在云环境中部署的服务器可以使用标记在虚拟或物理机器上的元数据进行排序和过滤。
在配置 AWS、Microsoft Azure 或 OpenStack 实例时,可以在公共或私有云中为服务器标记元数据,以便对它们进行分组。
在以下示例中,我们可以看到一个剧本使用os_server OpenStack 模块创建新的 OpenStack 服务器。它将遍历静态库存,标记每个新创建的组,并释放机器上的元数据:

然后,可以使用–l参数过滤动态库存,指定group: qa的服务器。这将返回一个合并后的服务器列表。
Jinja2 过滤器
Jinja2 过滤器允许 Ansible 过滤 playbook 或角色,从而控制在执行特定命令或模块之前需要满足哪些条件。Ansible 提供了多种现成的 Jinja2 过滤器,或者也可以编写自定义过滤器。
使用 Jinja2 过滤器的 playbook 示例将仅在服务器的元数据 openstack.metadata.build 值等于当前构建版本时,才将该服务器添加到 NetScaler 中:

执行 ansible-playbook add_hosts_to_netscaler.yml 命令,并通过 –l 限制为 qa,将仅返回 qa 元数据组中的主机作为库存。然后,主机可以在 playbook 或角色中进一步使用 when Jinja2 过滤器进行过滤,只有当主机的 openstack.metadata.build 值与 current_build 变量 9 匹配时,才会执行“加入负载均衡池”命令:
ansible-playbook –I inevntories/openstack.py –l qa –e environment=qa –e current_build=9 playbooks/add_hosts_to_netscaler.yml
结果将是,只有新的主机会被添加到 NetScaler 的 lbvserver VIP 中。
这些主机也可以以类似方式在同一 playbook 中使用 不等于 条件删除:

所有这些可以结合使用,同时配合串行百分比,将新版本逐步部署到负载均衡器中,并利用动态库存、委托、Jinja2 过滤器和 Ansible 的串行滚动更新功能一起实现简单的负载均衡器编排。
创建 Ansible 网络模块
由于 Ansible 可用于调度对负载均衡器的 API 命令,因此可以轻松地用它来构建出流行网络解决方案(如 Citrix NetScaler、F5 Big-IP 或 Avi Networks)所使用的负载均衡器对象模型。
随着微服务架构的推广,负载均衡配置需要拆分以保持可管理性,因此它是以应用为中心的,而不是存储在集中式的单体配置文件中。
这意味着在进行负载均衡更改时会涉及操作问题,因此网络操作员可以使用 Ansible 来构建复杂的负载均衡规则、应用 SSL 证书、设置更复杂的第 7 层上下文切换或公共 IP 地址,并将这些作为服务提供给开发人员。
利用负载均衡供应商提供的 Python API,每个操作可以作为一个模块创建,并使用一组 YAML var 文件来描述负载均衡器的预期状态。
在稍后的示例中,我们将探讨开发人员如何利用 Ansible 的变量文件为每个新的虚拟服务器创建服务和健康监控器,这些虚拟服务器运行在 NetScaler 上。然后,这些服务会绑定到由网络团队创建的 lbvserver 实体,并设置为 10% 的滚动百分比,可以加载到 playbook 的 serial 命令中。playbook 或角色用于创建服务、lbmonitors、34 个服务器并将服务绑定到 lbvservers,而变量文件则描述了这些 NetScaler 对象的期望状态:

摘要
在本章中,我们看到从专有供应商到开源解决方案都提供了各种负载均衡解决方案,并讨论了微服务对负载均衡的影响,将其从集中式模型转变为分布式模型,以帮助应对东西向流量。
然后,我们探讨了蓝绿部署模型、不可变和静态服务器的优点,以及如何在这两种模型中使用 Ansible 协调软件发布。在此过程中,我们展示了 Ansible 在协调负载均衡器时的有用性,通过利用动态库存、滚动更新、委派和 jinja2 过滤器,帮助实现负载均衡的需求。
本章的关键要点是,微服务应用程序改变了应用程序负载均衡的方式,分布式负载均衡在部署微服务应用程序时更为适合,因为微服务应用程序具有更多的东西-西行流量模式。
不可变基础设施为什么非常适合微服务应用程序的原因现在应该很清楚了。本章还定义了如何将状态和数据从操作系统中分离,以及支持无状态和有状态应用程序所需的不同滚动更新模型。在下一章中,我们将研究如何将这些相同的自动化原则应用到 SDN 控制器上,主要聚焦于 Nuage 解决方案。它将涵盖配置防火墙规则和其他 SDN 命令,从而使整个网络可以通过编程进行控制和自动化。
第六章:使用 Ansible 编排 SDN 控制器
本章将重点讨论 SDN 控制器及其如何帮助网络团队简化日常任务。
我们将探讨为什么 SDN 控制器被采纳,并重点介绍它们在正确使用时所带来的即时业务好处。重点讨论的是如何拆分网络操作,以便通过利用自动化扩展网络操作。
本章将讨论利用软件定义网络的好处,并介绍可用于编排 SDN 控制器 API 和对象模型的实际配置管理流程。最后,我们将探讨如何使用 Ansible 执行并包装一些这些配置管理流程,以 Nuage VSP 作为实际示例。
本章将涵盖以下主题:
-
关于软件定义网络的争议
-
为什么公司要使用 SDN?
-
网络操作的拆分
-
不可变的网络
-
使用 Ansible 编排 SDN 控制器
关于软件定义网络的争议
随着 AWS、Microsoft Azure 和 Google Cloud 等公共云的出现,网络现在被视为一种商品,并从硬件转向了软件。这使得开发人员能够根据应用程序的需求调整网络,而不是将应用程序强行适配到一个可能未针对现代微服务应用程序进行优化的老旧网络中。
因此,如果任何企业想要以不同的方式对待其内部数据中心网络,那么这似乎是没有意义的。然而,像所有新思想一样,接受和采用之前总是伴随着恐惧和不确定性,这与新的或不同的工作方式密切相关。
反对使用 Clos Leaf-Spine 架构和 SDN 控制器的常见争论围绕一个共同的主题,那就是它需要变革,而变革是困难的。我们回到 OSI 模型的传说中的第 8 层,那就是用户层:

网络操作员必须对实施的任何解决方案感到舒适。这一点非常重要,但同样重要的是用户层,因为它是由网络团队提供给最终用户的网络服务。因此,易用性在两个层面上都很重要:网络操作和提供给网络消费者的自服务操作。
在公司考虑实施软件定义网络之前,他们需要出于正确的理由,并根据需求来实施。单纯实施一个新工具,在这种情况下是 SDN 控制器,无法单独解决操作性问题。
组织需要弄清楚新的运营模式应是什么,并利用软件定义网络作为这些新业务流程的促进者,专注于运营速度,旨在消除网络作为应用交付瓶颈的存在。简而言之,网络运营需要适应 DevOps,否则它们会妨碍软件交付,拖慢整个应用生命周期。
增加的网络复杂性
反对使用覆盖网络的部分论点是,它们比传统的二层网络更复杂,拥有更多的动态组件,这些组件可能导致更广泛的故障。
尽管覆盖网络和基础网络的构建方式可能不同,但可以公平地说,软件定义网络仍然是一个相对较新的概念,许多人对改变感到恐惧。只要在网络可用性、冗余性、性能和变更速度等基本要求得到满足,就没有理由不实施软件定义网络。
对软件定义覆盖网络的恐惧可以类比为运营人员最初对服务器虚拟化的怀疑,他们最初反对引入虚拟机监控程序。这些新概念最初被视为额外的复杂层和抽象层,可能不会像预期那样具有良好的性能。
然而,通过运行虚拟机监控程序所带来的可移植性和机遇,远远超过了对绝大多数应用场景的性能影响。这些好处包括提高的可移植性、灵活性和操作速度。
当然,仍然存在一些边缘案例和不适用于虚拟化模型的应用,但虚拟化为 99%的数据中心带来的好处意味着,作为一种商业解决方案,它实在不能被忽视。
覆盖网络为网络带来的好处与虚拟机监控程序为服务器带来的好处相似。当然,在实施软件定义覆盖网络时,基础网络应该为冗余性构建,这样一旦发生故障,它会发生在基础网络上,而不会影响覆盖网络。
基础网络应具备横向扩展性且简单,以叶脊架构为例,架构中一系列脊交换机连接到位于每个机架顶部的叶交换机。引入更多配有叶交换机的机架,或者增加新的脊交换机来防止链路过载,可以实现横向扩展性。
关于覆盖网络增加复杂性的问题,任何一位花费数小时调试二层生成树网络中表现不佳的链路的系统可靠性工程师或网络工程师都会证明,生成树网络本身就非常复杂。系统可靠性工程师或网络工程师可能还会展示他们为了解决问题而绘制的网络图,作为复杂性的证据。
因此,网络在最好的时候也很复杂;然而,在使用承载网和叠加网时,承载网的主要关注点应是横向可扩展性和性能。它应确保网络运营商能够根据需求轻松扩展网络。
另一方面,叠加网络的重点是简洁性,因此它应该具有易于理解的软件结构,同时确保 API 端点能够处理来自消费者的所需数量的并发请求。
如果实施得当,网络应该分为两个不同的部分。叠加网络是用户友好的软件,类似于 AWS、Microsoft Azure、Google Cloud 或 OpenStack,而承载网则是需要网络架构师精心设计并为可扩展性构建的硬核网络。
缺乏软件定义网络技能
另一个反对不实施软件定义网络的论点是当前行业内缺乏技能;对于任何新技术来说,最初都会缺乏足够的熟练人员来支持它。一个观点是,公司将不得不雇佣全新的员工来实施软件定义网络。
然而,这可以通过与 SDN 供应商合作或利用提供的员工培训计划来弥补。这是一种业务转型,因此,网络人员需要在一段时间内不断培养新技能。
但是,网络人员需要随着软件定义网络带来的变化而发展,并像 IT 的其他团队一样培养新技能。实施软件定义网络一开始是一个巨大的变化,但优秀的网络人员应该感到兴奋并迎接这些变化。实施软件定义网络所能带来的效率和收益是不可否认的。
改变一开始可能令人畏惧,有时可能看起来像是一次巨大的文化变革或努力。要在大公司甚至小公司中成功发起变革,通常必须有自上而下的支持或支持。
采用软件定义网络将意味着改变业务的运营模式,并且自动化将在每个层面上得到采用;在使用 SDN 控制器时,叠加网络中的网络任务不能再是手动的。实施软件定义网络的组织还需要寻找自动化承载网的方法。在本书中,我们已经研究了如何利用 API 配置网络设备,因此,承载网和叠加网都需要实现自动化。
“软件定义数据中心”这一术语被厂商过度使用,但如果网络团队希望为公司其他部门提供卓越的用户体验,这背后的原则不能被忽视。如果公司将软件定义网络解决方案作为独立的举措来实施,但如果没有编写自动化以利用提供的丰富 API 来加速网络操作,那么它将没有真正的价值。如果公司要部署软件定义网络,并让网络工程师手动输入网络设备上的命令或使用 GUI,那么公司不如不做,因为他们可以使用任何现成的交换机或路由器来做到这一点;他们浪费了软件定义覆盖网络所提供的机会。
仅仅部署软件定义网络解决方案,而仍然让开发人员提出网络工单,将不会带来任何商业价值;它不会提高效率、市场上线时间或变更的可靠性。为了确保组织从软件定义网络中提取出显著的商业利益,你需要一种全有或全无的方法;网络操作要么完全自动化,要么随着时间推移变得碎片化并崩溃。
如果网络工程师坚持在自动化工作流外进行手动更新,那么它可能会打破整个操作模式。它会改变网络的期望状态,并可能完全破坏自动化。
在部署软件定义网络时,首先自动化所有常见操作,并允许开发人员自助服务,如果可能的话,确保它是不可变的。能够从源代码控制管理系统重建网络应该是目标,因为它充当了变更记录。
在第三章,将 DevOps 引入网络操作,我们讨论了如何启动文化变革。人类是习惯性动物,他们倾向于坚持自己知道的东西;网络工程师花了多年时间获得网络认证,学习如何配置生成树算法和二层网络,因此这是一次巨大的文化转变。
支持常规要求的有状态防火墙
软件定义网络的主要问题之一是缺乏有状态防火墙,因为 Open vSwitch 基于流量数据,并且传统上是无状态的。直到最近,反射规则被用来在内核用户空间级别模拟有状态防火墙。
然而,最近 Open vSwitch 的特性发展使得有状态防火墙得以实现。因此,Open vSwitch 的有状态防火墙问题不再存在。连接跟踪(conntrack),以前仅作为 iptables 的一部分,现在已从 iptables 中解耦,这意味着现在可以同时根据连接和流量数据进行匹配。
Nuage VSP 平台在其 4.x 版本中引入了有状态防火墙。Nuage VSP 平台用有状态规则取代了反射规则,以管理 Nuage VRS(Nuage 定制版 Open vSwitch)上的所有 ICMP 和 TCP ACL 规则:

为什么组织需要软件定义网络?
任何优秀的企业网络都应该以以下目标为基础构建:
-
性能
-
可扩展性
-
冗余性
网络首先需要具备高性能,以满足客户需求。客户可以是数据中心的最终用户,也可以是公共域中应用的最终用户。随着持续交付和部署的推进,如果网络在测试环境中阻碍了开发人员,可能会影响一个潜在功能或 bug 修复上线,因此,低于标准的预生产网络是不可接受的,它们应该设计为生产环境的缩小版功能副本。
可扩展性侧重于将网络横向扩展以支持公司增长和需求的能力。随着更多应用的增加,网络如何实现水平扩展?是否具有成本效益?是否可以轻松适应新的服务需求,如第三方 VPN 访问或点对点网络集成?在创建灵活且强大的网络设计时,所有这些问题都需要得到充分考虑。
冗余性建立在任何企业网络都不应有单点故障的概念上。这样网络可以从交换机故障或核心路由器问题中恢复过来,而不会导致客户中断。网络的每个部分都应该旨在最大限度地提高正常运行时间。
这三点似乎是过去优秀网络设计和建设的基础。然而,随着应用从单体应用转向微服务,成功的网络操作需要额外的要求。
传统上,单体应用通常有一个设置操作,然后保持相对静态,而微服务应用则需要更动态的网络,且网络的变化程度更大。
现代网络的需求已发生变化,网络需要迅速更新,以应对微服务架构的需求,而无需等待网络工程师处理工单。随着持续交付形成反馈循环,过程必须迅速且精益,问题能够快速修复,否则整个流程将崩溃并停滞不前。
软件定义网络增加了灵活性和精准性
软件定义网络,特别是覆盖网络,依然侧重于性能、可扩展性和冗余性;这些因素绝不能妥协,但它也带来了以下好处:
-
灵活性
-
恢复平均时间
-
精准性和可重复性
软件定义网络将网络放入具有关联对象模型的软件覆盖网络中,这使得网络可以通过暴露丰富的 API 集合来进行编程。这意味着,工作流可以用于设置网络功能,就像在云或虚拟化环境中控制基础设施一样。
由于网络是可编程的,请求新的子网或进行 ACL 更改可以像在虚拟机监控程序上启动虚拟机一样迅速完成。软件定义网络消除了传统的阻碍因素或操作限制。过去,这些往往包括需要向网络运维团队提出工单来更改网络,而这个过程通常受到冗长的变更控制流程的制约。相反,利用软件定义网络时,开发人员可以通过 API 调用控制网络操作的子网,从而能够快速进行更改。
使用软件定义网络时,平均恢复时间也得到了改善,因为网络更改是可编程的,因此网络清单可以存储在源代码管理系统中。这使得网络可以版本化,任何更改都会通过源代码管理进行交付,并使网络更改具备模块化、可审计和易于跟踪的特性。
如果覆盖网络发生了重大更改,可以通过源代码管理系统中的版本树查看自上次网络正常发布以来发生了什么变化。然后可以使用相同的可编程脚本快速回滚网络更改至之前的版本,解决问题。当然,这就是实现不可变网络的美妙之处,而不是静态网络,在这种网络中,状态始终保持与初始网络一样干净,可以根据需要向前或向后滚动。
软件定义网络中的可重复性是通过程序化操作工作流来实现的,以便所有网络更改都能以相同的方式由所有用户执行。这些操作可以通过网络团队批准的 API 工作流对覆盖网络进行执行。
程序化工作流的使用意味着网络更改可以融入到应用程序部署过程中,例如持续交付。这意味着,像代码一样,网络更改将被检查到源代码管理系统中,通过程序化工作流操作(以管理网络的期望状态)推送到测试环境,进行测试和验证,然后再推广到下一个测试环境或生产环境。
使用覆盖网络的可重复性确保了质量保证测试环境中的所有构造可以与生产环境相同,因为所有的网络构造都在软件中描述,并且容易复现。
对持续交付有良好的理解是关键。
寻求利用软件定义网络的组织,理想情况下应该已经为代码和基础设施建立了一个成熟的持续交付模型,然后再处理网络操作。那些致力于进行 DevOps 转型的公司,也会从围绕软件定义网络设计新运营模型中大大受益。
那些要求将其所有 IT 操作,包括网络功能,自动化的公司,将从使用 SDN 控制器帮助团队自动化网络中获得不可估量的量化收益。那些本身理解 DevOps、持续集成和持续交付的公司,更有可能充分利用 SDN 控制器的全部能力,并推动创新。
强调一点,如果覆盖网络是由网络工程师手动修改而不是程序化修改的,那么它将不会带来任何商业价值,公司也会错失关键。
实施软件定义网络时,操作模型需要改变,如果发生问题,需要将其纳入自动化流程中进行修复,以避免问题再次发生。任何复杂的流程在最初自动化时,可能会遇到一些意想不到的边缘情况,并在未预料到的条件下失败。因此,持续迭代和改进自动化流程非常重要。让团队采用持续改进的方法论,将确保自动化流程不断迭代和改进,从而随着时间的推移变得越来越稳健。
重要的是要认识到边缘情况会发生,并且在发生时不要惊慌;通过自动化修复问题会使所有用户受益,但同样,自动化中的问题可能会影响多个用户,因此它是一把双刃剑。在创建自动化流程时,进行充分的测试,以尽量在测试环境中捕捉这些边缘情况,变得至关重要。
自动化带来的好处之一是,所有变更都可以像一位高技能的网络工程师一样精确地执行,这位工程师可以将所有的知识传递给自动化系统。这意味着每一次自动化的网络变更都像公司中最优秀的网络工程师一样,经过同样的细心和精确操作。
自动化工作流的预先批准和明确定义的变更可以由公司中的任何人执行,而不仅仅是最优秀的工程师,如果这些变更是自动化的,这样就消除了瓶颈,网络团队可以腾出时间去处理比日常重复的日常业务 (BAU)任务更有趣的任务,这些任务使用自动化会更准确地完成。
简化复杂网络
对于拥有非常复杂遗留网络的组织,软件定义网络将是一个理想的选择,因为修复现有网络可能不可行,原因是必须遵守 99%的正常运行时间目标。相反,可以在现有网络的基础上并行创建一个新的绿地网络。
这将允许应用负载随着时间的推移迁移到新的网络,并在此过程中简化现有网络的复杂性。在迁移期间,新建的绿地网络和旧的遗留网络共存时,可以使用 SDN 覆盖网络将应用程序依赖关系路由回遗留网络,直到这些依赖项迁移完成。
软件定义网络的另一个好处是,它可以让私有云解决方案在更大的规模上运行。如果私有云运行超过 100 个虚拟化管理程序,那么 SDN 解决方案将对其有益,例如扩展 OpenStack Neutron 功能,允许公司在大规模上运行 OpenStack,而不是部署多个较小的 OpenStack 云以应对瓶颈。
分割网络操作
随着软件定义网络(SDN)在公司或企业中的引入,运营责任必须发生转变。如果一个组织运行多个微服务应用程序,一个相当典型的情况是公司有 100 个开发人员开发这 200 个微服务。
这 200 个微服务共同部署公司面向客户的网站。
公司可能采用敏捷软件开发,将 100 个开发人员分成若干个交付团队,每个团队包含约 10 个开发人员,组成 scrum 团队,每个交付团队负责一组相对复杂的微服务。
公司有 10 个网络工程师,负责满足 100 个开发人员的网络需求,同时维护网络的正常运行。
然而,在这种模式下,如果所有网络操作都是手动进行的,那么网络工程师将无法跟上所需的变更请求,因此他们要么不得不加班工作,最终导致精疲力尽,生产力下降。在这种模式下,他们处于应急处理模式。
在这种模式下,开发人员的生产力也可能会受到影响,因为网络工程师将成为吞吐量的瓶颈。所描述的模式显然无法扩展,因此需要进行运营变革。
在描述的场景中,每十个开发人员需要一个网络工程师,随着公司未来的扩展,公司将希望投资开发人员来创造更多的产品。对于组织来说,扩大网络团队以支持这些网络操作无疑是更具挑战性的,因此在这种情况下,网络自动化成为必需,网络团队需要更加智能地工作。
在不改变网络团队操作方式的情况下引入新产品和开发者可能导致过度劳累,因此网络工程师能够支持 10 个开发者,但无法支持 20 个开发者进行所有网络操作手动操作。因此,在提倡自动化时,考虑开发者与网络工程师的比例非常重要,如下所示:

业务部门可能会将软件定义网络视为解决扩展问题的方案,目标是简化网络。这意味着网络工程师可以更快速地进行网络变更,以支持开发者的需求。
但仅仅引入像 CISCO ACI、Juniper Contrail、VMware NSX 或 Nuage Networks 这样的软件定义网络解决方案,并不能解决问题,除非流程已经自动化并且低效的业务流程得到了改进。
基于 API 驱动的网络中的新职责
因此,软件定义网络中网络工程师的角色必须发生变化;他们需要像操作人员为创建基础设施时一样,将部分权限下放给开发者。但软件定义网络不应意味着完全开放 API 访问给开发者。这也是灾难的导火索。需要建立有效的控制机制,作为质量关卡,而不是生产力的抑制器。
覆盖网络中的一些操作工作流程仍然应由合格的网络工程师控制,并受到安全性管理,但不应影响开发者的生产力和需求。
如果期望开发者足够精通网络技术,能够登录路由器并为其应用程序设置路由需求,显然不公平,因此必须找到一些中间解决方案。
允许开发者以不受控制的方式访问网络设备,存在网络中断的风险,这违反了三个主要网络原则之一,并且会妥协冗余性,网络工程师有责任确保系统的正常运行时间。
覆盖架构设置
在设置覆盖网络时,通常会在一个全新的环境中构建,作为应用程序迁移计划的一部分,并作为旧有网络的目标环境。应用程序迁移可以是逐步进行的,也可以一次性完成,其中所有内容都会迁移,然后作为迁移“大爆炸”式活动的一部分进行启用。
无论采用何种应用程序迁移方法,确保覆盖网络的设置能够实现以下目标是非常重要的:
-
敏捷性
-
最小化恢复平均时间
-
可重复性
-
可扩展性
网络性能将由底层组件和使用的硅片决定,但在实施 SDN 对象模型的构造和工作流程时需要正确定义覆盖网络,以确保任何操作都可以快速执行,具有可重复性,并且设计具有可扩展性和支持回滚。在实施 SDN 之前,应对其性能进行测试,以确保虚拟化开销不会影响性能。
因此,让我们快速回顾一下 Nuage VSP 对象模型,该模型在第二章中进行了详细讨论,软件定义网络的出现:
-
组织:管理所有第三层域
![超链接架构设置]()
-
第三层域模板:在创建子第三层域之前需要一个公司 L3 域模板。公司 L3 域模板用于管理适用于所有子第三层域的总体默认策略。如果在模板级别更新了公司 L3 域模板,则会立即在所有已创建的子第三层域上实施更新。
![超链接架构设置]()
-
第三层域:可用于将不同环境分割开来,使用户无法从部署在第三层测试域的子网跳转到第三层生产域的子网。
![超链接架构设置]()
-
区域:区域段的防火墙策略位于应用程序级别,因此每个微服务应用程序可以拥有自己的区域和每个第三层域的入口和出口策略。
![超链接架构设置]()
-
第三层子网:这是部署虚拟机或裸金属服务器的地方。在此示例中,我们看到子网应用程序 1和子网应用程序 2:
![超链接架构设置]()
-
应用程序特定出口策略:用于出口规则的唯一应用程序策略,可用于查看每个单独应用程序的连接规则:
![超链接架构设置]()
-
应用程序特定入口策略:用于入口规则的唯一应用程序策略,可用于查看每个单独应用程序的连接规则:
![超链接架构设置]()
-
泄露域:用于通过第三层子网将路由泄露到覆盖网络中,以桥接绿地网络和传统网络之间的连接:
![超链接架构设置]()
所以,以 Nuage VSP 为例,我们有一个包含两个第三层域的组织,分别是测试和生产,每个微服务应用程序都有自己的区域,包含其独特的微子网和虚拟机:
![超链接架构设置]()
就网络设置而言,网络团队可以使用自动化,并控制覆盖网络中的以下结构:
-
组织:管理所有第 3 层域:
![覆盖架构设置]()
-
第 3 层域模板:用于管理默认策略:
![覆盖架构设置]()
-
第 3 层域:用于分隔开发和生产等环境之间的责任:
![覆盖架构设置]()
-
泄漏域:用于使遗留网络可以从覆盖网络访问:
![覆盖架构设置]()
组织最有可能是第一天的设置活动,而域模板策略可以由网络和安全团队定义和规定。跨所有网络应用的任何安全策略,不管它们部署在哪个域,都由域模板进行管理。因此,测试环境将与生产环境拥有相同的模板策略,并符合所有的安全、治理和合规要求。
开发团队随后可以在测试第 3 层域下创建独特的测试环境,采用相同的后续策略,无需网络团队逐一审计。开发人员使用的应用安全规则可以由安全团队与开发团队达成一致,网络团队无需直接参与,除非他们被请求提供有关设置 ACL 规则的最佳实践建议。
另一个第一天的设置活动可能是设置访问遗留网络,团队将从中迁移应用程序一段时间,因此它们仍然有依赖的应用程序驻留在该网络中。
Nuage VSG 是一个硬件网关设备,连接外部网络到 Nuage VSP 平台及其相关的泄漏域,能够实现这一功能。Nuage VSG 将外部网络的路由泄漏到覆盖网络中,并进入特定的第 3 层域。
Nuage VSP 平台允许网络团队定义利用 VSG 的软件中的GRThubDomain 泄漏域。在此示例中,泄漏域被设置为 IP 主机接口连接到遗留网络中的前端、业务逻辑和后端路由器:

Nuage VSP 平台随后允许将新创建的GRThubDomain与生产或测试第 3 层域相关联,通过将泄漏域与之关联。
在以下示例中,GRThubDomain 泄漏域与生产第 3 层域相关联,以允许从生产第 3 层域下的区域和子网访问遗留网络路由:

网络团队还将负责监控网络底层,并确保在引入更多计算资源时网络能够适当扩展,因此将根据新机架的扩展引入 Leaf 交换机,同时引入新的 Spine 交换机以避免链路饱和。
自助网络
重要的是要关注开发人员通常需要网络票证的网络操作作为起点。这些是开发人员常见的痛点,通常会成为生产力的障碍。通过查看开发团队在网络票务系统中提出的常见问题,可以有效地将网络操作分离。
这些是网络操作员应该使其成为自助服务的常见业务操作:
-
开放防火墙端口
-
创建新的开发环境
-
与其他应用的连接
这些操作应该作为软件定义网络中的自助服务操作进行设置。
在 Nuage VSP 对象模型中,网络操作员应允许开发人员控制以下对象模型实体:
-
区域:它们封装了一个微服务应用:
![自助网络]()
-
第 3 层子网:这些定义了微服务应用可用的 IP 范围:
![自助网络]()
-
应用特定 Egress 策略:定义微服务应用的 Egress ACL 策略:
![自助网络]()
-
应用特定 Ingress 策略:定义微服务应用的 Ingress ACL 策略:
![自助网络]()
这将允许网络操作团队为开发团队提供组织、层 3 域和层 3 域模板。
在测试或生产层的第 3 层域下,开发团队可以灵活地为每个微服务应用创建独特的新区域,然后创建任何它们需要配置的相关子网和虚拟机。
子网将是微型子网,因此类似于/26、/27或/28的子网可能是可以接受的。网络团队将提供子网架构,并提供一个预定系统,团队可以在 IPAM 解决方案中预定地址空间,如果他们正在引入一个应用或创建一个新应用,以避免与其他团队的冲突。
只要每个交付团队遵循这些结构,网络团队就无需参与新应用的配置或引入,这将变成自助服务,像 AWS、Microsoft Azure 或 Google Cloud 一样。
然而,为了更好地支持开发团队,网络团队应理想地创建自助服务自动化,使开发团队能够在 Nuage VSP 中与运维团队一起执行以下操作:
-
创建区域
-
删除区域
-
创建子网
-
删除子网
-
创建 Ingress 规则
-
删除入口规则
-
创建出口规则
-
删除出口规则
-
创建网络宏(外部子网)
-
删除网络宏(外部子网)
无论实施何种 SDN 解决方案,所需的自服务构造将是相似的,为了扩展网络操作,许多操作必须自动化并实现自服务。
理想情况下,这些自服务工作流操作可以添加到 Ansible playbooks 或角色中,并包含在部署流水线中,以便在部署基础设施的同时也配置网络。
不可变网络
为了充分利用软件定义网络的优势,使用不可变网络相比静态网络带来了多重好处。就像基础设施即代码一样,网络即代码,并且利用不可变网络意味着每次应用程序部署时,其网络都会从描述网络期望状态的源代码管理系统中重新部署。这意味着网络配置不会随着时间的推移发生漂移。
使用网络即代码模型来驱动不可变网络可以在生产环境之前测试应用程序的连接性。应使用与生产环境相似的测试环境,在将任何网络更改发布到生产之前检查应用程序的连接性。
将网络更改作为持续交付模型的一部分进行实施意味着,如果应用程序连接性在测试环境中被证明是错误的,那么在生产环境中应用程序连接性也将是错误的。因此,错误的连接性更改永远不应进入生产环境,而应通过创建反馈循环来在生产之前捕获这些问题,反馈循环会提醒团队网络更改不适合目的。捕获此类问题将防止停机和应用程序停机。
A/B 不可变网络
因此,网络应该理想地与应用程序发布周期集成,并成为其一部分,网络将在每次发布时从头开始构建,并从源代码管理系统加载。可以使用不可变的 A/B 网络部署网络。
以集成了 OpenStack 的 Nuage VSP 为例:
-
一个网络将位于第 3 层域下
-
每个区域将与特定的微服务应用程序相关联
-
在区域下,将在 Nuage 和 OpenStack 中分别创建一个子网
-
每个发布的虚拟机将在 OpenStack 中创建,并与 Nuage 子网关联
Application1 版本 1.1 的第一次发布被部署到 Test 第 3 层域,在 Subnet A Application1 上部署两台虚拟机,这些虚拟机位于 Application1 区域下:

应用程序版本 1.2 的第二次发布被部署到 Test 第 3 层域,缩减发布,并在 Subnet B Application1 上部署一台虚拟机,该虚拟机位于 Application1 区域下:

一旦版本 1.2 已在负载均衡器上投入使用并进行滚动部署,新的虚拟机将在Subnet B Application1投入服务,Subnet A Application1随后可以与其虚拟机一起销毁,作为部署清理的一部分:

下一版Application1(版本 1.3)将被部署到Subnet A Application1,并再次扩展至两个虚拟机:

一旦版本 1.2 已在负载均衡器上投入使用并进行滚动部署,Subnet A Application1上的新虚拟机将投入服务,Subnet B Application1可以随后与其相关的虚拟机一起销毁,作为部署清理的一部分:

每次发布将交替在Subnet A Application1和Subnet B Application1之间进行,每次都会从源代码管理构建网络,并清理上一次发布的内容。
多余防火墙规则的清理
防火墙面临的主要技术债务问题之一是,随着时间的推移,随着应用程序的退役或网络连接的变化,它们会积累大量过时的 ACL 规则。进行清理往往存在风险,因为网络工程师担心可能会引发停机。因此,网络团队需要手动清理防火墙规则。
在使用 A/B 不变网络部署时,出站和入站策略与子网关联,这意味着在 Nuage VSP 中,当子网被删除时,所有与该子网关联的 ACL 策略也将作为发布过程的一部分自动清理。
在以下示例中,Subnet A Application1具有以下连接性,因此,当子网作为发布过程的一部分被删除时,所有这些特定于子网的 ACL 规则将被清理:

需要注意的是,由于 ACL 规则存在于子网到区域之间以满足应用程序依赖关系,因此如果 A 子网部署在服务中,B 子网部署将与其相关的 ACL 进出规则并行启动,以取代 A 部署。
所有依赖Application1的应用程序将需要一个指向区域而非子网的 ACL 规则,这意味着它们将不会失去与应用程序的连接,因为它们的规则将依赖于区域,而非子网。在不变子网模型中,子网到子网的规则是不可行的。
为了说明这一点,以下示例中,当前部署的子网 Application1 拥有连接到 Application2 的子网到区域的 ACL 规则。因此,尽管 Application2 的出口和入口策略每次在 A 和 B 部署之间交替,如下图所示:

所需的 ACL 规则始终作为Application1的依赖项可用,因为它订阅的是区域级别的连接,而非子网级别的连接:

应用程序退役
使用不可变子网使得当应用程序不再需要时,停用变得简单。子网和关联的 ACL 规则的清理逻辑已经存在,因此可以重新使用已创建的自动化来完全清理需要退役的微服务应用程序。
操作和网络团队可以轻松提供一个清理管道,供开发团队清理不再需要的应用程序。然后,他们分配的子网范围可以由 IPAM 解决方案释放,以便这些范围可以提供给需要入驻平台的新微服务应用程序。
使用 Ansible 编排 SDN 控制器
如在第五章中讨论的,使用 Ansible 编排负载均衡器,可以用来发布和配置服务器,并直接向SDK或REST API发出命令:

这对于编排提供 Restful API 端点和一系列 SDK 来控制软件定义对象模型的 SDN 控制器非常有用,这些模型使网络操作员能够自动化所有网络操作。
就 Nuage VSP 平台而言,构建覆盖网络的 VSD 组件在后台通过 REST API 调用,因此所有操作可以使用 Nuage 的 Java 或 Python SDK 进行编排,SDK 封装了 REST API 调用。
只需在 Ansible 控制主机上安装 Nuage VSPK SDK,然后就可以用它来编排 Nuage。由于 Ansible 是用 Python 编写的,因此可以轻松创建模块来编排 Nuage 实体树中的每个对象模型。
使用 Nuage VSPK 模块可以交替地用任何可用的编程语言编写,例如 Java,但 Ansible 的 Python 样板代码可能是创建模块的最简单方法。
Nuage VSPK 对象模型在实体之间具有父子关系,因此需要对父对象进行查找,以返回与实体相关联的唯一标识符所对应的子实体。
以下示例突出显示了构建 Nuage VSPK 对象树所需的操作列表:
-
启动一个新的 Nuage
session。 -
user用于创建子级enterprises。 -
创建一个
domain_templates,作为企业的子模板。 -
domains被实例化为域模板的子模板。 -
在域下创建一个子
zone。 -
在区域下创建一个子
subnet。![使用 Ansible 协调 SDN 控制器]()
使用 SDN 进行灾难恢复
使用 Ansible 进行编排的主要好处之一是它可以用于创建一组 Day One playbooks,在开发人员自服务之前构建初始网络。因此,Nuage 组织、公司 L3 域模板 和三层域的初始设置可以作为 Day One playbook 或角色来创建,其他必要的操作也可以包含其中。
可以利用 Nuage Python VSPK 来轻松创建名为 公司 的组织、名为 L3 域模板 的三层域模板,以及根据 Nuage VSPK 对象模型创建的两个三层域 Test 和 Prod,如下图所示:

这些 Python 命令可以很容易地封装在 Ansible 中,创建一组模块来利用 delegate_to localhost 创建一个 Day One playbook,该 playbook 将在 Ansible 控制主机上执行每个模块,然后连接到 Nuage APIs。
每个模块默认应该编写为幂等的,并在发出 Create 命令之前检测实体是否存在。如果实体已经存在,则不应该发出 Create 命令,尤其是在覆盖网络已经处于期望状态的情况下。
如果整个网络需要恢复,Day One playbook 可用于在灾难发生时从头构建整个网络。Day One playbook 应该存储在源代码管理中。而每个部署管道将根据最初定义的结构构建应用程序区域、子网和虚拟机。
如果需要,也可以将管理传统网络连接的泄漏域和泄漏域关联添加到 Day One playbook 中。
将 A/B 子网和 ACL 规则存储在 YAML 文件中。
Ansible 还可以用于将自服务子网和 ACL 规则信息存储在 var 文件中,这些文件将作为每个开发团队部署管道的一部分,通过一组自服务 playbook 被调用。每个应用环境可以存储在一组 var 文件中,定义每个 A/B 子网。
用于创建 A 或 B 子网的 playbook 将使用 delegate_to localhost 执行操作,针对 Nuage VSD API 进行创建操作。
该 playbook 将执行以下操作:
-
如果尚未创建区域,则创建区域。
-
使用子网 YAML 文件在 Nuage 中创建与 OpenStack 映射的子网。
-
将 ACL 策略应用于进入和退出规则,直接将它们应用到子网。
与第一天的剧本一样,可以为每个 VSPK 命令编写独特的模块;在这个示例中,Python VSPK 创建了一个名为Application1的区域和一个名为Subnet A Application1的子网:

因此,这些命令也可以封装在 Ansible 模块中,应该是完全幂等的,网络的期望状态由存储在源代码控制中的 var 文件确定。
剧本中的逻辑会在部署时通过从源代码控制中拉取 var 文件来加载它们。然后,剧本会使用 Jinja2 过滤器条件来检测 A 或 B 子网是否存在,或者两者都不存在,并使用 when 条件。
如果两个子网都不存在,将创建子网 A;如果子网 A 存在,则会创建子网 B。
剧本可以从环境特定的 var 文件中读取这些信息,该文件在以下截图中指定。由于其幂等性,它将在区域上运行,如果该区域不存在,则会创建它,并使用 jinja2 剧本的 when 条件来创建子网 A 或 B:

一组独特的 A 和 B 子网将被提交到源代码控制中,作为每个所需环境的前提条件,每个第 3 层域下可以有一个或多个环境。
ACL 规则理想情况下应在所有封装在第 3 层域中的环境中保持一致,因此会创建一组明确的 ACL 规则,并将其分配给应用程序的独特策略,用于跨所有环境的入站和出站规则。
每个环境可以为每个第 3 层子网拥有其独特的入站和出站策略。如果在测试第 3 层域下存在多个环境,Ansible 剧本则可以为该环境的策略名称附加一个唯一标识符,适用于服务器集成、UAT 或其他测试环境。
一个应用程序的独特 ACL 规则可以由开发团队填写,作为将应用程序迁移到新平台的一部分,基于使应用程序功能所需的最小连接性,同时对第 3 层域模板应用“拒绝所有”规则。
ACL 规则应始终是子网到区域的关系,以满足相互依赖性,每个 ACL 规则将以子网作为源进行创建,以便在销毁子网时,ACL 规则会自动清除。
以下展示了自助服务 ACL 规则文件的示例,它将创建两个入站规则和一个出站规则,针对Application1策略:

自服务手册可以提供给开发团队,确保他们始终有一个标准的方式来创建区域和子网。var文件的 YAML 结构还将提供网络所需状态的模板。这意味着,只要将自动化管道指向另一个 Nuage 端点,整个网络就能从源控制中以编程方式构建。
总结
本章中,我们回顾了 SDN 控制器可以帮助自动化的不同网络操作,并试图澄清一些与软件定义网络相关的常见误解。
接下来,我们探讨了公司如何通过使用软件定义网络受益,并研究了 SDN 解决方案如何帮助解决一些与网络操作相关的挑战。
本章然后重点讨论了网络操作如何需要适应并拥抱自动化,使得开发团队能够自助完成一部分不同的网络任务,以及网络如何被划分并共享责任。接着,我们讨论了不可变 A/B 网络的好处,以及它如何帮助简化网络,构建一致的程序化控制网络,同时保持防火墙规则的简洁。
在本章中,您应该已经了解到为什么软件定义网络对于那些希望扩展网络操作的组织来说至关重要。我们还介绍了如何将叠加网络对象模型用于微服务应用程序,以及不可变网络和 A/B 子网的好处。
本章的关键要点还包括 SDN 控制器如何帮助网络运营商构建首日网络的不同方式,哪些网络操作可以实现自服务,以及如何通过 Rest API 调用或 SDK 编程控制网络操作。
在下一章中,我们将探讨持续集成以及网络操作如何借鉴开发团队的一些最佳实践,并将其应用于网络操作,从而确保网络版本管理得当,并能够滚动前进或回滚更改。
一旦我们建立了持续集成的基础,就会进入涵盖网络测试和持续交付的章节,这些章节将概述一套最佳实践,帮助网络团队将网络自动化集成到部署管道中。
第七章:使用持续集成构建进行网络配置
本章将重点介绍持续集成,过程内容,以及为什么它适用于网络操作。我们将讨论在自动化网络操作时,为什么持续集成过程至关重要。
本章将讨论配置管理工具的好处,并将介绍一些实用的配置管理流程,这些流程可用于设置持续集成过程,以及支持持续集成过程的可用工具。
本章将涵盖以下主题:
-
持续集成概述
-
可用的持续集成工具
-
网络持续集成
持续集成概述
持续集成是一个用于提高开发更改质量的过程。应用于开发人员时,持续集成过程将新的代码更改与其余代码库集成。这是在开发生命周期的早期进行的,创建了即时反馈循环,并针对更改提供通过或失败的结果。
在 DevOps 的范畴内,持续集成是一个关键组成部分,因为它使用集中化的工具,使更改对其他用户可见,并促进软件开发生命周期早期的更改协作和集成。持续集成通常与持续交付过程一起使用,其中持续集成作为软件交付生命周期的第一部分。
在实施持续集成之前,开发人员有时只有在需要打包发布时,才会发现代码更改没有生效。此时,所有开发人员的更改由发布管理或运维团队进行合并。当发布准备好打包时,开发人员可能已经转向新的任务,并且不再处理该部分工作,这意味着修复问题会消耗更多时间,延误发布计划。
一个好的持续集成过程应该在每次开发人员提交更改时触发,意味着他们有一个及时的反馈周期,能够告知他们更改是否正确,而不是在几周或几个月后才发现提交存在问题,导致发布过程变慢。
持续集成基于尽早解决问题的前提,意味着在开发阶段进行修复,最远的右侧是生产环境。这个短语的意思是,如果在开发周期的早期发现问题,修复的成本较低,并且对业务的影响较小,因为理想情况下它永远不会进入生产环境。
持续集成过程遵循以下步骤:提交更改到源代码管理(SCM),然后验证仓库中的更改,并将结果(通过或失败)反馈给用户:

持续集成过程的输出应该是被发送到测试环境和生产服务器的内容。确保通过持续集成和相关测试的相同二进制文件与最终部署到生产服务器上的文件一致,这一点非常重要。
像持续集成这样的流程用于创建反馈循环,能够在问题发生时立即显示出来,从而节省成本。这意味着变更刚刚在实施者的脑海中出现,他们可以迅速修复或撤销该变更,目前开发人员正通过协作迭代代码,并在问题发生时及时修复。
虽然并非所有 IT 人员都遵循相同的部署策略,但反馈循环和验证过程不应仅限于开发人员。当然,进行网络更改时可能不需要编译过程,但可以通过网络设备或 SDN 控制器、负载均衡器上的更改来验证变更是否正确。
开发者持续集成
在其最纯粹的形式中,持续集成过程将开发人员的代码变更与其他开发人员的最新变更进行集成,并确保它正确编译。持续集成过程还可以选择性地对代码库运行一组单元测试或集成测试,打包编译后的二进制文件,然后将构建包上传到工件库,并用唯一的版本号标记代码仓库和构建包。
因此,一个简单的持续集成过程可以总结为以下反馈循环:
-
开发人员将代码变更提交到SCM 系统并将其与代码库进行集成。
-
代码库被拉取到CI 构建服务器。
-
代码被编译以检查新的提交是否有效且不破坏,并且仓库会被标记为构建版本号。
-
返回通过或失败的退出条件,并将反馈结果传递给用户。
-
对下一个代码变更重复步骤 1-5。
![开发者持续集成]()
步骤 1(开发者提交)和步骤 2(在CI 构建服务器上创建仓库副本)是由SCM 系统处理的过程。
过去 10 年中,一些流行的版本控制管理系统(SCM)包括 Subversion、IBM Rational ClearCase、Microsoft Team Foundation Server、Perforce 和 Telelogic CM Synergy。近年来,分布式源代码控制管理系统逐渐从集中式系统转向 Git 和 Mercurial 等分布式系统。
过程中的步骤 3(代码编译)、步骤 4(代码编译反馈给用户)和步骤 5(重复过程)由持续集成构建服务器执行,这些服务器充当持续构建过程的调度代理。
如 Cruise Control、Hudson,或最近的 Jenkins、Travis 和 Thoughtworks Go 等工具用于调度持续集成。
第 4 步(将编译反馈给用户)可以使用如下编译工具进行:
-
Maven
maven.apache.org/ -
Ant
ant.apache.org/ -
MsBuild
msdn.microsoft.com/en-us/library/ms171452(v=vs.90).aspx -
Rake
rake.rubyforge.org/
所有这些工具,以及更多工具,可以根据所需的代码编译类型,作为过程中的主要验证步骤使用。
持续集成过程会持续进行,轮询每次新的开发者提交,进行代码编译并重复相同的过程,以提供持续的反馈循环。如果开发者破坏了持续集成构建,他们需要立即修复,以免阻碍其他开发变更的编译和验证。因此,开发人员使用持续集成来协作,并确保他们的变更成功集成。
额外的步骤,如单元测试或集成测试,可以在编译成功后加入到过程中,以增加对变更的验证。仅仅因为代码编译通过,并不意味着它总是能正常工作。当所有编译和测试完成并打包后,可能会引入第六步,将软件打包并部署到工件库。
所有良好的持续集成过程都应该基于编译、测试和打包的前提。因此,代码发布应该只打包一次,并在部署时将同一包分发到所有服务器。
数据库持续集成
在设置好持续集成以帮助提高代码发布质量之后,控制数据库变更的开发人员通常会考虑对数据库变更做类似的处理。由于数据库变更总是企业发布过程中的重要组成部分,数据库发布出现故障会阻碍软件的部署和发布给客户。
结果是,数据库架构更改或数据库编程存储过程也应该在持续集成过程中尽早集成,并以类似的方式通过快速验证和反馈循环进行测试。
从某种程度上来说,开发人员在考虑持续集成时比较轻松,因为编译过程是一个二元的通过或失败的度量,易于理解。当然,脚本语言是这个规则的例外,但可以通过单元测试来补充,以提供对各种代码操作的验证,并且良好的测试覆盖率能够提升代码质量。
在进行数据库模式更改时,需要满足一系列测试标准,才能将代码推送到生产环境。优秀的数据库开发人员在进行 SQL 更改时会提供前进和回滚脚本,并将其应用到生产数据库,通常会在将其提交到源代码管理系统之前在开发机器上进行测试。
数据库开发人员通过使用前进和回滚发布脚本来实现数据库变更,并将其存储在 SCM 系统中。回滚仅在紧急情况下执行,通常是在生产环境中应用时,如果前进脚本由于某种原因失败。
因此,一个典型的数据库发布过程将包含以下两个步骤:
-
使用发布脚本应用 SQL 表或列的创建、更新、删除或存储过程。
-
如果此步骤失败,请使用回滚发布脚本回滚 SQL 表或列的创建、更新、删除或存储过程。
因此,在任何生产发布之前,数据库开发人员的前进和回滚脚本应该经过测试。由于多个数据库开发人员参与同一版本发布,因此这些数据库发布脚本应按照它们在生产环境中应用的顺序进行应用,因为一个开发人员的变更可能会破坏另一个开发人员的变更。
在设置数据库持续集成之前,需要满足一些前提条件:
-
使用与生产匹配的数据库模式以及相关数据集,并确保所有特性一致,例如索引,以便我们能够测试与实际生产版本相似的环境。
-
持续集成过程还应该利用与数据库发布脚本序列化相同的部署运行器脚本,并在失败时提供回滚功能。
测试回滚脚本与测试前进脚本同样重要,因此数据库持续集成过程需要有效的测试来涵盖回滚。
数据库开发人员在本地工作站上应用的常见数据库部署工作流程如下所示:
-
使用部署运行器脚本将前进数据库脚本应用到 CI 测试数据库。
-
使用部署运行器脚本将回滚数据库脚本应用到 CI 测试数据库。
-
使用部署运行器脚本将前进数据库脚本应用到 CI 测试数据库。
-
使用部署运行器脚本将回滚数据库脚本应用到 CI 测试数据库。
如果前面的步骤成功,那么前进和回滚的数据库脚本在语法上是正确的,且在应用到生产数据库时不会失败。
前面的步骤还使用部署运行器检查顺序的有效性,并检查集成的数据库部署脚本是否协同工作且在回滚时不会冲突。
通过持续集成,我们已经排除了可能导致生产环境失败的多种情况。然而,仅仅依赖前述的持续集成过程是不够的,因为与代码编译一样,SQL 不返回错误并不意味着数据库的前滚和回滚脚本在技术上是有效的,因此数据库更改仍然需要通过功能测试进行补充。
持续集成的关键是将质量检查提前到交付生命周期,并创建反馈循环。持续集成并不是为了证明一个发布是 100% 有效的,而应该看作是证明已经遵循了检查过程,从而证明发布没有问题。
一个简单的持续集成数据库过程将为数据库开发人员提供以下反馈循环:
-
开发人员将前滚和回滚更改提交到SCM 系统,并与代码库进行集成。
-
代码库被拉取到CI 构建服务器。
-
使用部署运行器脚本将前滚数据库脚本应用于 CI 测试数据库。
-
使用部署运行器脚本将回滚数据库脚本应用于 CI 测试数据库。
-
使用部署运行器脚本将前滚数据库脚本应用于 CI 测试数据库。
-
使用部署运行器脚本将回滚数据库脚本应用于 CI 测试数据库。
-
返回通过或失败退出条件并反馈给用户。
-
重复步骤 1-7,进行下一个数据库更改。
![数据库持续集成]()
一旦发布准备好上线,数据库 CI 将应用最终的更改,为下一次发布、下一次数据库更改迭代以及下一批数据库脚本做好准备,这些脚本将由下次发布应用。或者,CI 数据库架构可以从生产环境中刷新。
一个好的做法是始终创建数据库的基准线,以便如果数据库开发人员不小心提交了错误的前滚和回滚操作,CI 数据库可以轻松恢复到所需的状态,而不会成为开发的瓶颈。
当然,这只是一种处理数据库更改验证的方法,其他方法也是可能的。微软提供了数据库项目来实现这一目的,但验证引擎并不重要,关键是要在发布生命周期的早期进行任何更改的验证。
确保没有任何内容进入生产环境,除非经过 CI 过程,这是非常重要的。如果设置了一个很好的流程,但又跳过它,那么这将使 CI 数据库架构失效,可能带来巨大的后果。
可用于持续集成的工具
有许多不同类型的配置管理工具可以帮助构建持续集成过程,因此有多种不同的选项可供选择,刚开始可能会显得让人不知所措。
工具应根据流程需求进行选择,并由团队或用户进行挑选。如 第三章《将 DevOps 带入网络运维》中所述,将 DevOps 带入网络运维,在选择任何工具之前,首先需要规划好需要解决的需求和期望的流程。
同样重要的是,避免工具的泛滥,这是大公司中常见的问题,应为每个操作选择一个最合适的工具,而不是让多个工具做相同的事情,因为这样会给业务带来额外的运营负担。
如果公司中已有用于持续集成的配置管理工具,那么它很可能能够满足需求。在考虑用于执行持续集成流程的工具时,需要以下工具:
-
SCM 系统
-
验证引擎
SCM 系统主要用于存储代码或配置管理的配置文件在源代码控制仓库中
验证引擎用于调度代码编译或验证配置。因此,持续集成构建服务器被用于调度,而许多编译或测试工具可用于提供验证功能。
源代码管理系统
SCM 系统提供了持续集成过程的核心,但无论选择哪个 SCM 系统,从基础层面来看,它应该具备以下基本功能:
-
对所有需要提交更改的用户都应该可访问
-
存储文件的最新版本
-
拥有一个可以被用户浏览的集中式 URL,以查看可用的仓库
-
具备基于角色的访问权限模型
-
支持版本回滚和文件版本树
-
显示提交更改的用户以及更改的日期和时间
-
支持仓库的标签管理,可以使用该标签来查看所有贡献于发布的文件
-
支持多个仓库分支以便进行并行开发
-
具备合并文件和处理合并冲突的能力
-
具备命令行
-
插件支持持续集成构建服务器
大多数 SCM 系统还将支持以下附加功能:
-
提供可编程的 API 或 SDK
-
能够与开发人员的 IDEs 容易集成
-
与 Active Directory 或 轻量级目录访问协议 (LDAP) 集成,以实现基于角色的访问控制
-
支持与变更管理工具的集成,其中 SCM 提交可以与变更工单关联
-
支持与同行评审工具的集成
SCM 系统可以是集中式或分布式的,近年来,分布式源代码管理系统的使用越来越广泛。
集中式 SCM 系统
当最初创建 SCM 系统时,旨在促进开发团队工作,采用了集中式架构来构建这些系统。集中式 SCM 系统用于存储代码,开发人员会访问他们需要对其进行更改的代码库,并对集中式系统中的实时代码进行编辑。
为了确保开发人员的高效工作,集中式 SCM 系统始终需要保持在线并可用:
-
开发人员会访问他们希望修改代码的代码库
-
然后他们会签出他们希望编辑的文件
-
进行更改
-
然后将文件重新提交到代码中央分支
SCM 系统会有一个锁定机制,以避免冲突,确保同一时间内只有一个用户能够编辑文件。如果两个开发人员同时访问该文件,在线 SCM 系统会显示该文件已被另一位开发人员锁定,他们必须等待该开发人员完成修改后,才能继续签出代码并进行后续更改。
开发人员在进行更改时,会直接连接到集中式 SCM 系统中托管的代码库,以更新代码。当开发人员进行更改时,相应的更改状态会被写入集中式数据库,更新整体代码库的状态。
状态更改随后会自动同步到其他开发人员的视图中。集中式 SCM 系统的一个批评意见是,开发人员有时希望脱机工作,因此一些集中式源代码管理系统引入了快照视图的概念,作为永久在线更新代码库视图的替代方案,并引入了脱机更新功能。
在集中式 SCM 系统中,快照视图是某个时间点上,活跃代码库的快照副本。最佳实践要求,在将任何开发更改提交到集中式服务器之前,应该更新快照视图;任何合并冲突应在本地解决,之后再提交在快照视图中所做的更改。
开发人员会通过命令行接口或与开发人员集成的 IDE 图形界面与集中式 SCM 系统进行集成,以便于使用,这样他们就不需要在命令行和 IDE 之间切换。
一些优秀的集中式源代码管理系统示例如下:
-
IBM Rational ClearCase
-
Telelogic CM Synergy
-
IBM Rational Team Concert
-
微软 Team Foundation Server
-
Subversion
-
Perforce
分布式 SCM 系统
分布式 SCM 系统没有中央主控节点,而是将更改复制到多个位置。用户会创建代码库的副本,然后可以通过自己的本地副本进行拉取或推送操作,这些副本存储在开发人员的本地开发机器上。
分布式系统中的每个代码库都有一个所有者或维护者,用户将通过拉取请求的形式提交更改。开发人员会创建一个拉取请求,这类似于合并请求,但仓库的维护者可以决定是否接受该请求。一旦接受,提交的更改将被合并到分支中。
分布式 SCM 系统的主要优势之一是能够在离线时对代码库进行操作。更改可以提交到本地代码库,然后当开发人员准备好时,将其推送到主分支。
分布式 SCM 系统更容易进行合并且效率更高,因此它们更适合敏捷开发,这通常意味着为每个微服务提供多个小型代码库,而不是为单体应用提供大型集中式代码库。
分布式 SCM 系统的示例如下:
-
Git
-
Mercurial
-
Veracity
分支策略
分支策略用于满足现代软件开发的需求,不同的分支服务于不同的使用场景并支持代码的多个版本。
SCM 系统传统上依赖于主干分支,通常被称为主线或主分支。主干分支策略意味着主干/主线分支始终是干净且可工作的代码版本,该分支上的文件代表生产环境中的代码。
然后,为了支持最新版本的活跃开发,创建了开发分支;而发布分支用于在生产系统中发现错误时进行维护发布。
可以实现许多不同的分支策略;以下示例展示了主干分支策略。
主干/主线/主分支保持清洁,所有发布都通过将更改合并到该分支来进行,每次发布时都会给该分支打标签。这允许在标签之间进行差异对比,以查看发生了哪些变化。
开发分支用于活跃的开发,创建版本 1.0,然后合并到发布分支 1.0,此分支随后立即合并回主干/主线/主分支。
开发分支随后开始版本 2.0 的活跃开发,而发布分支 1.0则用于 1.x 的维护发布,特别是当需要修复 Bug 时:

主干分支策略意味着需要大量的合并和协调,发布经理需要在发布日协调合并和版本发布。
中央化的配置管理系统被建立以支持主干式的软件开发方法,这在支持瀑布开发时是有效的。
瀑布式软件开发具有严格的项目阶段,包括分析、设计、实现和测试阶段,因此在团队每几个月只发布一次版本,而不是每天发布时,主线分支策略就足够用了,繁琐的合并过程并不是瓶颈。
然而,向敏捷软件开发的过渡意味着实现主线策略变得更加困难,因为现在团队发布频率更高,已经转向了持续部署和交付模型。
更适合敏捷开发的替代分支策略是使用功能分支。在敏捷软件开发中,工作被拆分成持续两周的冲刺。因此,主分支或主线分支仍然被使用,但在冲刺期间开发人员会创建非常短暂的功能分支。分布式 SCM 系统将合并的控制权交给开发人员,而不是使用集中式的发布管理团队来处理这些操作。
在以下示例中,我们可以看到功能分支的一个例子,在为期两周的冲刺中创建了三个不同的功能分支,功能 A、功能 B 和 功能 C。当开发人员完成了功能开发后,这些功能会合并回主干/主分支。
每当从一个功能分支进行提交时,变更会直接合并到主干/主分支,并且会启动一个持续集成过程来验证这些变更,每一次成功的提交都会成为潜在的发布候选版本。经过持续集成过程打包后的发布版本可以准备部署,如下图所示:

一些纯粹主义者会反对使用功能分支,倾向于始终在主干/主分支上工作。然而,这个决策交给各个团队来决定哪种方法最适合他们,这是一个主观问题。也有人会认为,功能分支可以在主干/主分支上的适当测试创建之前,增加额外的控制层级,以便在合并之前进行适当的同行评审。
当对一个分支进行提交时,应该触发持续集成构建并验证所提交的变更。这会在整个过程中形成反馈回路。任何进入任何分支的变更都应该由持续集成构建来管理,以筛选出良好的变更,并在发生破坏性变更时立即予以突出显示,以便及时修复。
持续集成构建服务器
各种持续集成构建服务器可用于帮助安排验证步骤或测试。最早的持续集成构建服务器之一是 Thoughtworks 的 Cruise Control,后来发展成为 Thoughtworks Go。
Cruise Control 允许用户配置一个 XML 文件,设置不同的持续集成构建任务。每个构建任务都会运行一组命令行选项;通常是针对代码仓库的编译过程,如果成功则返回绿色构建,若构建失败则返回红色构建。Cruise Control 会以构建日志的形式突出显示错误,通过 Cruise Control 仪表盘或电子邮件将反馈提供给用户。
当前市场领先的构建服务器是 Cloudbees Jenkins,这是一个开源项目,是原始 Hudson 项目的分支。Jenkins 使得不再需要配置 XML 文件,而是将所有设置操作转移到 GUI 或 API 中。它带有大量插件,几乎可以执行任何可能的持续集成操作。自 Jenkins 2.x 发布以来,它还深入到了持续交付领域。
下一代 CI 系统已朝云解决方案发展,Travis 成为开源项目的热门选择。这允许用户提交一个 Travis YAML 文件,该文件从源代码管理中创建构建配置,并可以与代码一起版本化。这是 Jenkins 2.x 当前所做的,使用 Jenkinsfile,并且 Jenkins 工作构建器项目一直在为 OpenStack 项目做这项工作。
在寻找持续集成构建服务器时,有许多不同的选项,考虑以下内容;无论选择哪种持续集成构建系统,基本层面上都应具备以下基本功能:
-
用于反馈的仪表盘
-
绿色构建和红色构建的概念
-
通用命令行的调度功能
-
基于退出条件的构建通过或失败,
0表示通过 -
与知名编译工具的插件支持
-
能够轮询 SCM 系统
-
能够与单元测试框架解决方案如 Junit、Nunit 等集成
-
基于角色的访问控制
-
能够显示已构建的仓库的最新提交的变更列表
大多数持续集成构建服务器还将支持其他功能,例如:
-
拥有可编程的 API 或 SDK
-
提供电子邮件或消息集成功能
-
与 Active Directory 或 LDAP 集成,实现基于角色的访问控制
-
支持与变更管理工具的集成,其中可以将 SCM 提交与变更票证关联
-
支持与同行评审工具的集成
网络持续集成
那么为什么网络工程师应该关注持续集成呢?如果网络团队希望改善以下几点内容,他们应该关注持续集成,这些内容在第三章《将 DevOps 引入网络运营》中有详细讲解,将 DevOps 引入网络运营:
-
变更速度
-
平均解决时间
-
提升的正常运行时间
-
部署次数增加
-
团队间的跨技能培训
-
取消单一故障点
持续集成带来的一个优势是,能够轻松追踪网络上发生了什么变化,并查看是哪个工程师做了变更。通过查看持续集成构建系统中的最新提交,可以获得这些信息。
回滚将像部署最后一次标签发布配置一样简单,而不是在发生错误时需要翻阅设备日志,查看网络设备上应用了哪些变更。
每个网络工程师都可以查看持续集成构建系统中的工作配置,了解其操作方式,这样每个网络工程师都知道流程是如何运作的,从而有助于技能的交叉培养。
拥有持续的反馈循环将使网络团队不断改进流程。如果某个网络流程不尽如人意,网络团队可以轻松地突出流程中的痛点,并在变更过程对所有工程师可见且一致的方式下进行修复。
当网络团队使用持续集成流程时,网络团队将摆脱应急处理模式,进入战术性的持续改进和优化模式。持续集成意味着网络变更的质量将得到提升,因为每次网络变更都有相关的验证步骤,这些步骤不再是手动的并且容易出错。
相反,这些检查和验证是内建的,并且每次网络操作员提交网络变更到 SCM 系统时都会执行。这些变更随着时间的推移积累,使得网络变更更不容易出错,并且赋予网络工程师与开发人员和基础设施团队相同的能力。
利用网络持续集成还消除了进行生产变更的恐惧,因为这些变更已经在持续集成过程中得到了验证和确认,因此生产变更可以视为一种日常业务活动,而不需要提前几周计划或担心。其理念是:如果某项活动存在问题,那就更频繁地进行它,不断迭代,改进,并让人们不再害怕去做。
已经涵盖了不同的 SCM 分支策略、持续集成构建服务器等主题,并展示了如何将持续集成用于代码和数据库变更,现在应该能清楚地理解什么是持续集成,并明白它不仅仅是代码的编译。相反,持续集成是验证并行变更,确保它们能够协同工作,并为用户提供反馈循环。
DevOps 运动强调与他人互动、消除瓶颈、加速产品上市并提高准确性,因此持续集成同样适用于网络。自动化流程以及团队之间基于类似概念的协作至关重要,因此持续集成确实是将基础设施和网络作为代码结合在一起的纽带。
对于网络工程师来说,像持续集成这样的概念一开始可能显得陌生,但与其讨论深度编译过程,不如聚焦于流程。如果询问任何网络工程师,是否能拥有一个快速且易于使用的流程来验证所有网络变更,确保在生产前进行验证并提供快速反馈回路,那么答案必定是肯定的。因此,持续集成可以成为一个有用的工具,减少生产环境中的问题变更。
本书中,在第四章,使用 Ansible 配置网络设备,第五章,使用 Ansible 编排负载均衡器,以及第六章,使用 Ansible 编排 SDN 控制器,我们探讨了如何将网络变更视作代码,并使用像 Ansible 这样的配置管理工具来配置网络设备、负载均衡器和 SDN 控制器。
因此,在考虑以下图示时,关于网络变更的持续集成问题并非是在问网络变更是否可以进行持续集成,而是应该在询问,在 SCM 提交后,哪些验证引擎可以用于网络变更,以便为网络操作员提供通过或失败的快速反馈回路:

网络验证引擎
创建网络变更的持续集成构建时面临的挑战是使用什么作为验证引擎。使用 Ansible 进行网络变更时,依赖于 YAML 配置文件,因此可以首先进行的验证是检查 YAML var文件的有效性。
var文件用于描述网络的期望状态,因此检查这些 YAML 文件在语法上的有效性是一个有效的检查方式。为了实现这一点,可以使用如yamllint这样的工具来检查提交到源代码管理中的文件语法是否有效。
一旦 YAML 的var文件被提交到源代码控制系统,持续集成构建应创建一个标签,标明已发生新版本发布。所有源代码管理(SCM)系统应该都具备标签或基线功能。
打标签版本意味着当前网络发布版本可以与先前版本进行对比,以查看 YAML var文件中有哪些文件变更。如果在任何阶段发现问题,所有网络变更都会变得透明。
那么,其他可能的验证是什么呢?当关注网络设备的配置时,我们将配置更改推送到一个网络操作系统,如 Juniper Junos 或 Arista Eos。因此,能够运行新提交的更改,并确保语法在这些操作系统中是程序 matically 正确的,作为持续集成过程的一部分是非常理想的。如第四章 《使用 Ansible 配置网络设备》所述,大多数网络设备操作系统都是基于 Linux 的,因此,作为 CI 过程的一部分,拥有一个网络操作系统来发布命令似乎并不荒谬。
同样的情况也适用于检查用于编排负载均衡器或 SDN 控制器的配置,理论上,附加一个测试环境到持续集成过程中也是非常可取的。通过利用负载均衡器的软版本或 SDN 控制器的仿真版本将是非常有益的,这样网络工程师就可以在实施前检查他们的网络更改,确保 API 调用和语法正确。
然而,模拟 SDN 控制器或创建或模拟生产环境存在一些挑战,取决于供应商,他们可能会因为成本问题,在设置持续集成环境时面临巨大的开销。网络设备、负载均衡器和 SDN 供应商正在发展,以支持自动化和 DevOps 友好的流程,如持续集成。因此,网络供应商开始意识到提供小型测试环境的有效性;这就是虚拟化或容器化的负载均衡器或 SDN 控制器版本作为 API 端点来验证在 YAML 文件中设置的期望状态的地方。
另外,供应商可以提供一个 vagrant box 来测试在 YAML var文件中指定的期望配置是否有效,这些文件被检查到 SCM 系统中,然后再将其传播到第一个测试环境。在开发生命周期中,任何能够加速失败并尽可能将问题向左移动的过程增强都应该在可能的情况下实施。
所以,利用所有这些验证器,我们来看一下这些过程如何应用于网络设备,或者交替使用编排。所使用的验证器数量可能取决于所用的网络供应商,因此我们将首先看看一个针对网络设备的持续集成构建的起点,无论供应商如何,然后再看一些更高级的选项,这些选项可以在供应商提供软件负载均衡器或 SDN 仿真时使用。
网络设备的简单持续集成构建
由于大型组织在实施微服务应用程序时通常需要每天进行网络更改,因此为了满足这些需求,网络应尽可能自助服务。为了跟上需求,网络团队可能需要使用特性分支 SCM 策略,或者允许直接将自助服务 YAML 文件提交到主分支,如下图所示:

每次提交应在合并之前进行同行评审。理想情况下,自助服务流程应允许开发团队将网络更改与他们的代码更改一起打包,并遵循自助服务方法。
第一个应该为网络设备或编排设置的持续集成构建应专注于版本控制 Ansible YAML 文件,并对期望状态运行简单的 YAML 验证。
每次运行的持续集成构建还将标记仓库。标记 SCM 仓库意味着可以比较发布版本,或轻松回滚。它还将作为审计日志,显示哪个用户进行了更改,以及在环境中具体更改了什么。未经持续集成过程的更改不应应用于生产系统。
因此,一个简单的网络持续集成构建将遵循以下简单的验证步骤:
-
对 YAML 文件进行语法检查。
-
如果成功,仓库将在 SCM 系统中被标记。
因此,一个简单的网络持续集成构建将遵循以下步骤。网络操作员将把 YAML 文件提交到 SCM 系统,以更改网络的期望状态;如果 YAML Lint 操作发现仓库中的所有 YAML 文件具有有效的语法并返回正面结果,则持续集成构建服务器将标记该构建:

配置一个简单的 Jenkins 网络 CI 构建
这个简单的网络设备持续集成构建可以在 Jenkins CI 构建服务器上设置。Rake 和 yamllint gem 应该在将要执行构建的 Jenkins 从属机上进行配置。
一旦完成这些步骤,新的 Jenkins CI 构建可以在几分钟内创建。
首先,选择一个新的 Jenkins 自由风格作业:

然后配置 SCM 系统,在本例中使用 Git,指定 git@gitlab:devops/sdn.git 作为仓库,并指定项目的 */master 分支以及提供访问仓库所需的 SSH 密钥:

现在进行验证步骤,选择一个 shell 命令构建步骤,该步骤将在配置了 Rakefile 的 git@gitlab:devops/sdn.git 仓库中运行 rake yamllint,以便可以解析 YAML 文件:

最后,配置构建任务,以便将 Jenkins 构建版本标记到devops/sdn.git gitlab 仓库,并保存构建:

这配置了一个非常简单的 Jenkins CI 构建流程,它将轮询 Git 仓库以获取新变更,对仓库运行yamllint,然后在构建成功后标记 Git 仓库。
构建健康状态将在 Jenkins 中显示;绿色圆球表示构建处于健康状态,YAML 文件当前状态良好,检查持续时间显示执行构建花费了 6.2 秒,如下截图所示:

在网络持续集成构建中添加验证
在强调了需要更强大验证以确保网络设备的预飞行配置,并将故障尽可能地提前到开发生命周期的早期以减少修复成本之后,能够将任务关键型配置更改推送到网络操作系统(如 Cisco Nxos、Juniper Junos 或 Arista Eos)将是一个很好的持续集成验证。
因此,就像数据库验证 SQL 语法是否正确一样,能够运行新提交的更改,并确保应用到网络设备的网络命令或编排命令语法在程序上是正确的,应该成为持续集成构建的一部分。
随后,持续集成可以帮助提升网络变更的质量,因为错误的变更永远不会被推送到网络设备、负载均衡器或 SDN 控制器。当然,推送的配置功能可能不是所需的,但至少不会出现配置在部署时有语法错误的情况。
由于网络设备、负载均衡器和 SDN 控制器的变更是任务关键型的,这为任何网络变更和检查带来了额外的验证检查,并以快速、自动化的方式提供反馈,如果网络变更不符合要求,能够快速反馈。
网络设备的持续集成
在设置网络设备之前,需要进行一些前提条件的持续集成:
-
需要一个网络操作系统,并将生产配置推送到该系统,以及所有实时设置,这些可以托管在虚拟设备上
-
像 Jenkins 这样的持续集成构建工具需要在代理上设置 Ansible 控制主机,以便它能够执行 Ansible 操作手册
-
所有操作手册应该编写带有块状回滚机制,以便在操作手册执行失败时,后续的清理工作能够自动进行
一个典型的网络设备发布流程将包括以下两个步骤:
-
应用网络变更自服务操作手册。
-
由于操作手册是幂等的,只有发生更改时才会显示变更。
Ansible 操作手册应提供对状态更改的前进和回滚的弹性。之前的步骤还使用 Ansible 操作手册检查了顺序的有效性,并检查了对网络设备的调用是否有效。
一个简单的持续集成网络构建过程将为网络操作员提供以下反馈循环:
-
网络操作员将 Ansible 操作手册或 YAML
var文件的更改提交到SCM 系统,并与代码库集成。 -
代码库被拉取到CI 构建服务器。
-
使用
yamllint检查 YAML 文件。 -
Ansible 操作手册应用于将网络更改推送到设备。
-
返回通过或失败的退出条件并反馈给用户。
-
对下一个网络设备更改重复步骤 1-5:
![网络设备的持续集成]()
网络编排的持续集成构建
在为负载均衡器或 SDN 控制器设置网络编排之前,需要一些先决条件:
-
需要一个软件负载均衡器或模拟的 SDN 控制器,并将生产配置推送到其上以及所有实时设置。
-
像 Jenkins 这样的持续集成构建工具需要在代理上设置一个 Ansible 控制器,以便它可以执行 Ansible 操作手册,以及可以执行网络编排模块的 SDK。
-
所有操作手册应编写块级回滚,以便在操作手册执行失败时能够进行后续清理。
一个典型的网络设备发布过程将包括以下步骤:
-
将网络更改应用到自服务操作手册中。
-
由于操作手册是幂等的,只有在发生更改时,才会显示更改。
类似于网络设备更改,Ansible 操作手册应提供对状态更改的前进和回滚的弹性。可能需要在虚拟化平台上设置一些测试服务器,以模拟负载均衡,以便也能测试健康检查。
一个简单的持续集成网络编排持续集成过程将为网络操作员提供以下反馈循环:
-
网络操作员将 Ansible 操作手册或 YAML
var文件的更改提交到SCM 系统,并与代码库集成。 -
代码库被拉取到CI 构建服务器。
-
使用
yamllint检查 YAML 文件。 -
一个 Ansible 操作手册被应用于编排 API 并创建必要的负载均衡器或 SDN 更改。
-
返回通过或失败的退出条件并反馈给用户。
-
对下一个网络编排更改重复步骤 1-5:
![网络编排的持续集成构建]()
总结
在本章中,我们了解了持续集成是什么,以及如何将持续集成过程应用于代码和数据库。随后,本章探讨了如何将持续集成应用于网络操作,以提供反馈循环。
我们还探讨了不同的 SCM 方法论,集中式和分布式 SCM 系统的区别,以及如何在瀑布式和敏捷过程中使用分支策略。
然后,我们深入研究了用于创建持续集成过程的各种工具,重点展示了使用 Jenkins 设置简单网络持续集成构建的一些例子。
在这一章中,你学习了什么是持续集成,如何将其应用于网络操作、SCM 工具,以及集中式和分布式系统之间的差异,另外还介绍了常见的 SCM 分支策略。
本章的其他关键要点包括持续集成构建服务器及其用途,如何将网络更改集成到持续集成中,以及可能的持续集成验证引擎用于网络更改。
在下一章中,我们将了解各种测试工具以及它们如何应用于持续集成过程,以提供额外的验证。这将允许为网络操作创建单元测试,以确保在部署网络更改到持续交付流水线之前,所需的状态已经在设备上实现。
第八章:网络更改测试
本章将重点介绍软件开发生命周期、DevOps、测试和质量保证中的一个重要部分。将描述为什么将网络更改纳入持续集成过程并彻底测试它们至关重要。接着,我们将研究可用于帮助创建网络操作测试套件的开源测试工具。
本章将重点讨论整体质量保证过程,概述一些网络团队或实施网络操作团队可以采用的最佳实践方法。
我们还将探讨实施反馈循环、质量报告的好处,以及可以实施哪些检查以确保网络按预期运行。这些都是网络团队向代码驱动的网络操作过渡时的关键话题。
本章将涵盖以下主题:
-
测试概览
-
质量保证最佳实践
-
可用的测试工具
测试概览
有很多方法可以确保在进行操作或开发更改时保证质量。
当结合质量检查并对其进行排序时,它们可以用来形成一套质量门控,开发、基础设施甚至网络更改在到达生产环境之前应通过这些质量门控。我们将简要介绍一些常见的测试策略,这些策略用于确保系统或应用程序的任何更改都能有效运行,包含以下测试阶段:

单元测试
最流行的质量保证类型之一是单元测试。单元测试将测试每个独立的代码操作,并确保每个方法或函数在不同的输入下表现出预期的行为。
一个或多个单元测试是确保方法或函数按预期工作的必要条件。因此,可能需要编写多个单元测试来测试任何基本操作,基于一个独立操作验证通过或失败。
单元测试通常可以在已编译的二进制文件上进行,而不需要完整的测试环境。利用流行的测试框架,单元测试可以根据输入来验证通过或失败。
例如,对 Apache Tomcat Web 服务器的单元测试可能包括确保代码能够在 HTTP 端口 8080 上处理流量:

组件测试
组件测试涉及隔离地测试单一组件,并确保其作为自包含实体表现出应有的行为。
组件测试通常涉及将应用程序部署到测试环境,并对该组件执行一系列测试,测试其所有特性和功能。微服务应用程序是每次发布时都需要进行测试的小组件。
这可能涉及确保银行应用程序能够根据特定类型的账户正确处理交易。
集成测试
集成测试涉及多个微服务组件,因此,如果两个不同的组件被集成,就需要编写一组集成测试,确保它们都能集成并表现出预期的行为。
集成测试通常需要模拟一个数据库架构或多个组件,并在环境中一起部署和测试。虽然单元测试可以断言构建的二进制文件的行为,但集成测试要稍微复杂一些。
可以通过模拟或存根来模拟另一个应用程序的端点行为,并验证其是否按预期工作。
集成测试可以测试两个不同的微服务端点是否可以连接,并且像 TCP 握手这样的交易能否在发起方服务和接收方服务之间正确完成,通过接收 ACK 来确保两微服务应用程序之间的双向 TCP 握手正常工作:

系统测试
系统测试通常在一个完整的环境中进行,所有组件都已完全部署。系统测试将测试整个系统,通常作为生产前的最后一步进行。一些可以进行的测试包括用户旅程测试,例如设置一个完整的交易。这测试了完全集成的系统是否能通过所有的端到端测试,就像客户在生产环境中使用它一样。
这可能涉及将多个微服务应用程序集成在一起,例如微服务A、B、C和D,并确保它们能够在功能上集成并作为一个整体工作:

性能测试
性能测试是相当直观的,它会在第一次执行时为应用程序的性能设定基准。然后,它会使用该基准来检查每次新版本发布时应用程序是否有性能下降。
性能测试将用于检查性能指标,这对于查看代码提交是否导致系统整体性能问题非常有用。性能测试可以纳入系统测试阶段。
另外,性能测试也可以意味着压力测试或负载测试应用程序、网络或基础设施的极限,并通过编写测试来检查系统是否能够应对预期的流量模式。
耐力测试是指设定一个测试时间段,看看基础设施、网络或应用程序在固定时间内能承受多大的压力。
峰值测试是确保系统能够应对从低谷流量模式中突然激增的流量,测试系统是否能够处理高度变化的流量。
可扩展性测试另一方面可以意味着水平扩展基础设施或增加更多应用程序,直到达到没有性能提升的程度。这可以识别系统的扩展极限。
负载测试可以用来查看一个系统在给定时间内可以处理的事务或数据量。
下图展示了属于性能测试范畴的不同测试类型:

用户验收测试
用户验收测试涉及让最终用户测试新特性或功能。用户验收测试通常用于确保客户或产品经理对已经做出的开发更改感到满意。这种类型的测试通常是探索性的,并且相当手动。它通常用于测试网站或图形用户界面的外观和感受。
为什么测试对网络团队很重要?
质量保证是网络或基础设施更改的重要部分,它不仅仅是软件开发的问题。如果软件安装的网络或基础设施没有按预期运行,那么它将产生与软件漏洞相同的客户影响。
客户不会区分软件漏洞、基础设施或网络问题。客户只知道他们无法使用产品,并且在他们看来,企业没有满足他们的需求,也没有提供良好可靠的服务。
没有足够的测试对企业非常有害,因为企业的声誉可能会受到损害,而且社交媒体的兴起意味着,如果网站出现故障或无法正常运行,几乎一瞬间,停机信息就会在社交媒体平台上广泛传播。
如果有一个用户注意到问题,他们可以发推文,这会提醒其他客户注意到这个问题,一条推文变成多条,等到公司反应过来时,故障已经在 Twitter 或其他社交媒体上成为热议话题,现在全世界的人都知道该企业有问题。
这种情况是许多在线企业最担心的,如果网站无法上线、无法正常运行并提供良好的用户体验,那么企业就不再赚钱,客户可能会转向竞争对手。
任何开发、基础设施或网络团队的关键目标之一是为最终用户提供良好的服务,防止停机或故障。通常,使用一组关键绩效指标(KPIs)来量化性能,并设定目标,以判断企业是否满足客户需求。
因此,使网络变更的交付减少出错的可能性应该是任何网络团队的目标。在第四章,配置网络设备使用 Ansible,第五章,使用 Ansible 管理负载均衡器,以及第六章,使用 Ansible 管理 SDN 控制器中,我们研究了如何使用配置管理工具自动化网络设备、负载均衡器和 SDN 控制器。同时,拥有一套可重复执行的测试来验证任何网络变更,应该也是网络团队努力的目标。理想的场景是,网络团队在变更实施之前,就知道该变更会失败,而不会对客户产生影响。这意味着在批准变更之前,充分进行测试,并尽可能快地在测试环境中发现问题,以避免破坏性变更直接推送到生产环境。
网络工程师在初步转向自动化流程时,常见的担忧之一是对自动化缺乏信任。网络工程师习惯于在发布网络变更之前,进行尽职调查和一系列检查。仅仅因为实施了自动化,并不意味着网络工程师用于验证网络变更的手动检查清单就不再需要。
然而,考虑到软件交付时,整体流程的速度取决于最慢的环节,因此如果这些网络验证检查仍然是手动的,那么整个流程就会变慢。这将导致在自动化过程中插入手动步骤,最终不可避免地会拖慢新产品的交付速度。
简单的解决方案是自动化每一项网络检查清单,这样原本由网络工程师手动执行的验证就会变成一个自动化检查或测试,成为与自动化一起运行的自动化测试套件的一部分。
这些检查或测试是在一段时间内编写和构建的。所以,当发现边缘案例并且没有测试覆盖,导致失败时,应该采取的做法不是使用“自动化无法工作”的论点,并为恢复到经过验证的手动方法提供理由,而是网络工程师应该创建一个新的测试或检查,并将其添加到自动化验证包中,以便在问题影响最终用户之前,在测试环境中捕获并失败。
当前的网络变更与测试
网络团队仍然主要使用瀑布式方法,因此他们需要调整并采用更灵活的方法。这将使网络团队能够更好地与其他 IT 团队进行整合,成为持续交付过程中的参与者,而不仅仅是旁观者。
当瀑布方法成为交付软件开发项目的标准方法时,将会遵循一个非常严格的过程生命周期。
瀑布流程规定每个新特性将经历以下阶段:
-
分析
-
设计
-
实施
-
测试
瀑布方法的主要实施之一是V 模型,最初用于将项目简化为可交付的块。这意味着所有利益相关者都可以识别进展并寻找潜在的延迟。
这种简化使得项目经理和高层管理人员非常高兴,因为他们有一种简单的方式来跟踪项目进度,并判断是否按时完成或超出预算。
V 模型的结构如下所示:

在瀑布模型中,分析和设计阶段位于 V 模型的左侧,并会在过程开始时进行。简而言之,V 模型的左侧用于与利益相关者互动,进行必要的研究,并收集所有必要的高层和低层需求,以明确实现新产品或变更所需的内容。V 模型的左侧还涉及在架构层面记录整体过程。
在分析阶段完成初步需求收集后,分析阶段会签署结束,这意味着架构设计阶段可以开始,并对需求进行详细规划。作为设计阶段的一部分,将创建高层和低层设计文档,记录拟议的更改,并进行相关的审查、签署和批准流程。
一旦设计完成,V 模型的左侧也就完成了,变更或产品的实施将开始。实施阶段可能需要数周甚至数月时间才能交付所需的结果,并且这一生命周期阶段位于 V 模型的底部。
一旦所有需求实现完成,实施阶段将被签署结束,项目将进入 V 模型的右侧,测试阶段将开始。
然后,测试团队将对任何更改或新产品特性进行单元测试、集成测试,最后进行系统测试。实施阶段发现的任何问题都会导致变更请求。这意味着高层或低层设计需要更新,实施工作需要重新进行,然后测试需要重复或重新编写,以便对产品进行精炼。
随着在第三章中讨论的敏捷开发的推进,将 DevOps 引入网络运营,V 模型已被认为是一种次优的交付机制。从报告的角度来看,V 模型是理想的和透明的,但这意味着实施过程受到对工程师施加的严格限制。
V 模型没有考虑到工程师喜欢迭代过程的事实,而且他们在开始一个过程时写下的实际实现可能不是他们最终实施的设计。V 模型与原型制作的契合度较差,因为工程师通常喜欢花时间与系统互动,尝试、失败、迭代,然后改善实现。
不考虑原型制作会导致多个变更请求,这对企业带来成本影响,因此,在敏捷方法中使用两周的迭代开发周期来计划迭代开发被证明更为现实。尽管这仍然是高级经理们的一个难题,因为他们习惯了需要报告截止日期和里程碑,而截止日期在所有实际情况中不过是一个虚拟的日期。
在瀑布过程中,工程师仍然会进行相同数量的原型制作以交付实施,工作所需的时间是x,无论计划如何结构化。敏捷开发只是结构化以接受原型制作和时限内的突发工作。
所以,项目经理对工程师的老生常谈问题总是;这什么时候完成? 作为回答的“我不知道”在瀑布模型中是不可接受的。期望的是一个估算,或者在工程圈里是一个虚拟的日期,而项目经理很可能会在该日期未能完成时进行更改。
那么,这一切与网络变更和测试总体上有什么相关性呢?嗯,今天的网络团队通常在考虑进行网络变更时会实施一个迷你 V 模型。网络经理会充当项目经理,规划设计、实施和测试阶段的周期,并将其反馈给高层管理团队,因为网络变更被视为需要大量规划和测试才能实施的大型工作。
网络经理可能不会像传统方法那样将测试拆分为测试、集成和系统测试,因为网络测试通常没有这么复杂,但这并不允许网络工程师进行原型制作。
相反,网络工程师,像基础设施工程师或他们之前的任何运营团队一样,将被迫在一个严格的计划中做出改变。这个计划将体现以下标准的满足:
-
实施的变更是否按预期工作?
-
变更是否破坏了任何东西?
-
文档是否已更新以反映变更?
如果满足所有这些点,网络团队会认为这是一次成功的变更。
然而,这并没有讲述完整的故事,因为在持续交付模型下进行网络更改时,还需要考虑其他几个方面:
-
这个更改会破坏任何看不见的部分吗?
-
相同的更改是否也已在预生产环境中实施?
-
相同的更改是否已在预生产环境中进行了测试和验证?
前面提到的三个点是进行任何更改时的强制性要求,但剩下的三个点也应视为强制性要求,以维持成功的持续交付模型。这对网络工程师来说是一个思维方式的转变,他们需要在进行更改时将这些因素考虑在内。
网络工程师进行的所有网络更改都需要提交到源代码管理系统,并在推送到生产环境之前,通过所有必要的环境进行传播,如下图所示:

如果网络工程师直接手动在生产环境中进行更改,而没有先通过自动化在测试、预生产和生产环境中实施,那么测试环境中的网络配置将永远与生产环境不一致。这将导致严重的后果,因为测试、预生产环境和生产环境的配置将会逐渐偏离。
这意味着任何开发人员、基础设施人员或网络工程师,如果在使用测试和预生产环境时,期望它们是生产环境的副本以进行关键任务更改,将会感到失望。反过来,这也可能会影响在这些环境中运行的任何测试,因为它们不再能准确反映生产环境的状态。
那么,实践中这意味着什么呢?V 模型中的系统测试框可能在预生产环境中通过,但在生产环境中失败。这无法增强对持续交付过程的信心,而持续交付现在是业务中至关重要的部分。
无法过分强调,在进行任何网络、代码或基础设施更改之前,确保所有更改都推送到预生产环境,以保持所有环境的有效性。这一点对于网络工程师而言是一个心态转变,他们在做更改时需要考虑这一点。
这不仅用于测试更改,还用于保持预生产环境作为生产环境的缩小版镜像,从而避免所有测试在测试环境中通过,但部署到生产环境后却导致客户停机的情况。因此,这意味着,在将更改发布到生产之前,必须在相关的测试环境中完成所有验证测试。
如果手动更改直接推送到生产环境,即使是紧急情况,也需要立即将更改提交回源代码管理系统(SCM),源代码管理系统应始终作为所有配置的唯一真实来源。
如果应用了任何手动更改,雪花环境将变得普遍,具体表现如下。这里是指工程师在生产环境中进行了手动更改,但未通过部署流水线将更改推送到其他环境中:

为了使网络变更能够按预期的速度交付,网络变更和测试不能继续采用迷你 V 模型策略。如果网络团队和管理人员真心希望在持续交付模型和 DevOps 模型中进行协作,他们需要跟上开发和基础设施团队在敏捷变更方面的步伐。
然而,解决方案并不是停止验证更改和进行应有的尽职调查,而是从那些多年来成功应用于开发和基础设施变更的规范化质量保证流程中汲取经验,这些流程同样也能帮助测试网络变更。
质量保证最佳实践
质量保证团队在采用瀑布式 V 模型交付结构时,通常处于信息孤岛,只在开发团队完成后回顾性地测试开发变更。
这导致质量保证团队不得不对每个开发变更作出反应,因为他们需要为一个自己还没有见过的功能编写测试,或者理解该功能是如何完全运作的。这种情况经常发生,开发人员会在没有预警的情况下将功能提交到源代码管理系统,随后质量保证团队需要对其做出反应:

这种工作方式带来了许多挑战,例如:
-
开发人员更改了用户界面,因此质量保证团队的自动化测试失败了,因为测试工程师未意识到用户界面发生了变化。
-
测试工程师不了解新功能,导致没有编写适当的测试来正确地测试功能。
-
开发人员不得不花大量时间向质量保证测试人员解释功能是如何工作的,以便他们能够在提交后编写测试。
-
修复断裂的回归测试时的延迟,这些问题并不是由错误导致的,而是测试本身的问题。
-
质量保证团队以完全被动的方式行事,因为他们无法看到开发人员即将进行的更改。
-
质量保证包未通过测试,或者测试结果显示“通过”,意味着实际的软件问题会被漏掉。
因此,在考虑网络测试时,解决此问题的方法不是雇佣一个单独的测试团队。相反,它是将网络测试融入并整合到持续交付模型中。
敏捷开发表明,在编写代码更改的同时,将质量保证测试工程师嵌入到开发团队中意味着可以在提交前编写测试。这是一种更高效的工作方式。
将质量保证工程师从孤立的质量保证团队中调出,并让他们与开发人员一起在同一个 scrum 团队中工作,这意味着团队成员可以协作,确保提交的变更在每个阶段都能正常工作。
相关的回归测试、集成测试或系统测试将形成一组自动化的质量门控,变更将通过这些门控传播:

相较于使用传统的瀑布式方法,敏捷测试方法的主要优势是:
-
质量保证测试人员不再被动工作,而是完全能看到开发人员正在创建的内容。
-
每个敏捷用户故事可以编写适当的接受标准,其中包括自动化测试,允许质量保证工程师在开发人员编写新特性时进行测试任务。
-
当新特性被编码时,相关的测试会为新特性编写
-
新特性测试可以添加到回归测试包中,以便每次代码提交时都会进行该特性测试。
这一过程变更消除了障碍,即团队结构,并将两个团队结合起来,使得它们变得更加高效,这本质上是 DevOps 方式。
创建测试反馈循环
如果我们回顾一下第七章中的持续集成过程,使用持续集成构建进行网络配置,我们会发现有提交过程。提交基本上启动了整个持续交付过程。一旦提交发生,变更就已经开始进入生产流程。对主干/主线/主分支的任何提交都是最终变更,因此如果进行网络提交,它已经在向生产环境推进的过程中。
如果在检查后没有验证引擎或测试存在,那么变更会一直流经测试环境,直到到达生产环境。

这意味着利用具有适当测试门控的反馈循环至关重要,因此一旦代码提交发生,它将得到充分的测试,并提供即时指示,表明变更失败。一旦所有质量门控成功完成,变更才应该被提升到生产环境,这种模型促进了持续改进和快速失败。变更失败发生得越早,对业务的成本越低。
持续集成测试
在第七章中,使用持续集成构建进行网络配置,我们重点讨论了持续集成的过程以及如何将多种不同的检查作为验证引擎的一部分应用于用户提交。这确保了用户提交始终得到正确验证。
持续集成提供了一套反馈循环,其中代码提交到 SCM 后,验证引擎将返回通过或失败的结果。所有测试都可以构成更改的验证引擎:

当持续集成过程应用于开发时,采用的方式是将所有更改提交到Trunk/Mainline/Master分支:

新的开发功能将提交到Trunk/Mainline/Master分支。这个新的提交将被编译并立即与其他代码库集成,随后将执行单元测试,以检查构建二进制文件是否通过,如下图所示:

使用提交到Trunk/Mainline/Master的持续集成方法依赖于团队的纪律性。如果提交失败,且CI 构建服务器返回构建失败,那么做出失败提交的团队成员有责任立即修复构建,方法是回滚或修复破坏的提交。
在任何情况下,持续集成构建都不应处于失败状态,因为这意味着Trunk/Mainline/Master分支不处于干净状态,所有后续的代码提交将在构建修复之前无法进行有效的持续集成。这会减慢团队的生产力,因此持续集成是一个协作过程,失败应该视为一个学习的机会。
分支上的门控构建
另一种流行的方法是使用功能分支和门控构建。每当开发人员进行更改时,他们将提出一个合并请求,该请求将由团队的其他成员进行同行评审,然后再合并。
每当合并请求被接受时,它将启动合并过程,但作为合并过程的一部分,将执行一个称为门控构建(gated build)的过程。

在合并发生之前,会调用门控构建过程,并与Trunk/Mainline/Master集成。它将作为预提交运行等同于持续集成构建的过程,但只有在预提交构建的构建和单元测试通过时,合并请求的内容才会合并到Trunk/Mainline/Master分支。
门控构建过程意味着Trunk/Mainline/Master分支始终保持完全干净和功能正常。纯粹的持续集成可能会让开发人员破坏持续集成构建,而门控构建通过确保测试通过来防止这种情况发生。
将质量保证最佳实践应用于网络
网络团队可以通过采用一些最佳实践和经过验证的测试方法,极大地受益于测试开发或基础设施更改。
质量保证完全关乎原则和流程,因此测试方法论是相对中立的,实施这些流程的工具是次要的。
当团队在持续交付模型中工作时,对网络设备、负载均衡器,甚至是 SDN 控制器的任何变更都应该使用源代码管理工具定义,并通过像 Ansible 这样的编排和配置管理工具来进行。
在持续交付模型中,网络变更需要通过环境进行传播,并始终受到源代码管理系统的控制,源代码管理系统的状态就是网络的状态:

网络变更可以像代码变更一样处理,充分的测试可以作为网络团队的倡议创建,或通过与质量保证团队的合作来完成。每个阶段的测试类型可能与开发或基础设施团队在部署管道中运行的测试集略有不同。
然而,可以衍生出等效的网络特定测试,创建一套健全的测试,确保网络变更在部署到生产环境之前必须通过每个质量门控,通过将特定的网络测试与部署管道中的每个质量门控关联。
网络团队,如开发和基础设施团队,需要创建一套反馈循环来管理网络变更,以便在部署管道中执行不同类别的测试。
所有测试应理想地作为每个网络变更的一部分自动化,以一种主动的方式进行,并在网络变更排定时同时编写。这将使网络变更在开始时就可以以自动化的方式进行测试:

在设置持续集成时,选择持续集成或受限构建策略取决于网络团队或提交变更的工程师的偏好。
单元测试应该与网络持续集成过程集成。网络操作员首先会提交代码变更或更改网络状态。
CI 构建服务器将使用 Lint 检查 Ansible var YAML 文件,确保 YAML 文件的语法有效。
如果有效,则将在任何下游环境中执行的相同 playbook 会在 CI 测试环境中执行,以确保 playbook 在语法和执行方面成功。
最后,一组单元测试将在环境中执行,以验证在执行完 playbook 后,环境的功能和期望状态。

需要注意的重要事项是,单元测试作为持续集成过程的一部分执行,这些测试可以是合并请求验证的一部分,或者在提交到Trunk/Mainline/Master分支时执行。
将网络测试分配到质量门控
在查看网络团队可以进行哪些类型的测试以验证网络更改时,这些测试可以分为不同的测试类别,并分配到不同的质量门控。
本章涵盖的一些主要测试环境包括:
-
单元测试
-
集成测试
-
系统测试
在考虑将测试放在哪里之前,我们应该首先了解网络团队的需求。在一张空白画布上,哪些测试集对网络操作有益?
以下是一些想到的测试,但任何对特定团队有效的检查或验证都是适用的,应该包括在内:
-
网络工程师在进行更改时手动执行的网络检查清单
-
对网络自动化进行单元测试,以确保网络设备处于期望的状态
-
测试网络性能,查看期望的吞吐量,并测试网络部分在过载时是否需要扩展
-
测试网络设备的故障切换
-
测试网络代码质量
-
测试通过网络的不同用户旅程
-
测试服务质量
所有这些类型的测试可以分配到特定的测试环境,并创建质量门控:

可用测试工具
测试工具,像所有工具一样,应该用于促进测试过程和结果。因此,对于每一个测试质量门控,都需要工具来包装过程、安排和执行测试。
市面上有各种测试工具,网络工程师使用它们可以大大受益。
单元测试工具
如前所述,网络单元测试将成为持续集成构建过程的一部分,并由持续集成构建服务器安排。
一个可以帮助进行网络更改单元测试的开源工具是 Test Kitchen。Test Kitchen是一个单元测试工具,利用 Busser 框架,可以用于进行基础设施测试。Test Kitchen 支持许多测试框架,如Bats和RSpec。
Test Kitchen 的 Busser框架由以下架构组件组成:
-
驱动程序
-
配置工具
-
平台
-
套件
Test Kitchen 通过一个kitchen.yml文件定义其所有插件,该文件概述了用于测试的驱动程序、配置工具、平台和套件。
驱动程序可以是任何可以用于提供虚拟机或容器的平台。Test Kitchen 支持 Vagrant、Amazon、OpenStack 和 Docker,因此可以用于测试基础设施更改。
Provisioner是一种配置管理工具,如 Ansible、Chef、Puppet 或 Salt,用于将服务器配置为需要测试的状态。
Platform是 Provisioner 将执行操作的操作系统。可以为跨操作系统测试指定多个平台。当测试新版本的网络操作系统时,这非常有用,能够确保在进行软件升级时,这些操作系统的行为与前一版本相同。
Suites用于与 Platform 定义一起创建测试套件,因此如果定义了两个不同的平台,单元测试将以一致的方式在每个平台上执行。
使用 OpenStack 的 Test Kitchen 示例
test kitchen gem 需要预先安装在 Ansible 控制主机上。然后执行以下步骤:
-
在 Ansible 控制节点中,进入包含顶级播放器文件结构的文件夹,如下图所示:
![使用 OpenStack 的 Test Kitchen 示例]()
在这里,执行以下命令:
kitchen init –provisioner=ansible –driver=openstack这将创建一个
kitchen.yml文件和一个测试子目录。 -
接下来,需要创建
folder test文件夹,该文件夹将存储单元测试:mkdir ./tests/integration/default/bats -
然后,需要将
test kitchen文件填充上 Driver、Platform、Provisioner 和 Suites。在以下示例中:
-
Driver 被指定为 OpenStack,使用
cumulus-vx镜像,并创建 Platform。 -
镜像的大小为
m1.large,这指定了服务器的 CPU、内存和磁盘。 -
实例将在
network_team租户和qa可用区域中创建。 -
一旦启动,
configure_device.ymlplaybook 将被执行,以在第 2 步中定义的test/integration下的默认文件夹中配置网络设备。这告诉 Test Kitchen 执行的 Bats 测试的位置,用于测试设备的状态:
![使用 OpenStack 的 Test Kitchen 示例]()
-
-
每个测试可以被赋予一个唯一的名称,并使用
.bats文件扩展名,在第 2 步中创建的bats目录下定义每个单元测试:Test/integration/default/bats/unit_test.bats -
使用 Bats 编写的测试示例如下:
![使用 OpenStack 的 Test Kitchen 示例]()
这检查
eth0接口在执行时是否处于良好的工作状态。 -
最后,要执行
test kitchen,请输入以下截图中所示的命令:![使用 OpenStack 的 Test Kitchen 示例]()
Test Kitchen 将执行以下工作流:
-
在 OpenStack 中创建实例。
-
运行 playbook。
-
安装 Busser 插件。
-
运行单元测试。
-
如果所有测试通过,则销毁实例。
-
网络检查清单
如前所述,网络工程师通常会有一套手动检查清单,用来验证网络变更是否成功。
有时,这可能涉及验证用户界面是否具有所需的配置,检查自动化是否按预期工作。
与其手动进行这些检查,不如使用 Selenium 执行图形用户界面检查。
Selenium 的工作流程可以总结为测试脚本调用 Selenium WebDriver,然后创建浏览器会话以测试网站或网页:

测试脚本可以用多种语言编写,如 Java、Python 或 Ruby。
在使用 Python 编写脚本时,可以通过执行 pip install 来安装 Selenium 的 Python 版本。
由于 Selenium 是基于浏览器的,它与多个浏览器兼容,如 Internet Explorer、Firefox、Chrome 和 Safari,并进行跨浏览器支持测试。
以下截图展示了一个 Selenium 测试示例;该脚本将在 Chrome 中启动 google.co.uk,输入DevOps For Networking,然后点击 Google 上的搜索按钮:

因此,任何图形界面都可以进行屏幕抓取,例如负载均衡器或网络设备接口,以确认已输入并返回了正确的信息。如果旧的网络设备没有 API,这也会很有用。
网络用户旅程
一种好的测试方法是测试整个网络中的用户旅程。这可以通过在网络中进行点对点测试来实现。
一个网络用户旅程的好例子是测试等成本多路径(ECMP)在叶脊架构中的应用,以确保其按预期执行。
另一个测试可能是设置跨数据中心的点对点测试,以确保链路按预期工作,并且不会突然降级。
设置用户旅程测试意味着如果基线性能下降,则可以追溯到特定的网络变化,作为网络部署管道的一部分。这与应用程序性能基准测试非常相似,并确保新版本不会导致性能下降,从而影响最终用户。
网络用户旅程测试意味着如果在网络中发现性能不佳的路径,则可以快速定位并修复,从而提高问题发生时的平均解决时间。网络工程师可以使用像iPerf这样的工具,通过网络中的各个节点发送大量数据包。这可以帮助识别网络中的瓶颈,确保性能符合预期。
服务质量
现在许多网络工具提供服务质量(QoS),它允许网络运营商限制特定租户在网络中使用的带宽量。
这可以防止嘈杂的测试环境影响生产环境。由于网络设备可以为特定租户网络设定性能保证,因此这一点是可能的。这意味着某些应用程序工作负载总能保证一定的网络吞吐量,而其他不太重要的租户网络则可以在高峰期受到限制。
可以在网络设备上设置不同的阈值和告警,并且如果 QoS 在随机时刻下降,则可以检测到网络硬件故障。这还可以帮助网络工程师避免陷入老生常谈的:“我觉得我们有网络问题”。相反,他们可以证明问题是应用程序的问题,因为网络服务稳定且按预期运行,并且可以轻松显示。
最好在生产环境之外模拟和测试 QoS,并让网络团队提出不同的场景,设计最适合网络的方案,基于他们所托管的应用程序。
故障转移测试
故障转移测试 应该由网络团队定期进行测试,因为现代网络应该具备灾难恢复意识,并设计为可以容忍故障。
网络故障转移测试可以通过编写 Ansible 剧本或角色来模拟,禁用某个服务或重启交换机,确保系统能够适当地进行故障转移。
使用 delegate_to: localhost,可以通过 API 向网络设备(如交换机)发出命令,使用 API 程序化地禁用它们。或者,Ansible 可以 SSH 连接到网络设备的操作系统,并发出临时的强制重启命令。
在进行故障转移测试时,应设置补充监控,以确保网络不会丢包,并测试在初始主设备禁用后,网络设备故障转移的速度。
网络代码质量工具
在定义网络的期望状态时,请确保编写的 Python 代码以及使用的任何其他代码都具有高标准和良好的质量,以便创建 Ansible 模块。
SonarQube 是一款开源的代码质量工具,允许团队分析其代码质量。它的架构由三个主要组件组成:
-
SonarQube Runner
-
SonarQube 数据库
-
SonarQube 网络界面
Sonar 提供了一系列插件,可以配置用于提供单元测试报告、代码覆盖率或代码质量规则,并且可以为任何语言(如 Python、Java 或 C#)进行设置。
SonarQube 会在每次运行时拍摄代码仓库的快照,并存储项目在代码质量方面的历史。这些数据可以随着时间推移显示代码质量的提升或下降。Sonar 可以用来定义特定的最佳实践或规则,当提交违反这些规则时,会显示为违规。
SonarQube Runner 在运行时使用 sonar.properties 文件,该文件可以作为源代码管理系统的一部分进行包含。这个文件可以在持续集成过程中被拉取下来。这意味着在自定义 Ansible 模块进行新代码提交后,可以执行 SonarQube Runner 对代码进行测试,检查新提交的代码并查看其影响。
SonarQube Runner 将使用sonar.properties文件中规定的插件执行代码质量检查。在新或更改的 Ansible 模块的情况下,将调用特定于 Python 的代码质量测试组。分析完成后,信息将显示在 Sonar 的 Web 界面上。
该过程的工作流程如下面的截图所示,SonarQube Runner 触发整个过程:

以下截图展示了 SonarQube Python 项目仪表板的一个例子,概述了代码中需要修复的漏洞、缺陷和技术债务:

在任何公司实施持续改进模型时,跟踪代码质量和指标非常重要。因此,适当地衡量和分析代码中可以改进的地方,对于让工程师参与并编写测试至关重要。
总结
本章中,我们探讨了为什么测试网络更改是必要的。我们重点讲解了利用反馈循环持续改进网络操作的好处。接着,我们研究了网络团队在进行网络更改和测试时面临的一些挑战,以及他们如何需要适应并采纳质量保证最佳实践,以便在公司运行持续交付模型并辅以 DevOps 方法时保持竞争力。
然后我们探讨了网络团队如何为测试设置质量门,并查看了每个测试阶段可以映射的一些测试。最后,我们研究了一些可用于进行网络测试的工具,以实现单元测试、检查清单和代码质量检查。
在本章中,你学习了不同类型的测试策略,如单元测试、组件测试、集成测试、性能测试、系统测试和用户验收测试。关键要点还包括质量保证最佳实践,以及它们为何适用于网络,以及可以帮助确认自动化网络更改的不同类型的网络验证。
本章还深入探讨了可以帮助测试网络的测试工具,如 Test Kitchen(kitchen.ci/)、SonarQube(www.sonarqube.org/)和 iPerf(iperf.fr/)。
在下一章中,我们将重点关注部署管道,了解可以用来自动部署网络更改的工具。我们还将探讨持续交付和部署之间的差异,以及何时应采用每种方法。
以下博客和演示可能有助于进一步详细了解微服务测试策略:
第九章. 使用持续交付管道部署网络变更
本章将重点介绍可以用来通过部署管道部署网络变更的不同方法。
它将首先介绍持续交付和持续部署过程,并阐述这些方法论在工作流中所涉及的内容。
我们还将探讨可以用来设置部署管道的不同部署工具、工件仓库和打包方法,以及如何将网络变更集成到这些管道中的方法。
本章将涵盖以下主题:
-
持续集成包管理
-
持续交付和部署概述
-
部署方法论
-
打包部署工件
-
部署管道工具
-
使用部署管道部署网络变更
持续集成包管理
在第七章,使用持续集成构建进行网络配置,我们探讨了持续集成的过程,而在第八章,测试网络变更,我们探讨了如何将测试添加到持续集成过程中,以便在发生故障时提供更多的验证和反馈循环。
在进行持续集成时,使用快速失败/快速修复的理念是可取的。这意味着要进行必要的验证检查,以判断构建是否有效,并向用户提供反馈循环。
这促进了团队在进行频繁的小规模增量变更时保持正确的行为,从而降低了变更的风险。尽管每个变更都通过持续集成(CI)引擎进行验证,并对变更提供即时反馈,但团队始终遵循持续改进的过程,努力提供通过所有质量检查的更强健的解决方案。
提供反馈循环同样重要,而成功的构建与此过程同样重要,因为这是产品推向市场的方式。当持续集成构建完成时,通常需要打包已处于适当状态的构建工件,以便将其部署到目标服务器。这通常被称为创建可交付的产品或工件。
任何持续集成过程应执行以下步骤:
-
提交
-
构建(编译/版本控制/标签)
-
验证
-
打包
-
推送
每次发生新的提交时,都会触发一个新的持续集成构建。这将导致从 SCM 系统中拉取代码,触发构建步骤,这可以是编译过程,或者如果构建过程没有使用编译语言,则是二进制文件的版本控制或标签操作。最后,将执行一系列验证步骤,包括任何必要的测试。
如果所有验证都成功,则需要执行一系列持续集成后的步骤。构建后的步骤将包括打包和推送过程,这意味着打包构建的二进制文件并将新版本的包推送到选择的工件仓库。
下图显示了一个包含提交更改、构建(编译代码)、验证(单元测试)、打包(工件)以及推送到工件仓库的示例过程:

设置持续集成构建和打包持续集成工件时,需要记住的一个重要原则是:工件应只打包一次,而不是每次需要部署时都打包。
这是从可重复性角度看很重要的,同时也能减少部署所需的时间,因为构建过程可能很长,需要很多分钟。当构建已经打包时,所有测试和必要的验证都已经在工件上执行过,作为持续集成过程的一部分,因此,如果没有发生变化,就不需要再次重复这个过程。
我们必须确保在将工件推向生产环境之前,测试环境中部署的工件完全相同;这意味着各环境之间不会出现偏差。在不同的构建服务器上打包相同的源代码可能导致 Java 版本略有不同,甚至像环境变量不同这样的简单问题也可能导致构建的二进制文件被编译成不同的结果。
保持一致的部署工件,始终坚持“打包一次,部署多次”的原则。
包一次,部署多次的标准如下所示,其中单个工件用于初始化测试和生产环境:

为每个环境创建不同的构建工件是不可取的;发布管理的最佳实践规定,构建包和工件应包含令牌,这样就不需要不同快照的相同包。
构建包的令牌可以在部署时进行转换。所有特定于环境的信息都保存在某种配置文件中,通常称为环境文件,该文件在部署时用于填充令牌。
打包持续集成构建工件时应遵循以下最佳实践:
-
工件应打包一次并分发多次。
-
工件包应与令牌化配置文件一起打包。
-
在部署时,应该通过环境文件来转换工件包配置文件。
-
如果部署配置对所有环境都相同,可以使用公共文件来补充环境文件,从而避免重复。
以下流行的配置管理工具能够通过利用配置文件转换令牌化模板。每个配置文件都扮演着环境文件的角色:
-
Puppet
puppet.com/ -
Chef
www.chef.io/chef/ -
Ansible
www.ansible.com/ -
Salt
saltstack.com/
以 Ansible 为例,在第四章,使用 Ansible 配置网络设备一章中,我们介绍了 jinja2 模板的概念。Jinja2 模板允许模板文件用令牌填充,这些令牌在部署时会被特定的键值对替换。
Ansible 允许用户使用变量(令牌)填充 jinja2 模板。每个 var 文件可以配置成对每个环境唯一。环境文件可以通过命令行参数导入到剧本和角色中。这将进一步在部署时将 jinja2 模板转换为特定环境的信息。
在以下示例中,我们看到一个 Ansible 剧本 configure_env.yml 被执行,并且需要设置一个名为环境的独特环境变量:

这些将被导入到 configure_env.yml 中,以便为每个环境加载一组独特的环境信息。
因此,以组件、集成、系统测试和生产环境为例,以下文件将被加载:
-
../roles/networking/vars/comp.yml -
../roles/networking/vars/int.yml -
../roles/networking/vars/sys.yml -
../roles/networking/vars/prod.yml
对于每个独特的环境,部署命令的不同之处仅在于加载的环境文件,这将使部署环境具有特定性:

持续交付和部署概述
持续交付和部署是持续集成过程的自然延伸。持续交付和部署创建了一个一致的机制,将更改部署到生产环境,并创建一个传送带,将新功能传递给客户或最终用户。因此,从概念上讲,持续交付就像是一个传送带,但在实际过程上,如何实现这一目标呢?
持续集成过程将执行以下高层次的步骤:
-
提交
-
构建(编译/版本/标签)
-
验证
-
包
-
推送
一旦工件被推送到工件库,持续交付和部署就会接管。每一个由持续集成过程创建的构建工件都应视为发布候选版本,这意味着它可以在通过持续交付管道中的所有验证后,潜在地部署到生产环境。
像持续集成一样,持续交付和部署会创建一系列反馈循环,以指示验证测试是否在某个环境中失败。
持续交付流程将涵盖每个部署阶段的以下高层步骤:
-
部署(拉取/令牌化/设置)
-
验证(测试)
-
推广
部署管道中的一个阶段将包含一系列测试,用于帮助验证应用程序是否在发布到生产环境之前按要求正常工作。
部署管道中的每个阶段都会有一个部署步骤,它将从Artifact Repository拉取工件到目标服务器并执行部署步骤。部署过程通常涉及安装软件或配置服务器状态的更改。配置更改通常由配置管理工具管理,例如 Puppet、Chef、Ansible 或 Salt。
一旦部署完成,将在环境中进行一系列测试,以验证部署并测试应用程序或更改的功能。
持续交付意味着如果在测试环境中验证测试通过,那么构建工件会自动推广到下一个环境。在下一个环境中,部署、验证和推广步骤将以与前一个环境相同的方式进行。如果出现故障,发布候选版本将会失败,并且不会被推广到下一阶段。
使用持续交付时,自动推广会一直持续到生产前的环境,如下图所示:

持续部署与持续交付不同,它在生产前没有暂停状态,并且自动部署到生产环境:

所以,持续交付和持续部署之间的唯一区别就是是否手动暂停将构建工件推广到生产环境。
实施持续交付而非持续部署的原因通常与治理或测试的成熟度有关。
刚开始时,全天候持续部署到生产环境可能显得非常令人生畏,因为它要求部署过程完全自动化,并且每个环境中的验证和测试必须足够成熟,以捕捉所有已知的错误。
在持续部署中,生产部署的触发器是 SCM 提交,因此它把大量的信任放在了部署系统上。这意味着期望分支策略被设置为从主干/主线/主分支拉取所有变更并触发部署流水线。拥有多个不同的分支将使部署过程变得复杂,因此重要的是实施一个最小化重复并避免部署流水线数量爆炸的分支策略。
如果实施不当,持续部署可能导致持续的停机时间,因此通常在建立持续集成后,企业和团队应从持续交付开始,目标是随着流程的成熟最终过渡到持续部署。
正如在第三章中所述,将 DevOps 带入网络运营,业务内部需要进行文化变革来实施持续交付模型,实际上这是一种全有或全无的方式,才能成功实现。
正如在第八章中所述,测试网络变更,手动更新环境可能会影响测试的有效性,因此应该尽一切可能避免,所有变更都应通过 SCM 流向下游环境。
持续交付促进了自动化和在每个部署流水线阶段创建测试包,但它也允许企业精挑细选最终部署到生产环境的发布候选版本。
这意味着在生产之前的停顿期间,可以手动进行额外的验证,以弥补构建制品未达到所需的测试覆盖率或测试水平。这对于受监管要求的公司来说尤其适用,因为它们可能只在指定的部署窗口内进行部署,而无法持续部署到生产环境。
持续交付意味着受监管的公司仍然可以受益于自动化环境和测试,但生产部署只是通过点击按钮来选择已经通过所有前述验证并部署到生产环境的制品。
部署方法论
在进行持续交付和部署时,并没有适合所有场景的统一部署策略。像 Puppet、Chef、Ansible 和 Salt 这样的配置管理工具在部署方法和保持服务器最新的方式上有所不同。
选择的工具并不重要,重要的是理想的工作流和流程,以支持交付一致、快速且准确的变更。
拉取模型
Puppet 和 Chef 等工具采用集中式配置管理方法,它们有一个集中的服务器,充当部署过程的“大脑”。
在 Puppet 的情况下,集中式服务器是 Puppet Master,而在 Chef 的情况下,集中式服务器是 Chef Server。这个集中式服务器是为存储服务器配置而提供的一套基础设施,按照配置管理工具的参考架构进行。
所有对服务器配置的更新首先推送到集中式服务器,然后通过代理推送到相应的服务器。这些代理可以轮询集中式服务器获取更新并立即应用,或者等待 Puppet Agent,或者在 Chef 的情况下,等待 Chef Client 启动,从集中式服务器到包含代理的服务器进行配置的融合。
拉取模型的主导原则是集中式服务器控制系统的状态,每个变更都需要通过 Puppet Master 或 Chef Server。
如果任何用户登录到服务器并更改状态,那么下一次从集中式服务器进行状态融合时,代理(Puppet Agent 或 Chef Client)运行时可能会覆盖这些手动更改,前提是该配置由集中式服务器管理。
在这种模型中,集中式服务器将控制所有应用版本信息和环境配置。
下图展示了一个拉取模型的示例。图中展示了 Chef 如何在持续交付过程中使用:
-
持续集成过程创建了一个新的构建工件,并将其推送到工件仓库。
-
Chef 的命令行客户端knife作为构建后动作被调用,它会将新版本的应用更新到Chef Server,该版本即将被部署。
-
然后,部署过程通过运行Chef Client在组件测试环境上触发,这将触发Chef Client与Chef Server进行状态检查。
-
在这种情况下,Chef Client基于上次knife更新检测到有新的应用版本可用,因此更新环境到新的应用版本。
-
最后,所有验证和测试步骤都会在推广到部署流水线的下一阶段之前执行。
-
仅在组件测试环境的推广成功后,才会触发后续的集成测试环境的融合!拉取模型
推送模型
像 Ansible 和 Salt 这样的工具采用推送模型来进行配置管理,它们有一个控制主机,通过 SSH 连接到服务器并进行配置。
Ansible 和 Salt 并不使用集中式服务器,而是使用一个控制主机,该主机在服务器上安装了命令行客户端。然后,控制主机通过 SSH(使用密码或 SSH 密钥)登录到服务器,推送更改到服务器。
由于 Ansible 和 Salt 是基于 Python 的,它们不需要代理,可以在任何 Linux 发行版上运行,因为 Python 是这些服务器的前提条件。Windows 机器通过 WinRM 连接并进行配置。
所有配置管理信息都存储在 SCM 系统中,并被拉取到控制主机,这些配置随后用于将更新推送到服务器。
推送模型的主要原则是将更改提交到 SCM 中。SCM 服务器,而不是集中式服务器,是状态、配置和版本控制的真实来源。
以下是推送模型的一个示例,展示了 Ansible 在持续交付过程中的使用:
-
持续集成过程创建了一个新的构建构件,并将其推送到构件库。
-
构件库中出现新构件时,会触发部署过程,Ansible 的剧本/角色会从SCM 系统下载到Ansible 控制主机。
-
然后在组件测试环境中触发部署过程,并对目标清单中所有服务器执行 Ansible。
-
最后,在将其提升到部署管道的下一个阶段之前,所有验证和测试步骤都会运行。
-
只有在组件测试环境的推广成功后,Ansible 才会在后续的集成测试环境中执行
![推送模型]()
何时选择拉取或推送
在选择拉取或推送配置管理方法时,取决于个人偏好,应该根据基础设施的处理方式来选择。
拉取模型在处理长期存在的服务器基础设施时非常受欢迎。它非常适合补丁管理,以保持合规性。由于拉取模型具有一个集中式服务器来维护当前状态,如果从某个服务器中移除配置,集中式服务器会注册需要删除。推送模型只理解当前的期望状态,并且由于缺乏收敛性,不会考虑以前的状态。因此,如果从剧本中删除了一些配置,例如,在下次部署时不会自动清理这些已删除的配置。
拉取方法的缺点是需要维护集中式服务器的基础设施,而这可能会变得相对庞大;同时,由于它是基于代理的,还需要维护代理的版本。
推送模型非常适合协调和更新大量服务器。当使用不可变基础设施时,它们很受欢迎,因为服务器的旧状态并不重要。这意味着只有当前期望的状态才是相关的,因此不需要清理已删除的配置,因为服务器将在每次部署时重新部署。
使用不可变基础设施的拉取模型实际上是没有意义的,因为服务器只会聚合一次,然后销毁,因此为了处理聚合而运行大量集中式服务器是浪费的。
打包部署工件
仅使用配置管理工具来部署应用程序是不够的;持续交付和部署的速度取决于最慢的组件。因此,等待手动进行网络或基础设施更改并不可取;所有组件都需要被构建、版本控制,并且部署过程自动化。
在从头开始构建新环境时,需要使用多个部署工件来构建一个环境;应用程序代码只是拼图中的一块。
构建冗余环境所需的依赖项如下:
-
应用程序
-
基础设施(基础操作系统以及虚拟或物理服务器)
-
网络
-
负载均衡
-
部署脚本(配置管理)
如果这些组件没有一起版本控制,就意味着无法进行真正的回滚,因为如果回滚应用程序而网络状态已发生变化,组件可能会出现故障。
理想情况下,应用程序代码、基础设施、网络、负载均衡和部署脚本应当作为一个整体进行版本控制和测试。因此,如果需要回滚,操作员可以简单地回滚到最后一个已知的包,其中包含经过验证的应用程序代码、基础设施、网络、负载均衡和部署脚本,这些元素曾经一起正常工作。
一种选择是拥有一个单一的代码库,在这个代码库中对所有依赖项进行版本控制。对于处理大量应用程序时,这种方式可能缺乏灵活性,并且可能导致配置的重复。
版本控制所有组件的另一种方式是通过持续集成构建,每个组件可以有自己的持续集成构建来版本控制各个组件并创建一个独特的代码库。
应用程序将以打包实体的形式存在,可能是 Red Hat Linux 上的 RPM 文件、Ubuntu 上的 APT 文件,或 Windows 上的 NuGet 包。
基础设施将通过云服务提供商的 API(如 OpenStack、Microsoft Azure、Google Cloud 或 AWS)进行配置,因此需要使用版本控制的清单文件来指定所需的服务器数量。
基础操作系统镜像可以使用如 Packer 或 OpenStack Disk Image Builder 等工具创建,并上传到云服务提供商的镜像注册中心。
如第四章、使用 Ansible 配置网络设备、第五章、使用 Ansible 配置负载均衡器和第六章、使用 Ansible 配置 SDN 控制器中所述,使用 Ansible 进行网络配置通常采用var文件的形式,这些文件描述了系统的期望状态。
在使用 SDN 控制器时,子网范围和 ACL 防火墙规则可以在这些var文件中描述,并利用按特定顺序调度的模块在部署时应用它们。类似地,负载均衡配置对象模型可以存储在 Ansible 的var文件中,以进行负载均衡的设置。
每个仓库都应该标记为持续集成构建的一部分,然后可以为每个应用程序创建一个附加的包构建。这个包构建用于将所有依赖项汇总并通过清单文件一起版本化。
贡献到清单文件的持续集成构建如以下图所示:

清单文件可以是简单的键值对文件或 JSON 文件。文件的格式并不重要,记录每个持续集成构建的最新标签版本是整个过程的关键。
在部署时,应该使用新的打包清单作为部署管道的触发器。部署管道的第一步将从工件仓库中拉取清单文件,然后可以读取其版本信息。
清单文件中列出的所有仓库版本随后可以被拉取到 Ansible 控制服务器,并用于部署所需的应用版本以及所需的基础设施、网络和负载均衡器,以满足每个环境的需求。
回滚将涉及将之前版本的清单文件传递给部署过程,进而恢复到已知能正常协作的应用程序代码、基础设施、网络、负载均衡和部署脚本的上一个已测试版本。
部署管道工具
部署管道涉及将不同工具链在一起,创建持续交付流程。
能够通过持续交付工具追踪流程是至关重要的,因为能够可视化管道过程对操作员来说非常重要,这样他们可以轻松跟踪。
了解流程的可见性使得调试变得容易,尤其是在发生错误时,因为错误会在任何流程中出现,且是不可避免的。持续交付管道的主要目标之一,除了自动化将更改交付到环境之外,就是提供反馈回路。因此,如果一个管道不容易跟踪和调试,它就没有达成其主要目标之一。
如果可能的话,应在管道中实现自动清理功能,这样如果部署过程中发生故障,可以将更改恢复到最后已知的良好状态,而无需人工干预。
从高层次来看,创建持续交付的部署管道时需要以下工具,包括SCM 系统、CI 构建服务器、工件库和CD 管道调度器:

在第七章,使用持续集成构建进行网络配置,以及第八章,单元测试网络更改中,我们讨论了 SCM 系统和 CI 构建服务器在持续集成和测试中的重要性。在本章中,我们将重点介绍部署过程中所需的工具,包括工件库和用于调度配置管理工具的 CD 管道调度器。
工件库
工件库是任何部署管道中的关键组件;它们可以用来托管多种不同的库,甚至只是存放通用工件。
平台的黄金镜像可以以 ISO、AMI、VMDK 和 QCOW 格式存储和版本控制,并用作云提供商(如 AWS、Google Cloud、Microsoft Azure 和 OpenStack)的镜像注册表源。
清单文件也可以存储在发布库中,用于管理应用程序、基础设施、网络和负载均衡要求的前进和回滚。
Artifactory
JFrog 的 Artifactory 是目前市场上最受欢迎的工件库之一,提供通过基于 NFS 的共享存储解决方案访问库的功能。Artifactory 与 Apache Tomcat Web 服务器捆绑在一起,作为安装包的一部分,可以在 Linux 或 Windows 上托管。
在负载均衡方面,Artifactory 可以设置为高度可用的三层集群以实现冗余。Artifactory 可以使用各种负载均衡器,如 Nginx 或 HAProxy,也可以使用专有负载均衡器,如 Citrix NetScaler、F5 Big-IP 或 Avi Networks。
Artifactory 由 MySQL 或 Postgres 数据库支持,需要 NFS 文件系统或 Amazon S3 存储来存储可供每个 Artifactory 的三个 HA 节点访问的工件。
Artifactory的架构概述如下图所示:

Artifactory 支持多种不同的仓库类型,这里展示了一些,因此它可以根据交付团队所开发的应用程序,托管多个不同的仓库:
-
Gradle
www.jfrog.com/confluence/display/RTF/Gradle+Artifactory+Plugin -
Git LFS
www.jfrog.com/confluence/display/RTF/Git+LFS+Repositories -
NuGet
www.jfrog.com/confluence/display/RTF/NuGet+Repositories -
Bower
www.jfrog.com/confluence/display/RTF/Bower+Repositories -
Vagrant
www.jfrog.com/confluence/display/RTF/Vagrant+Repositories -
Debian
www.jfrog.com/confluence/display/RTF/Debian+Repositories -
Generic
www.jfrog.com/confluence/display/RTF/Configuring+Repositories
这意味着 Artifactory 可以作为持续交付管道的单一仓库端点。Artifactory 最近引入了对 Vagrant boxes 和 Docker registry 的支持,因此可以用来存储 Vagrant 测试环境,这些环境可以用来存储网络操作系统或容器。这展示了市场领先的制品库所提供的一些功能。
CD 管道调度器
尽管制品库的工作相对简单,但同样重要的是,选择正确的持续交付管道工具要困难得多。
有许多可用的选项,例如:
-
IBM Urban Code Deploy
developer.ibm.com/urbancode/products/urbancode-deploy/ -
Electric Flow Deploy
electric-cloud.com/products/electricflow/deploy-automation/ -
Jenkins
jenkins.io/ -
Thoughtworks Go
www.go.cd/ -
XL Deploy
xebialabs.com/products/xl-deploy
但是,在选择工具之前,需要考虑正在实现的过程。那么,持续交付流水线的主要目标是什么?
一个好的持续交付流水线应该达到以下目标:
-
根据新工件在工件仓库中的可用性触发部署
-
调度命令行
-
渲染流水线视图
-
将任务分解为阶段
-
提供良好的日志输出
-
反馈通过或失败
-
与测试的集成
选择工具时需要考虑所有这些点,因此我们将挑选最受欢迎的持续交付流水线调度工具之一 Jenkins,并查看它调度流水线的方式。
Jenkins
Jenkins 最初是作为一个持续集成构建服务器而设计的。Jenkins 有一个可插拔框架,这意味着它通常会被定制以执行部署,插件如多任务插件被开发用来让它调度流水线。
然而,从 Jenkins 2.x 版本开始,Jenkins 将流水线作为其分发的核心功能组件,而不再依赖插件来满足其部署能力。
在以下示例中,可以看到 Jenkins 流水线任务类型:

使用 Jenkins 流水线任务类型,用户可以使用Pipeline Script指定流水线,声明流水线的每个阶段。在这个示例中,已使用回显命令来模拟每个流水线阶段,展示Pipeline script的样子:

流水线脚本的可视化显示展示在阶段视图中。阶段视图显示了流水线在部署网络、虚拟机、应用程序和负载均衡器配置时所经历的八个阶段:

每个阶段的日志在 Jenkins 控制台日志中清晰显示,允许工具的用户看到成功和失败的反馈:

当将有效命令放入Pipeline script时,与我们在上面示例中模拟回显不同,Jenkins 允许用户使用 groovy 代码片段生成器将任何步骤转换为流水线脚本格式。
在这种情况下,需要一个 shell 命令来执行 Ansible 剧本,create_vip.yml,在组件测试环境上,因此使用代码片段生成器来创建它:

这个代码片段命令可以粘贴到在流水线脚本中创建的create_vip.yml阶段:

作业配置的输出是一个 Jenkins 文件,可以存储在 SCM 中,以版本控制部署管道的变更。
使用部署管道部署网络变更
在进行持续交付或部署时,必须包含网络变更。网络团队需要为部署管道贡献关键部分。
由于 CD 管道调度器允许在部署管道中指定不同的阶段,它提供了极大的灵活性,并允许所有团队贡献自己的部分,形成一个真正协作的 DevOps 模式。
有时网络团队的担忧是开发人员不应该拥有所有网络设备的必要访问权限,因为他们不是专家。事实上,开发人员并不想访问网络设备,他们只是希望有一个快速的方式来推动他们的变更,而不被网络变更的应用所阻碍。
网络自服务
允许开发人员自行处理网络变更非常重要,否则网络团队将成为持续交付过程中的瓶颈。
因此,提供给开发团队一个强化的 Ansible playbook 来创建日常网络功能,无疑会帮助减轻开发人员的痛苦,并使新的网络变更的部署成为自服务功能。
开发人员可以使用一个包含网络团队最佳实践的 playbook 来应用任何网络变更。这遵循了这样的模式:开发人员可以利用基础设施团队提供的 playbook 来创建新的虚拟机,并使用 IPAM 解决方案注册他们的 DNS 条目。
部署管道中的步骤
在创建部署管道时,重要的是将每个功能拆分成一组精细的步骤。这意味着如果任何步骤失败,可以轻松回滚。直观地理解部署管道也很重要,因为将复杂的操作拆解为小步骤使得调试失败变得不那么令人生畏。
现代应用程序的部署管道将在每次部署时,通过执行以下高级步骤来配置新的环境:
-
下载清单
-
创建网络
-
在网络中创建虚拟机
-
安装应用程序
-
创建 VIP
-
滚动更新
-
运行测试包
-
推广到下一个阶段
管道的第一阶段是触发新部署到第一个测试环境。在这种情况下,检测到一个新的清单文件工件。
清单工件将被下载到 CD 管道调度器并解析。Ansible var 文件结构将从 SCM 使用清单版本进行组装。
一旦组装完成,网络需要被配置。根据发布版本,将创建 A 或 B 网络,并将应用必要的入站和出站 ACL 规则。
虚拟机将被启动到新配置的网络中,并用其元数据配置文件进行标记,标明需要在其上安装的软件。
运行 Ansible 动态清单以拉取刚刚创建的虚拟机,Ansible 从虚拟机读取配置文件元数据和元数据标签,并根据指定的配置文件在新集群的虚拟机上安装所需角色。
如果负载均衡器上不存在 VIP,将创建一个 VIP,并应用其负载均衡策略。然后将新服务器加入服务并将旧服务器移出服务。新服务器将进行冒烟测试,以确保它们按预期运行,然后销毁之前的版本。
然后执行完整的质量保证测试包,如果成功,清单工件将被提升到下一个阶段。
这些步骤会一直重复,直到生产环境。在持续交付模型中,生产部署将是手动按下按钮触发管道,而在持续交付管道中,如果所有质量门都通过,管道将自动触发。
引入配置管理工具
在使用如 Jenkins 等 CD 调度器时,其代理(称为“从属”)可以用于安装 Ansible,并将其变为部署的 Ansible 控制主机。
部署管道中的每个阶段都可以是一个小型的模块化 Ansible 剧本,使开发人员能够自助处理网络需求。这些剧本可以由网络团队创建,并随着时间的推移不断改进。
因此,Jenkins Pipeline 脚本将如下所示,每个阶段都有一个独特的剧本:

应用于每个测试环境的步骤应与生产环境保持一致,所有步骤都应由管道的服务账户执行。
每一个环境都应该通过实现不可变基础设施和网络从源代码控制构建。这样,所期望的状态始终是清单文件关联的代码库中指定的内容。
提供给每个剧本的 Ansible var 文件可以由开发团队填写,以设置防火墙策略或负载均衡策略。
这些 var 文件由相关的持续集成构建版本控制,用于 SDN 或负载均衡配置。每个与网络相关的 CI 构建在应用程序持续集成构建触发时会汇总到一个新的清单文件中。新清单文件的生成会触发部署管道的第一步。
网络团队在持续交付管道中的角色
在分析部署管道执行的步骤时,如果我们查看哪些团队具有执行每个管道阶段的必要权限,就能非常明显地看出将网络集成到持续交付流程中的重要性。
在部署应用程序的八个高级阶段中,三个阶段涉及与网络集成,分别是执行创建网络、创建 vip和滚动更新,如图所示:

这表明,如果网络操作不是部署管道的一部分,那么真正的持续交付将无法实现。
快速失败和反馈循环
创建持续交付管道的一个关键目标是创建快速失败的反馈循环,并为开发人员创建一个可视化的仪表板。然而,随着持续交付向持续运营领域的扩展,涉及到基础设施、网络和质量保证,所有团队都需要关注故障并做出相应反应。
当管道阶段失败时,每次出现故障时都需要进行自动清理,这样可以保持管道的良好状态,避免下一个管道被阻碍。任何流程中的中断都会导致变更无法到达生产环境。
所以,尽管可能是一个测试环境出现故障,但它现在阻止了潜在的修复程序被部署到生产环境。如果发生故障,管道还应该暂停整个过程,而不是继续到下一个阶段,如下所示:

Ansible 的块救援功能在处理失败的管道阶段和清理时非常有用,它为 playbook 和角色提供了类似于 try 和 catch 的功能。
测试也应该被集成到部署管道中,这样如果管道的运行测试阶段失败,就会有关于测试失败的历史记录,可以进行审计。管道还帮助提供已应用于环境的所有变更的完整历史。虽然由服务帐户触发,但提交变更的用户应该对每次变更负责。
总结
在本章中,我们探讨了将网络变更集成到部署管道中,以便网络团队能够为持续交付过程做出贡献。然后,我们讨论了持续交付和部署之间的区别。
然后,我们探讨了软件包管理在将开发、基础设施、质量保证和网络变更结合在一起作为部署管道的一部分时的重要性。我们还以 Artifactory 和 Jenkins 为例,展示了一些市场领先的工件仓库和 CD 管道调度器。
最后,我们探讨了在持续交付和部署范围内设置部署管道时应该采用的最佳实践。接着,我们专注于网络团队如何通过为开发人员提供自助服务的部署脚本来贡献于部署管道,以便保持整体过程的快速、精简和自动化。
阅读完本章后,您应该理解为何应用程序应该仅编译一次并存储在构件仓库中,并且相同的二进制文件应部署到多个环境中,以确保部署过程的一致性。
本章还重点讲解了基于拉取模型的工具(如 Chef 和 Puppet)与基于推送模型的工具(如 Ansible 和 Salt)在配置管理中的差异。
关键要点还应包括如何利用 Artifactory 作为构件仓库,存储多种类型的构建产物,以及如何使用持续集成生成清单文件,以对代码、基础设施、网络和负载均衡进行版本控制。
读者应学习持续交付管道中的所有必要步骤,如何使用 Jenkins 2.x 设置部署管道,以及在持续交付模型中集成网络的重要性。
在下一章,我们将重点讨论容器,并探讨它们对网络和网络操作的影响。我们还将了解一些可以使用的不同编排选项,例如 Docker 和 Kubernetes。
第十章:容器对网络的影响
现代 IT 书籍中没有一章关于容器的内容是 incomplete 的。在这一章中,我们将回顾容器的历史以及当前可以部署容器的选项。本章将探讨从网络角度支持容器运行所需的变化。接着,我们将重点讨论用于打包容器的一些技术,以及它们如何融入持续交付流程。最后,我们将重点讨论一些用于部署容器的编排工具。
本章将涵盖以下主题:
-
容器概述
-
容器打包
-
容器编排工具
-
容器如何适应持续集成和持续交付
容器概述
最近,IT 行业对容器的宣传非常多;你可能会认为,仅凭容器就能解决所有应用程序部署的问题。许多供应商的营销活动声称,实施容器会让企业更加敏捷,或者仅仅通过将应用程序部署到容器中,企业就已经在实施DevOps。如果你听到软件供应商在推广其容器技术或容器编排软件时这样说,那这无疑是他们的观点。
然而,容器并不是一个新概念。远不是:Solaris 10 早在 2005 年就引入了 Solaris Zones 的概念,这使得用户能够将操作系统分割为不同的组件并运行隔离的进程。现代技术如Docker或Rocket提供了一个容器工作流,允许用户打包和部署容器。
然而,像所有基础设施概念一样,容器只是流程的促进者,错误地将容器作为独立项目实施通常不会为公司带来业务价值。鉴于容器的近期流行,似乎大型软件供应商将容器解决方案作为其产品组合的一部分几乎已成必然。
容器,像所有工具一样,对于某些使用场景是非常有益的。在考虑容器时,重要的是要考虑它们对微服务架构带来的好处。可以公平地说,容器已被一些平台即服务(PaaS)公司视为开发与运维之间的桥梁。
容器技术使得开发人员能够以一致的方式将应用程序打包在容器中,同时描述他们希望如何使用 PaaS 技术在生产环境中运行微服务应用程序。开发和运维人员都能理解这一构建,因为他们都熟悉相同的容器技术和他们用于部署应用程序的构建方式。这意味着在开发工作站上部署的容器与在生产系统上运行时的行为是相同的。
这使得开发人员能够更加一致地定义应用程序拓扑和负载均衡需求,以便在测试和生产环境中通过共同的工具集进行相同的部署。
像 Netflix 这样的著名成功案例表明,将整个微服务架构容器化是可行的,并且能够取得成功。随着微服务应用的流行,常见的需求是将微服务应用程序打包并部署到多个混合云中。这为组织提供了选择使用哪家私有或公有云服务提供商的真实选择。
在微服务架构中,云原生微服务应用可以根据业务的繁忙或安静时段快速扩展或缩减。当使用公有云时,理想的做法是只利用所需的资源,这通常意味着微服务可以在一天中随时扩展或缩减,以节省运行成本。
基于利用率的弹性扩展是部署云原生微服务时的常见用例,这样微服务可以根据其监控系统或云服务提供商提供的数据进行动态扩展或缩减。
微服务沿袭了面向服务架构(SOA)的理念,并且可以被视为这一理念的现代实现。像 SOA 这样的微服务允许多个不同的组件通过服务网络和通用协议集进行通信。微服务旨在将服务解耦成具体的功能,使其可以单独进行测试,并将它们组合起来以创建整体系统,并且如所示,根据需求进行扩展或缩减。
在使用微服务架构时,不需要每次都部署整个系统,不同的组件版本可以独立部署,而不会导致系统停机。
从某种程度上看,容器可以被视为微服务应用程序的完美解决方案,因为它们可以用来独立执行特定功能。每个微服务应用可以在单独的容器构建中部署,并通过网络连接在一起,以便为最终用户提供整体服务。
容器本身已经原生支持在任何 Linux 操作系统上运行,并且具有轻量级的特点,这意味着在使用流行的容器技术时,如下所示,它们可以轻松部署、维护和更新:
-
Docker (
www.docker.com/) -
Google Kubernetes (
kubernetes.io/) -
Apache Mesos (
mesos.apache.org/) -
IBM Bluemix (
www.ibm.com/cloud-computing/bluemix/containers/) -
Rackspace Catrina (
thenewstack.io/rackspace-carina-bare-metal-caas-based-openstack/) -
CoreOS Rocket (
coreos.com/blog/rocket/) -
Oracle Solaris Zones (
docs.oracle.com/cd/E18440_01/doc.111/e18415/chapter_zones.htm#OPCUG426) -
Microsoft Azure Nano Server (
technet.microsoft.com/en-us/windows-server-docs/get-started/getting-started-with-nano-server) -
VMware Photon (
blogs.vmware.com/cloudnative/introducing-photon/)
容器化 本质上是在操作系统上虚拟化进程,并将它们相互隔离成可管理的组件。容器编排技术随后创建网络接口,使多个容器能够跨操作系统相互连接,或者在更复杂的场景中,创建完整的覆盖网络,利用程序化 API 和键值存储进行服务发现,以连接运行在多个物理或虚拟服务器上的容器。
Solaris Zones
2005 年,Solaris 引入了 Solaris Zones 的概念,并由此产生了容器化的概念。在用户登录到全新的 Solaris 操作系统后,他们会发现自己处于一个全局的 Solaris 区域中。
Solaris 随后为用户提供了创建新区域、配置它们、安装运行它们的包,并最终启动它们以便使用的选项。这使得每个隔离的区域能够作为单一 Solaris 操作系统内的独立部分使用。
Solaris 允许区域作为完全隔离的一组进程运行,这些进程在权限、磁盘和网络配置方面都来自默认的全局区域。不同的持久存储或原始设备可以被导出到区域并挂载,以使外部文件系统对区域可访问。这意味着多个不同的应用程序可以在各自独立的区域内运行,并与外部共享存储进行通信。
在网络方面,全球 Solaris Zone 将具有一个 IP 地址,并连接到默认路由器。所有新区域将具有相同子网内的唯一 IP 地址,并使用相同的默认路由器。如果需要,每个区域甚至可以有自己独特的 DNS 条目。Solaris Zones 的网络配置如图所示,通过访问/zones文件系统上的网络配置,两个区域连接到路由器:

.
Linux 命名空间
Linux 命名空间为系统进程创建了一个抽象层,对该进程的更改仅会影响同一命名空间中的其他进程。Linux 命名空间可用于隔离 Linux 操作系统上的进程;默认情况下,当 Linux 操作系统启动时,所有资源都运行在默认命名空间下,因此能够查看所有正在运行的进程。
命名空间 API 包含以下系统调用:
-
clone -
setns -
unshare
clone系统调用创建一个新进程,并将所有指定的进程与之关联;而setns系统调用用于将命名空间连接在一起,unshare系统调用则将进程从一个命名空间移出并移至新的命名空间。
以下是 Linux 上可用的命名空间:
-
挂载
-
进程 ID
-
进程间通信
-
UTS
-
网络
-
用户
mounts 命名空间用于隔离 Linux 操作系统的文件系统,使得特定的挂载点仅对属于同一命名空间的进程组可见。这使得不同的进程可以根据其所属的命名空间访问不同的挂载点,从而可以用于保护特定的文件。
进程 ID(PID)命名空间允许在 Linux 机器上重用 PID 进程,因为每组 PID 都是唯一的,并且属于特定命名空间。这允许容器在主机之间迁移,同时保持相同的 PID,从而确保操作不会中断容器。这也允许每个容器拥有独特的init进程,并使容器具有极高的可移植性。
进程间通信(IPC)命名空间用于隔离特定的资源,如进程之间的系统对象和消息队列。
UTS 命名空间允许容器拥有自己的域名和主机名;这在使用容器时非常有用,因为编排脚本可以针对特定的主机名,而不是 IP 进行操作。
网络命名空间在网络资源(如 IP 空间、IP 表和路由表)周围创建了一个隔离层。这意味着每个容器可以有其独特的网络规则。
用户命名空间用于管理用户对命名空间的权限。
因此,从网络角度来看,命名空间允许多个不同的路由表在同一 Linux 操作系统上共存,因为它们具有完全的进程隔离。这意味着每个容器可以根据需要应用其独特的网络规则。
Linux 控制组
控制组(cgroups)的使用使用户能够控制属于命名空间的一部分的 Linux 操作系统资源。以下控制组可用于控制 Linux 资源:
-
CPU
-
内存
-
冰冻
-
块 I/O
-
设备
CPU 控制组可以使用两种不同类型的调度器:一种是完全公平调度器(CFS),基于加权系统分配 CPU。另一种是实时调度器(RTS),它是一种任务调度器,根据任务的实时使用情况来限制任务的执行。
内存控制组用于生成与控制组中的任务相关的内存利用率报告。它对与控制组相关的进程的内存使用设置限制。
冰冻控制组(freezer cgroup)用于控制与冰冻控制组相关的所有进程的状态。冰冻控制组可用于控制一批任务并发出FREEZE命令,这将停止用户空间中的所有进程;THAW命令则可以用来重新启动这些进程。
块 I/O(blkio)控制组监控对块设备的 I/O 访问,并对 I/O 带宽或对资源的访问引入限制。Blkio 使用 I/O 调度程序,并可以分配权重来分配 I/O,或通过设置最大限制来对进程在设备上读取或写入的数量进行限制,从而实现 I/O 限速。
设备控制组通过在devices.allow和devices.deny下定义任务来允许或拒绝访问设备,并可以通过devices.list列出设备访问。
容器的好处
容器具有许多优势,特别是在可移植性、敏捷性、安全性方面,正如本章前面所提到的,它们帮助了许多组织(如 Netflix)部署微服务架构。
容器还允许用户通过使用命名空间在操作系统上分配不同的资源,并通过控制组限制 CPU、内存、网络块 I/O 和网络带宽。
容器的配置非常快速,因此可以迅速进行横向扩展和缩减,以支持云环境中的弹性扩展。它们可以迅速扩大以满足需求,并且容器可以通过多种技术从一台服务器迁移到另一台服务器。
控制组可以根据系统的变化迅速进行配置,赋予用户对操作系统低级调度特性的完全控制,而这些通常是在使用虚拟机或裸金属服务器时交由基础操作系统来处理的。容器可以进行微调,以提供对性能的更精细控制。
在某些场景下,裸金属服务器上的所有资源并不会被充分利用,这可能会导致浪费,因此可以通过容器来利用客户操作系统上所有的 CPU 和内存,方法是在内核级别通过命名空间隔离运行多个相同应用程序的实例。这意味着对于每个进程,它们看起来像是在自己独特的操作系统上运行。
到目前为止,容器的主要缺点之一是它们通常是低级别的,并且在大规模管理时非常困难。因此,像大规模实施和协调引擎(例如 Docker Swarm、Google Kubernetes 和 Apache Mesos)等工具通过创建抽象层来管理容器,从而减轻了这种痛苦。
容器的另一个好处是它们非常安全,因为它们通过使用不同的命名空间,限制了攻击面,并为操作系统增加了额外的安全层。如果操作系统被攻击,攻击者仍然需要在命名空间级别攻破系统,而不是直接访问所有进程。
在运行多个相同进程的不同版本时,容器非常有用;例如,一个企业希望为不同的客户运行同一个应用程序的多个版本。他们希望防止一个客户的登录和交易激增影响到其他客户的应用层。容器在这种情况下是一个可行的解决方案。
部署容器
随着容器的日益流行,传统的 Linux 发行版在运行纯容器平台时被发现表现不佳且笨重。
因此,已经创建了非常精简的操作系统来托管容器,例如 CoreOS 和 Red Hat Atomic,这些操作系统专门设计用于运行容器。
在操作系统之间共享信息对于容器来说也是一个挑战,因为按照设计,它们通过命名空间(namespaces)和控制组(cgroups)被隔离到特定的主机操作系统上。etcd、Consul 和 Zookeeper 等键值存储可以用于跨主机群集和共享信息。
CoreOS
CoreOS 是一个基于 Linux 的操作系统,专门设计用于提供一个最小化的操作系统来运行容器集群。它是目前最广泛使用的容器操作系统,旨在以大规模运行而无需频繁手动修补和更新操作系统上的软件。
任何在 CoreOS 上运行的应用程序都将以容器格式运行;CoreOS 可以在裸机或虚拟机上运行,支持 AWS 和 OpenStack 等公共和私有云。
CoreOS 通过自动拉取频繁的安全更新而不影响操作系统上运行的容器来工作。这意味着 CoreOS 不需要 Linux 管理员干预和修补服务器,因为 CoreOS 会通过零停机安全更新自动处理这些修补。
CoreOS 通过将应用程序依赖性从应用程序中剥离并转移到容器层来工作,因此容器依赖于其他容器来进行依赖管理。
etcd
CoreOS 使用 etcd,这是一种分布式键值存储,允许跨多台机器的多个容器连接到它,以获取数据和状态信息。
Etcd 使用Raft 算法来选举领导者,并通过跟随者来保持一致性。当多个 etcd 主机运行时,状态从大多数实例中拉取并传播到跟随者,因此它用于保持集群的一致性和实时更新。
应用程序可以读取和写入数据到 etcd,并且它被设计用来处理故障和故障条件。Etcd 可以用来存储到端点的连接字符串或其他特定环境的数据存储。
Docker
如果不提到 Docker,谈容器将是不可能的。2013 年,Docker 作为一个开源项目发布,可以用来打包和分发容器。Docker 最初是基于 Linux LXC 容器的,但随着项目的发展,它已经逐渐脱离了这一标准,并变得更加有主张和成熟。
Docker 基于在 Linux 内核中将每个容器进程隔离的原则工作。Docker 使用支持联合的文件系统、cgroups 和内核命名空间来运行容器并隔离进程。它具有命令行界面和经过深思熟虑的工作流。
Docker 镜像仓库
当容器镜像被打包时,它们需要被推送到 Docker 的容器镜像仓库服务器,这是一个容器的镜像存储库。
Docker 镜像仓库用于存储容器,容器可以像软件包仓库一样进行标记和版本管理。这允许存储不同版本的容器,以便进行向前滚动和回滚。
默认情况下,Docker 镜像仓库是一个文件系统卷,并在本地文件系统上持久化数据。像 Artifactory 和 Nexus 这样的工件仓库现在也支持 Docker 镜像仓库作为一种仓库类型。Docker 镜像仓库可以通过身份验证和 SSL 证书来确保容器镜像的安全。
Docker 守护进程
在安装过程中,Docker 会在目标操作系统上部署一个守护进程,用来运行容器。Docker 守护进程用于与 Docker 镜像仓库通信,并发出拉取命令以拉取最新的容器镜像或特定标签版本。然后,Docker 命令行可以用来调度启动容器,使用从仓库中拉取的容器镜像。默认情况下,Docker 守护进程会作为常驻进程运行在目标操作系统上,但可以通过 systemd 等进程管理器来启动或停止。
打包容器
容器可以以多种方式打包;其中两种最常见的打包方式是使用 Dockerfile,另外一种较少为人所知的方式是使用 HashiCorp 提供的工具 Packer。这两者在打包容器镜像时有略微不同的方法。
Dockerfile
Docker 允许用户使用其自有的配置管理工具 Dockerfile 来打包容器。Dockerfile 会通过列出在构建时使用包管理器安装的包来说明容器的意图。
以下 Dockerfile 展示了通过执行yum install命令在 CentOS 上安装 NGINX,并将端口80暴露给来自打包容器的客户操作系统。暴露端口80是为了让 NGINX 能够外部访问:

一旦创建了 Dockerfile,Docker 的命令行界面允许用户发出以下命令来构建容器:
docker build nginx
唯一的缺点是,应用程序通常使用配置管理工具,如 Puppet、Chef、Ansible 和 Salt 来安装。Dockerfile 非常脆弱,这意味着打包脚本需要完全重写。
Packer-Docker 集成
Packer 是 HashiCorp 的一个命令行工具,使用多个驱动程序来打包虚拟机镜像,也支持创建 Docker 镜像文件。Packer 可用于打包Amazon Machine Image(AMI)镜像,用于 AWS,或QEMU Copy On Write(QCOW)镜像,这些镜像可以上传到 OpenStack Glance。
使用 Packer 时,省去了使用 Dockerfile 来创建 Docker 镜像的需求;相反,可以使用现有的配置管理工具,如 Puppet、Chef、Ansible 和 Salt,来配置和打包 Docker 容器镜像。
Packer 具有以下高级架构,并使用一个 JSON 文件来描述 Packer 工作流,主要分为三部分:
-
构建器
-
配置管理工具
-
后处理器
构建器用于启动一个 ISO、虚拟机在云平台上,或者在此情况下,从构建服务器上的镜像文件启动一个 Docker 容器。
一旦启动,配置管理配置器将运行一组安装步骤。这将创建镜像所需的状态,模拟 Dockerfile 将执行的操作。完成后,镜像将停止并被打包。
一组后处理器将被执行,将镜像推送到一个工件库或 Docker 注册表,在那里它会被标记并版本化。
使用 Packer 意味着可以使用现有的配置管理工具来打包虚拟机和容器,而不是为容器使用完全不同的配置管理机制。Docker 守护进程需要作为前提条件安装在用于打包容器的构建服务器上。
在以下示例中,创建了一个nginx.json Packer 文件;builders部分定义了类型为docker,这让 Packer 知道使用 Docker 构建器。
export_path是最终 Docker 镜像导出的位置,image是将从 Docker 注册表中拉取并启动的 Docker 镜像文件的名称。
一个ansible-local类型的配置管理器将执行install_nginx.yml剧本,以便使用 Ansible 剧本而不是 Dockerfile 来安装 NGINX 到 Docker 镜像中。
最后,后处理器将把打包的镜像(包含安装的 NGINX)导入到 Docker 注册表,并使用标签1.1:

要执行 Packer 构建,只需执行以下命令并传入 nginx.json 文件:
packer build nginx.json
Docker 工作流
Docker 工作流 很好地融入了我们在 第七章 中讲解的持续集成过程,使用持续集成构建进行网络配置,以及我们在 第九章 中讲解的持续交付工作流,使用持续交付流水线部署网络变更。在开发人员推送新的代码提交后,编译并可能打包新的代码,持续集成过程可以扩展为执行 Dockerfile,以作为部署后的步骤打包新的 Docker 镜像。
每个下游测试环境和生产环境都配置了 Docker 守护进程,作为基础操作系统的一部分。在部署时,Docker 守护进程会被调度拉取新打包的 Docker 镜像并创建一组新的容器进行滚动更新。
该流程图可以如下所示:

默认 Docker 网络
在网络方面,当安装 Docker 时,它会创建三个默认网络;创建的网络是 bridge、none 和 host 网络,如下图所示:

Docker 守护进程默认情况下使用桥接(docker0)网络来创建容器;当在目标操作系统上执行 docker create 和 docker start 命令时,或者可以只执行 docker run 命令。这些命令将根据定义的 Docker 镜像在主机操作系统上创建并启动新的容器。
none 网络用于创建特定于容器的网络,这允许容器启动并持续运行;但是它没有网络接口。host 网络将容器添加到与客户操作系统相同的网络中。
当容器在其上启动时,Docker 的桥接网络会为每个容器分配一个在桥接网络子网范围内唯一的 IP 地址。可以通过执行以下 docker network inspect 命令查看容器:
docker network inspect bridge
Docker 允许用户通过 docker attach 命令检查容器配置;在这种情况下,可以检查 nginx 容器:
docker attach nginx
一旦连接,可以检查 /etc/hosts 文件以查看网络配置。Docker 桥接使用 NAT 网络,并且可以使用以下 –p 命令行参数进行端口转发。例如,-p 8080:8080 将主机的端口 8080 转发到容器的端口 8080。这使得所有在操作系统上运行的容器都可以通过它们的 IP 地址直接通过 localhost 访问,使用端口转发。
在其默认网络模式下,Docker 允许使用--links命令行参数将容器互联,该参数用于连接容器,写入容器的/etc/hosts文件。
现在不建议使用默认的网络设置,而是有更复杂的网络配置,但它覆盖的概念仍然很重要。
Docker 允许定义用户定义网络来托管容器,使用网络驱动程序创建自定义网络,如自定义bridge、overlay或层 2MACVlLAN网络。
Docker 用户定义的桥接网络
用户定义的桥接网络与默认的 Docker 网络非常相似,但意味着每个容器可以在同一桥接网络上与其他容器通信;与默认的 Docker 网络不同,无需链接。
要将容器放置在用户定义的网络上,可以使用以下命令在devops_for_networking_bridge用户定义的桥接网络上启动容器,并设置--net选项:
docker run –d –name load_balancer –net devops_for_networking_bridge nginx
每个启动的容器将驻留在同一操作系统客户机上。Publish用于暴露特定使用-p 8080-8081:8080/tcp命令的。因此,可以发布范围以便暴露网络的部分。
Docker Swarm
虽然本书已经详细介绍了可以与 Docker 一起使用的 Overlay 网络,它们是网络的虚拟化抽象层。Docker 可以为容器创建 Overlay 网络,用于创建属于多个不同操作系统主机的容器网络。
Docker 不是将每个容器隔离到一个唯一网络的主机上,而是允许其 Overlay 网络将部署在不同主机上的多个容器群组连接在一起。
这意味着每个共享 Overlay 网络的容器将拥有唯一的 IP 地址和名称。要创建 Overlay 网络,Docker 使用其自己的编排引擎,称为Docker Swarm。
要在 Swarm 模式下运行 Docker,需要使用外部键值存储,如 etcd、Consul 或 Zookeeper 与 Docker 一起使用。此键值存储允许 Docker 在不同主机之间共享信息,包括共享 Overlay 网络。
Docker machine
docker-machine 是一个有用的命令行实用程序,它允许在 VirtualBox、OpenStack、AWS 等许多平台上使用驱动程序虚拟机进行配置。
在以下示例中,我们可以看到如何使用docker-machine在 OpenStack 中启动机器:
docker-machine create –driver openstack (boot arguments and credentials) docker-dev
docker-machine更有用的功能之一是在云环境中启动虚拟机,并发出 Docker Swarm 命令。这允许在启动时设置所需的特定配置文件。
Docker Compose
另一个有助于协调容器的工具是Docker Compose,因为对每个需要部署的容器运行命令行在大规模应用中不可行。因此,Docker Compose 允许用户以 YAML 格式指定微服务架构拓扑,从而将容器依赖关系连接在一起,形成一个完整的应用。
微服务将由不同类型的容器组成,这些容器共同构成一个完整的应用。Docker Compose 允许将每个微服务定义为 YAML 格式,写入docker-compose文件中,从而以可管理的方式一起部署。
在下面的docker-compose.yml文件中,web、nginx和db应用被配置并相互连接,负载均衡器在8080端口上公开,供公众访问,负载均衡app1,它连接到redis数据库后端:

Docker Compose 可以在与 Docker Compose YAML 文件相同的目录下执行,以启动新的部署,应该执行以下命令:
docker-compose up
Swarm 架构
Swarm 架构的工作原理是每个主机运行一个 Swarm 代理程序,并且有一个主机运行 Swarm 主节点。主节点负责协调运行在各个主机上的容器,这些主机的代理程序都属于同一个发现组(键值存储)。
Swarm 的一个重要原则是发现机制,这可以通过使用像 etcd、Consul 或 Zookeeper 这样的键值存储来实现。
要设置 Docker Swarm,可以使用已设置好的 Docker 机器来配置以下内容:
-
发现服务器(键值存储,如 etcd、Consul 或 Zookeeper)
-
安装了 Swarm 代理的 Swarm 主节点,指向一个键值存储
-
安装了 Swarm 代理的两个 Swarm 节点,指向一个键值存储
Docker Swarm 架构展示了一个主节点在两个 Docker 代理上调度容器,同时它们都在向键值存储广播,键值存储用于服务发现:

在设置 Swarm 代理时,以本例中的 Swarm 主节点为例,它们将通过以下选项启动:--swarm-discovery定义了发现服务的地址,而--cluster-advertise在网络上广播主机机器,--cluster-store则指向所选的键值存储:

一旦架构设置完成,就需要创建一个覆盖网络来跨两个不同主机运行容器(在此示例中,覆盖网络被命名为devops_for_networking_overlay),可以通过以下命令执行:
docker network create –d overlay devops_for_networking_overlay
然后可以使用 Docker Swarm 主节点调度命令,在网络中根据镜像创建容器:
docker run -d –name loadbalancer –net devops_for_netwotking_overlay nginx
由于每个主机都运行在 Swarm 模式下,并且与键值存储相连,因此在创建时,网络信息元数据将由键值存储共享。这意味着所有使用相同键值存储的主机都可以看到这个网络。
然后,容器可以从任何一个 Swarm 主节点启动,加入相同的覆盖网络,将两个主机连接在一起。这将允许每个主机通过覆盖网络与其他容器进行通信,跨主机互联。
可以创建多个覆盖网络;不过容器只能在相同的覆盖网络中相互通信,不能跨不同的覆盖网络通信。为了解决这个问题,容器可以连接到多个不同的网络。
Docker Swarm 允许通过端口转发将多个特定容器分配并暴露,进行负载均衡。还可以进行滚动更新,以便升级容器中的应用版本。
由于其完全去中心化的设计,Docker Swarm 在可以解决的网络用例数量上非常灵活。
Kubernetes
Kubernetes 是 Google 推出的一个流行的容器编排工具,创建于 2014 年,是一个开源工具。Kubernetes 并没有自己开发容器打包工具和打包仓库,而是可以无缝接入 Docker 注册表作为其容器镜像仓库。
Kubernetes 可以通过 Dockerfile 协调使用 Docker 创建的容器,或者使用 Packer 并配合如 Puppet、Chef、Ansible 和 Salt 等配置管理工具。
Kubernetes 可以看作是 Docker Swarm 的替代方案,但在架构设计上采取了略有不同的方法,并且拥有许多丰富的调度功能来帮助容器管理。
Kubernetes 架构
在用户可以使用 Kubernetes 调度容器之前,需要先设置 Kubernetes 集群。市面上有许多配置管理工具,可以用来创建生产级别的 Kubernetes 集群,知名的解决方案有 Ansible、Chef 和 Puppet。
Kubernetes 集群由以下高层组件组成,每个组件又包含一组服务。从高层次看,一个 Kubernetes 集群由以下组件构成:
-
Kubectl
-
主节点
-
工作节点
![Kubernetes 架构]()
Kubernetes 主节点
主节点负责管理整个 Kubernetes 集群,用于协调工作节点,容器会在工作节点上进行调度。
部署后的主节点由以下高层组件组成:
-
API 服务器
-
Etcd 键值存储
-
调度器
-
控制器管理器
API 服务器提供了一个 RESTful API,允许管理员向 Kubernetes 发出命令。
如本章之前所述,Etcd 是一个键值存储,允许 Kubernetes 存储状态并在更改后将更改推送到集群的其余部分。Kubernetes 使用 Etcd 存储有关 Pod、服务、状态甚至命名空间的信息。
Kubernetes 调度器顾名思义,用于在服务或 Pod 上调度容器。调度器将检查 Kubernetes 集群的可用性,并根据资源的可用性做出调度决策,从而可以适当调度容器。
controller-manager 是一个守护进程,允许 Kubernetes 主节点运行不同类型的控制器。控制器用于分析集群的状态,并确保集群处于期望的状态,因此,如果某个 Pod 失败,它将被重新创建或重启。它遵循指定的阈值,并由 Kubernetes 管理员进行控制。
Kubernetes 工作节点
工作节点是 Pod 运行的地方;每个 Pod 都有一个 IP 地址并运行容器。Pod 决定容器的所有网络设置,并管理容器如何在不同的 Pod 之间进行通信。
工作节点将包含管理容器间网络通信所需的所有服务,与主节点进行通信,并用于分配资源给已调度的容器。
Docker 也在每个工作节点上运行,用于从 Docker 注册中心拉取容器并调度容器。
Kubelet 是工作服务,并安装在工作节点上。它与 Kubernetes 主节点上的 API 服务器进行通信,获取 Pod 的期望状态信息。Kubelet 还从 etcd 读取信息更新,并写入关于集群事件的更新。
kube-proxy 负责负载均衡和网络功能,如路由数据包。
Kubernetes kubectl
Kubectl 是 Kubernetes 的命令行工具,用于向主节点发出命令来管理 Kubernetes 集群。它还可以用来调用 YAML 或 JSON 文件,因为它与主节点上的 RESTful API 服务器进行通信。
Kubernetes 服务作为 Pod 之上的抽象层创建,可以通过标签选择器进行访问。
在以下示例中,kubectl 可以用来创建一个带有选择器 app: nginx 的 loadbalancing_service 服务部署,该选择器由 loadbalancing_service.yml 文件定义:

Kubectl 通过指定来执行 YAML 文件:
Kubectl create –f loadbalancing_service.yml
Kubectl 然后可以使用 ReplicationController 创建四个副本 Pod,这四个 Pod 将由服务进行管理,因为标签 app: nginx 与服务的选择器匹配,并使用 nginx_pod.yml 文件在每个 Pod 中启动一个 NGINX 容器:

Kubectl 使用以下方式创建服务:
kubectl create –f nginx_pod.yml
Kubernetes SDN 集成
Kubernetes 支持多种网络技术,这些技术本身足以写一本完整的书。对于 Kubernetes,Pod 是网络的主要插入点。
Kubernetes 支持以下网络选项:
-
Google 计算引擎
-
Open vSwitch
-
二层 Linux 桥接
-
Project Calico
-
Romana
-
Contiv
Kubernetes 旨在提供一个可插拔的框架来控制 Pod 的网络配置,并希望为用户提供选择;如果需要一个平坦的二层网络,Kubernetes 可以满足这个需求;如果需要更复杂的三层覆盖网络,它也能应对。
Open vSwitch 广泛应用于企业 SDN 控制器,如 Nuage Networks VSP 平台,该平台在第二章中有所介绍,软件定义网络的出现,以及第六章,使用 Ansible 编排 SDN 控制器。这部分内容重点讨论了如何将流信息推送到每个虚拟化服务器上的 Open vSwitch,以创建有状态防火墙并管理 ACL 策略。
在集成 Kubernetes 时,执行类似的实现,Open vSwitch 部署到每个工作节点上,Pod 流量被转发到 Open vSwitch。
在 Nuage 的案例中,他们定制的 Open vSwitch 版本(称为 VRS)会部署到每个 Kubernetes 工作节点上,以管理由 VSD Nuage VSP 的策略引擎控制的策略。
Nuage SDN 与 Kubernetes 集成的工作流程如图所示,图中显示了企业 SDN 控制器如何与 Kubernetes 和 Docker 等编排引擎集成,以提供企业级网络:

容器对网络的影响
容器无疑意味着大量网络功能已经转移到应用层,因此,容器实际上可以被视为其最真实形式的 PaaS 提供。
当然,仍然需要基础设施来运行容器,无论是在裸机服务器上还是虚拟机上。使用虚拟机来长期运行容器的优点是有争议的,因为这在某种程度上意味着双重虚拟化,任何使用嵌套虚拟化的人都知道,这并不总是对性能最优。因此,随着更多组织使用容器来部署它们的微服务架构,这无疑意味着用户对是否在虚拟机或物理机器上运行容器的选择将会有需求。
云计算通常意味着虚拟机,因此在虚拟机上运行容器可能是出于必要性而非选择的结果。能够在裸机服务器上协调容器,并在其上方使用覆盖网络,肯定更具吸引力,因为这样可以将容器更接近物理机器资源,而没有虚拟化开销。
这使得容器能够最大化物理机器资源,用户只需关注是否能跨多个云和数据中心运行服务,从而实现真正的灾难恢复。
随着混合云解决方案的发展,业界正超越了仅考虑机架冗余的思维模式。相反,业界正在向一种新的模式转变,这种模式将专注于将应用程序分布到多个云提供商之间。因此,能够使用 Docker Swarm 或 Kubernetes 等编排引擎以相同的方式编排网络和应用程序,将有助于实现这一目标。
这对网络运维人员意味着什么?这意味着角色正在演变,网络工程师的角色变为顾问,帮助开发人员以最佳方式设计网络,以支持其应用程序的运行。与其在私有云中将网络建设作为副项目,网络运维人员可以专注于为开发人员提供作为服务的覆盖网络,同时使基础网络架构快速且高效,从而能扩展以满足开发人员的需求。
总结
容器被认为是虚拟化市场的主要颠覆者。Gartner 已预测如下:
“到 2018 年,超过 50-60%的新工作负载将在应用程序生命周期的某一阶段部署到容器中。”
这是基于 Gartner 对 IT 市场的分析,因此这是一个大胆的声明,但如果成真,它将证明是应用程序部署方式的巨大文化转变,正如虚拟化曾经带来的变化一样。
在本章中,我们展示了容器如何帮助组织部署微服务架构,并分析了容器带来的内部机制和好处。主要的好处包括可移植性、部署速度、弹性扩展、隔离和不同资源的最大化、性能控制、有限的攻击面以及对多种网络类型的支持。
除了容器带来的好处,本章还介绍了 Docker 工具,并说明了 Docker 工作流如何融入持续交付模型,而这一模型正是大多数 DevOps 项目的核心。
本章的重点随后转向了 Docker 网络和可用于网络化容器的第二层网络选项。我们展示了如何使用覆盖网络将多个主机连接起来,形成一个集群,并展示了容器技术如何通过 Open vSwitch 与 Nuage VSP 平台等 SDN 控制器进行集成。
本章还介绍了容器编排解决方案,如 Docker Swarm 和 Kubernetes,它们独特的架构,以及如何将它们用于在多个主机上网络化容器,并作为平台即服务(PaaS)层。
容器化的重要性及其对平台即服务(PaaS)解决方案的影响不容小觑,Forrester 曾表示:
“容器即服务(CaaS)正在成为新的平台即服务(PaaS)。随着开发人员对容器和微服务的兴趣激增,云服务提供商正在通过托管的容器管理服务抓住这一机遇。”
总结来说,可以公正地得出结论,容器化可以带来许多好处,并帮助开发人员实现持续交付工作流和 PaaS 解决方案。容器化还提供了跨多个云提供商(无论是私有云还是公有云)部署工作负载的额外灵活性,使用像 Kubernetes、Apache Mesos 或 Docker Swarm 这样的通用编排层。
在接下来的章节中,重点将从容器转向在使用软件定义的覆盖网络和持续交付模型时确保网络安全。它将探讨一些技术,这些技术可以帮助在 API 驱动的环境中保障现代私有云的安全,以便在不妥协安全要求的情况下实现软件定义网络解决方案。
第十一章:网络安全
随着许多企业转向软件定义网络并使用 API 进行网络变更,确保网络安全的重要性成为一个突出问题。安全实施也需要发展,因为网络被虚拟化,并且现代协议用于构建 Leaf-Spine 架构以扩展多租户云环境。
本章将涵盖以下主题:
-
网络安全的发展与破解误区
-
保护软件定义网络
-
网络安全与持续交付
网络安全的发展与破解误区
随着网络工程师逐渐适应第一章中讨论的平面二层网络和生成树协议,云对网络的影响,网络安全及确保企业网络的方式在多年的发展中变得非常成熟,且已被安全团队充分理解。
大多数安全工程师对处理物理网络时应该实施的最佳实践都很熟悉。安全团队通常会实施一套严格的安全最佳实践,网络团队必须遵守这些实践,才能通过必要的认证。但是,这些最佳实践在实施软件定义网络时的适用性如何?
可以公平地说,目前仍然存在有关软件定义网络的知识差距,安全工程师甚至一些网络工程师对未知充满恐惧和不确定性。
本章希望能够帮助解开一些相关疑虑。作者是一个帮助运营软件定义网络的人员,这些内容并非理论或期望,而是基于坚实的事实。
所以,首先让我们回顾一下安全团队对网络安全的一些要求,并看看在处理软件定义网络时这些要求应如何调整。
帐户管理
在帐户管理方面,安全团队通常会要求在设置用户访问时遵循以下最佳实践:
-
访问生产服务器时应使用双因素认证
-
用户帐户应遵循最小权限原则,确保用户只拥有必要的权限
-
测试环境与生产环境之间应使用独立的用户帐户
-
DenyAll 应该是访问控制列表的默认设置
-
使用终端访问控制器访问控制系统(TACACS)或同等的认证方式来访问网络设备
在审查帐户管理时,安全从业者列出的所有要点仍然有效。任何软件定义网络(SDN)控制器或现代交换机厂商在评估时应该满足帐户管理要求。如果它们未满足这些要求,便不应在生产环境中实施。
当使用软件定义网络,并始终与持续交付模型保持一致时,服务账户将被自动化编排和配置管理工具(如Ansible)用来设置子网、网络和ACL策略,以执行任何网络更改。
提交到源代码管理系统的用户将不可避免地成为触发网络更改的人员,尽管这些更改是通过服务账户执行的。这个过程本身就是一种文化上的转变,因此应审查源代码管理库上的权限,以设置Active Directory 域服务(ADDS)或轻量级目录访问协议(LDAP)的访问权限,这样就可以追踪提交记录,并追溯到进行更改的用户。持续交付工具如Jenkins、ThoughtWorks、Go或其他许多持续集成构建服务器,可以满足这个需求。
可以使用单独的服务账户来编排测试和生产环境,以满足安全最佳实践。持续交付模型中的所有其他用户账户应为只读权限,用户可以查看由自动化驱动的持续交付部署的结果,除非是破玻账户,在紧急状态下可用。
安全团队必须理解,如果用户在不可变的软定义网络中进行手动干预,那么整体的持续交付模型可能会被破坏,因此没有进行手动配置的空间。所有的期望状态应通过源代码管理系统进行控制,并相应地推送到系统中。这再次是一个思维方式的转变,安全从业人员通常难以相信这一点,因为他们多年来一直看到网络工程师通过手动变更设备来做出任何修改,但这是一种新的方法,对于某些人来说是一个巨大的变化。
这一点在第九章《使用持续交付流水线部署网络变更》中得到了说明,文中提到,利用像 Ansible 这样的配置管理工具,将网络变更推送到测试和生产环境时:

这一概念最初对于安全从业人员来说难以理解,但DevSecOps运动正在帮助安全从业人员看到自动化持续交付过程带来的机会窗口。
自动化应意味着用户拥有更少的个人权限,并且批准的工作流操作是经过强化和签署的,控制允许进行何种交互。所有这些都通过持续交付流水线进行控制。
网络设备配置
关于网络设备配置的安全最佳实践,关注的是保持网络的最新可审计清单,定期对每个网络设备的操作系统层进行安全补丁更新,并使用来自相关信任存储的安全协议和公钥基础设施(PKI)证书。
因此,安全团队在配置网络设备时,常见的一组要求可能包括:
-
网络硬件清单应在IP 地址管理(IPAM)解决方案中可用
-
所有网络设备应定期进行补丁更新
-
配置 SNMP 版本 3 或以上
-
禁用未使用的端口
-
使用传输层安全协议(TLS)加密网络流量
网络设备配置的安全方法在设置上也不应改变,因为 SDN 控制器和现代交换机厂商应采用 TLS,定期打补丁,并通过 DNS 进行访问。
在使用 Leaf-Spine 架构和覆盖网络时,底层网络仍由物理网络设备构成,因此与这些设备相关的配置和安全最佳实践仍然完全有效且不可或缺。
SDN 控制器,如同网络交换机,部署在第二层底层网络上,因此应遵循与网络交换机相同的惯例,采用安全协议,并遵守补丁更新计划。
防火墙
安全团队在业内审视软件定义网络时的一个主要困惑源似乎与防火墙相关,部分人存在一些恐惧和不确定性,因为他们习惯在生产网络中使用物理有状态防火墙。
然而,只要虚拟防火墙满足安全要求,实现 SDN 控制器并允许它们通过虚拟化的微分段策略控制防火墙和网络分段应该没有问题。
安全团队通常会要求防火墙满足以下要求:
-
使用有状态防火墙
-
在 ACL 规则上使用显式许可和隐式拒绝
-
具备审核团队 ACL 访问权限的能力
-
记录防火墙上所有被拒绝的访问尝试
实施软件定义网络时应始终遵循防火墙最佳实践;然而,传统上,安全团队一直推动使用有状态的物理防火墙来分隔三层模型,三层分别为前端、业务逻辑和后端。
随着向微服务的迁移和软件定义网络(SDN)的采用,应用程序通常不适应这种结构,而Open vSwitch允许使用 OpenFlow 在虚拟化管理程序级别或操作系统主机级别实施入口和出口策略。
我们还看到,这一相同的过程可以应用于第十一章,容器对网络的影响,并且 Open vSwitch 可以安装在容器主机上,如 Core OS,甚至在裸金属服务器上,以控制防火墙策略。
只要遵循使用显式允许和隐式拒绝的最佳实践原则,并为防火墙上的所有拒绝尝试设置日志记录过程,那么就没有理由反对使用虚拟化防火墙的优点。
Open vSwitch 现在提供有状态防火墙功能,安全性与 Linux 操作系统上的 iptables 或物理防火墙相同,因此现在没有理由不将防火墙虚拟化用于企业网络。这与最初关于使用虚拟机管理程序进行基础设施服务的讨论相似,但它在可扩展性、可编程性、可审计性和可管理性方面为企业带来的好处,使得难以反对防火墙虚拟化。
漏洞检测
就漏洞和攻击的检测而言,叠加网络的安全要求也不应发生变化,尽管获取数据的方法可能需要稍微改变,因为像边界网关协议(BGP)和虚拟可扩展局域网(VXLAN)这样的协议需要不同的工具来跟踪网络中的数据包。
在进行漏洞检测和数据采样时,以下活动应定期安排:
-
定期漏洞扫描
-
深度数据包检查
在漏洞扫描方面,应当频繁地对网络及网络设备进行扫描。理想情况下,安全扫描器本身应在软件定义网络中具有独立的职责。安全扫描器应当能够访问基础网络进行全面扫描,另一个扫描器配置文件应当用于叠加网络。如果扫描器能够访问基础网络和叠加网络,它就会成为攻击向量,一旦被攻破,攻击者便能完全访问网络。因此,这是一个常常被忽视的重要问题;如果可能的话,叠加网络和基础网络设备及计算资源不应互相可路由。
安全团队通常要求能够通过深度数据包检查来检查网络数据包,以确保没有恶意活动。这在平面二层网络中已通过检查在 VLAN 之间传输的数据包来完成。
然而,随着叠加网络通过 VXLAN 封装传输数据包,网络能够扩展并缓解 4096 VLAN 限制。这意味着网络和安全团队将需要能够解封装 VXLAN 数据包的工具,以便像检查 VLAN 数据包一样检查数据包,否则安全工具将看到数据正在传输,但无法读取它。
设置能够进行 VXLAN 去封装的工具并非不可逾越的挑战。已有可用工具来完成这项任务,只需网络和安全团队调整他们当前使用的工具。
网络分段
实施软件定义覆盖网络时的最大变化之一是从平面二层网络原则和网络间的 VLAN 隔离转变过来。
安全团队习惯于处理物理网络,因此他们通常会规定需要满足以下要求:
-
使用 VLAN 来隔离流量类型(前端、业务逻辑和后端)
-
能够隔离测试和生产环境
-
在不同的网络层之间使用防火墙
然而,SDN 控制器在网络交换机上的硬件虚拟隧道端点(VTEP)之间创建 VXLAN 隧道,并将其扩展到每个硬件计算节点,以便在网络上构建虚拟化的覆盖基础网络。
SDN 控制器用于翻译来自交换机厂商的Open vSwitch 数据库(OVSDB)信息,并将流量数据推送到每个计算节点(虚拟化管理程序、容器或裸机服务器),这些都由 SDN 控制器的策略引擎决定,以创建防火墙和微分段。
这是一种不同的方法;每个微服务应用的防火墙由OpenFlow控制,并用于管理入口和出口策略。通过使用覆盖网络,应用可以与其他应用的微分段区域进行通信,如第二章中所示的Nuage Networks 虚拟服务平台(VSP)所示,软件定义网络的出现。
在以下示例中,我们可以看到应用 1的微子网通过子网与区域进行通信,和应用 2进行通信:

使用按应用划分的防火墙规则进行微分段,避免了使用物理有状态防火墙对所有应用进行区域分段。相反,每个应用都会创建单独的防火墙来管理网络之间的分段,三层域会在更高层次上将测试和生产环境相互隔离。
在这种微分段模型中,每个应用都有自己的策略,这意味着安全团队能够审计防火墙策略,并了解每个应用与哪些应用进行通信。
因此,覆盖网络应该带来安全上的提升,因为它清晰地展示了应用的连接要求,并且连接拓扑不再丢失在一组庞大的物理有状态防火墙的访问控制列表(ACL)规则中,这些规则并未明确映射到每个应用上。
软件定义网络意味着每个应用初始时拒绝所有连接,仅开放最小的显式访问权限,以便它们能够访问网络中的其他应用或服务。
这比在有状态防火墙上开放端口范围要安全得多,因此,理论上,叠加网络在正确实施时应能提高复杂网络的安全性。如果使用了如第六章中所强调的不可变网络(如 A/B 子网),使用 Ansible 编排 SDN 控制器,那么旧的 ACL 规则也会默认自动清理,这一直是网络和安全团队面临的挑战,因为他们担心删除旧的策略会导致特定应用程序出现故障。
安全团队可以与开发团队一起审核这些策略,并提供任何需要更改的建议,确保开发团队实施的所有 ACL 策略都是部署应用程序所必需的,并且使用的显式入口和出口 ACL 规则的数量是最小的。
保护软件定义网络
到目前为止,本章重点介绍了一组最小的网络安全要求,以确保软件定义网络的安全性。
但为了最大化软件定义网络的安全性,我们应该关注叠加层和基础层网络如何可能被攻击者以新方式利用,并探讨可以采取的不同机制,以防止这种情况的发生。
软件定义网络被分为叠加层(包含所有虚拟化网络,承载虚拟机、物理机和容器)和基础层(包含所有裸机设备,如虚拟化管理程序、网络设备和 SDN 控制器)。
在叠加层的攻击
叠加层网络的创建旨在通过 API 以编程方式自动化网络,并通过简化软件中的网络结构来加快变化速度。
在持续交付的范围内,开发人员可以设置自服务的 ACL 规则来管理南北向和东西向的 ACL 策略。
重要的是要有隐式控制,确保常见工作流操作只允许团队从其微子网设置 ACL 规则到网络中的其他位置,而且他们不能妥协叠加层中任何其他网络的完整性,除了他们自己的网络。因此,应通过测试自服务自动化来向安全团队证明这一点。
微分段在以下示例中非常强大:
使用隐式允许时,团队 A 中的应用程序 1 只能与团队 B 维护的应用程序 2 通信,如果团队 B 允许显式入口规则来允许应用程序 1 与之通信。因此,团队之间需要协调,他们的应用程序只有在每个微服务应用程序的防火墙上都有出口和入口规则时,才能相互通信。
除此之外,一些应用可能需要向北的互联网访问,因此网络团队需要建立一个代理机制来访问互联网,而不是直接给团队提供访问权限。网络团队应实施受控的代理机制,以便有一个固定的机制来管理向北的互联网访问。
攻击者可能会试图攻破覆盖网络中的虚拟机或物理服务器。一旦他们获得对机器的访问权限,可能会尝试下载软件并破坏网络。攻击者还可能尝试进行拒绝服务攻击(DoS),以破坏特定的微子网,这可能会通过攻破微子网中的所有虚拟机来破坏关键服务。
微分段相对于二层网络的一个好处是,如果生产环境中的一台主机被攻破,攻击者可以访问整个前端、业务逻辑或后端区域,而在微分段的情况下,他们会被限制在特定的应用程序中。
关于外向互联网访问和设置代理,至关重要的是用于下载软件包到主机的上游仓库应该通过受控的代理服务器进行,使用基于角色的访问控制(RBAC),通过 Active Directory 域服务或 LDAP,如 Artifactory 或 Nexus。
这意味着覆盖网络中的服务器只能访问一组经过基础设施团队批准的第三方软件仓库。未经批准的仓库无法通过覆盖网络服务器访问,因为它们不通过软件仓库代理,从而防止将可疑的软件包安装到覆盖网络中的服务器上。
通过软件仓库代理意味着网络和安全团队可以采取措施,防止下载数据包嗅探软件到服务器上,从而发现相邻服务或由入口和出口流量数据决定的开放端口。
还可能需要禁用互联网控制消息协议(ICMP),以防攻击者通过路由追踪找到微子网中相邻服务器的 IP 地址或底层网络设备(如机架顶端交换机和 SDN 控制器)的地址。
如果覆盖网络中的服务器记录丢包,那么应该设置适当的警报,通知网络或安全团队,某些非法活动正在微子网内发生。
在这种情况下,可以通过标记被攻击的主机并使用像 Ansible 动态库存等工具来将它们整体定位,发出关闭命令或通过实时迁移将它们移至隔离网络,从而阻止潜在的网络攻击者访问网络中的其他服务器。
对底层网络的攻击?
下层网络可能成为潜在攻击者的目标,攻击者通过访问虚拟化管理程序并寻求妥协 Open vSwitch 来实现这一目标。这将使他们能够直接在 Open vSwitch 的流表中实例化新流,从而访问网络中的多个不同位置。
攻击者可能会嗅探流量,并对不同的网络组件执行 中间人攻击(MitM),因此虚拟化管理程序理想情况下应位于一个独立的网络上,以隔离计算服务器的访问,并且不允许从覆盖网络直接路由。
在下层网络中,交换机现在利用集中管理系统将更新推送到交换机。例如,Arista CloudVision 平台的 CloudVision eXchange(CVX)服务器用于将配置推送到所有 Arista 交换机,因此必须通过 HTTPS 来控制对其 API 端点的访问,并且交换机的管理应在完全独立的网络上进行。
如果 CVX 集群被妥协,攻击者可能会丢失每台交换机的整个配置,从而在网络上发起 DoS 攻击,这也意味着 SDN 控制器将丢弃所有路由。
应该理想地实现 带外(OoB)网络来管理对网络设备的访问,访问应通过 TACCs 账户提供。使用带外网络进行北向和南向通信可以帮助保护网络设备,并为网络设备提供额外的安全性。
下层和覆盖网络应位于完全不同的网络上,并且不可路由;这意味着如果下层网络中的虚拟化管理程序被妥协,攻击者将无法直接从下层网络跳转到覆盖网络。下层设备理想情况下应通过堡垒服务器和双因素认证进行保护,以确保没有服务器是直接可访问的。
SDN 控制器通常是 x86 计算机,并通过 REST API 调用进行通信,因此必须在 SDN 控制器上实现 TLS,如果可能的话,还应颁发 PKI CA 来管理信任、真实性和访问撤销。
在以下示例中,我们可以看到 Arista CVX 平台使用 TLS 与下层网络中的 Nuage VSC SDN 控制器通过 OVSDB 进行通信:

如果下层设备通过 HTTP 会话进行通信,则会使网络不仅容易受到下层网络的攻击,还容易受到覆盖网络的攻击。
以 OpenStack 平台为例,SDN 控制器与 OpenStack Neutron 插件通信时,将交换整个覆盖网络的所有入口和出口信息。如果此连接使用未加密的 REST API 调用,这意味着攻击者可以拦截或跟踪所有流量信息,并可能用此信息妥协覆盖网络中的任何租户网络。
SDN 控制器的攻击
SDN 控制器上的北向 API 是一个理想的攻击向量,攻击者可以利用它来破坏整个覆盖网络。
为了防止这种情况,应实施 RBAC 并遵守足够的密码最佳实践。如果 SDN 控制器的北向 API 被攻破,攻击者可能会通过编程方式对覆盖网络创建新的流量数据。
这将使攻击者能够横向穿越网络并瞄准多个服务,从而绕过拒绝的防火墙策略并访问多个租户网络。
默认管理员账户应从第一天起更改其密码,以避免攻击者猜测默认账户的密码。始终应使用复杂密码。
应在 SDN 控制器上设置审计跟踪,并将日志记录到syslog服务器,这将允许网络和安全工程师检查攻击者是否进行了未经授权的更改。如果出现任何不正常的行为,应立即触发后续警报,并禁用该账户。
在 SDN 控制器上,应启用 SNMPv3 而不是早期版本,并设置 LDAP 账户或 SSH 密钥,以允许访问基于 Linux 的操作系统,而不是使用单一服务账户或 root 权限进行底层变更。
网络安全与持续交付
在使用自动化将网络更改推送到网络设备,或更改覆盖网络的期望状态时,应提升网络安全性。它应增加更改的可视性,因为所有更改都是通过集中式过程完成的,没有任何例外。
持续交付过程在设计上应允许安全团队清楚地看到哪个用户提交了网络变更。当通过持续交付过程将更改推送到网络设备或 SDN 控制器时,如果安全团队不批准这些更改,它将允许轻松回滚到先前的版本。然而,这仍然是非常被动的,持续集成和交付过程应将合规性和安全检查作为持续集成和交付过程的一部分。
将合规性检查作为持续交付的一部分,为网络和安全团队提供了很大的灵活性。这将使安全团队能够利用一些持续集成和交付的最佳实践来帮助保护网络,例如在部署管道的一部分中持续测试和验证集成的更改。
应用程序连接拓扑
在软件定义网络中,每个应用程序都是微分段的,因此它们具有可以由安全或网络团队审计的单独应用程序策略。这有助于安全合规性,因为它允许安全人员查看覆盖网络中特定应用程序的所有 Ingress 或 Egress 规则。
这一点在第二章,软件定义网络的出现中有详细阐述,展示了按应用程序细分的微分段策略,并为应用程序 1定义了 Egress 策略,如下所示:

应用程序的 Ingress 和 Egress ACL 规则应该可读并且可审计,可以使用 YAML 文件,或任何其他选定的配置文件来控制 SDN 控制器的期望状态,这些配置文件应存储在源代码管理系统中。
系统的实时状态也会出现在 SDN 控制器的图形用户界面(GUI)中,可以观察其是否与源代码管理系统中定义的内容一致。
安全从业人员必须能够读取和理解用于确定当前连接性和网络状态的配置文件。
网络和安全团队有着独特的目标,例如通过安全审计以保持业务的正常运转。安全团队能够查看应用程序连接矩阵并对连接进行全面可视化是非常重要的。
例如,在处理信用卡交易时,只有特定用户应该可以访问特定的租户网络。通过 SDN 强制执行这一点,并且通过易于理解的 SDN 策略证明这一点,可以使网络和安全团队的工作变得更容易,因为他们可以为每个应用程序提供实时的连接矩阵。
将安全检查纳入持续集成
安全检查理想情况下应内置于持续集成流程中,这一概念在第七章,使用持续集成构建进行网络配置中有深入探讨。否则,安全团队将无法跟上动态叠加网络和不断变化的网络策略所带来的日常变化。
合规性可以通过在开发人员为应用程序的自服务 ACL 文件应用的策略中禁止允许所有策略来与持续集成流程集成。
当用户将更改提交到源代码管理系统时,CI 构建服务器会启动一个新的持续集成构建。安全团队可以在持续集成构建过程中设置对 SDN 配置构建的验证,拒绝该配置并向用户提供即时反馈,因为这违反了合规性。
用户则需要将自服务 ACL 策略规则更改为隐式的,这样合规性就成了持续集成过程中的另一个验证,如下所示:

这与安全团队将 ACL 规则作为单独的手动检查进行审计相对立,后者当然会让违反安全策略的 ACL 规则漏网,使其进入生产环境,从而允许攻击者有可能利用应用程序的 ACL 规则过于宽松而进行攻击。这项验证甚至可以在CI 构建服务器之前进行,通过运行一个简单的 Git 钩子来完成,检测到 ACL 策略中的“允许所有”后拒绝提交。
使用云元数据
云元数据在 AWS、Microsoft Azure、Google Cloud 和 OpenStack 等公共和私有云中,以及其他云服务提供商中都是常见的使用方式。
使用特定元数据标记服务器有多种不同的用例,其中一部分用例在网络或安全团队应对特定网络安全挑战时可能会大有裨益。
正如本书中已涵盖的,云元数据是一系列应用于云服务器的键值对。如果我们以 2014 年导致一系列 DoS 攻击的安全漏洞 Shell Shock 为例,立即修复这些安全漏洞是非常重要的,以防止攻击者利用 Linux 服务器。
在持续交付的范围内,确保出现问题时,恢复的平均时间要尽可能短是非常重要的。
以漏洞扫描为例,每周,整个覆盖和底层网络都会使用安全扫描器进行日常扫描,最坏情况下为每周扫描一次。
每次每周的网络安全扫描运行在所有服务器上时,它会生成一份报告,记录每台服务器的漏洞列表。随后,服务所有者会对报告进行审查,安全团队将在数天内推荐特定的补丁或修复措施,因此如果重要漏洞被突出显示,解决问题的平均时间会较长。
如果网络安全扫描不是生成单独的报告,而是将特定的漏洞 ID 列表标记到服务器的云元数据中,那么整个网络的漏洞完整清单将可用,并可以据此进行实时更新。
以 OpenStack 为例,以下命令行可以在检测到漏洞时使用 qualys_vul_ids 键值对为服务器设置元数据:
nova meta-data (instance-uuid) set qualys_vul_ids (qualys_id_list)
以下示例将作为一个脚本的一部分执行,该脚本将在所有服务器上运行:
nova meta-data 061e8820-3abf-4151-83c8-13408923eb16 set qualys_vul_ids 23,122
这个键值对随后会传递给 OpenStack 元数据服务,后者会将所有在Qualys漏洞扫描过程中发现的相关漏洞标记到 OpenStack 实例上。
这将导致 OpenStack 实例包含以下元数据:

如果安全扫描暴露了诸如 shell shock 之类的漏洞,那么网络和安全团队可以识别出所有存在该漏洞的服务器。在这种情况下,Qualys ID 122与 shell shock 相关,并立即对受影响的服务器进行补丁修复。
可以使用 Ansible 动态清单通过一个定制的ad_hoc_patch.yml剧本,仅在满足条件时执行该剧本,来定位易受攻击的服务器。如果服务器上的qualys_vul_ids元数据标签上标记了Qualys ID 122,则执行补丁命令修复 Linux 服务器。
ad_hoc_patch.yml剧本将具有以下步骤:从元数据中设置事实,并仅在元数据标签包含正确的元数据时执行命令:

此剧本可以通过执行以下命令立即修复 shell shock Bashdoor漏洞:
ansible-playbook –i inventories/openstack.py –l Prod playbooks/ad_hoc_patch.yml
该剧本将对Prod可用区内所有面向客户的服务器执行补丁修复,针对存在漏洞的服务器,因此仅针对生产服务器。
该剧本仅对生产可用区中符合122元数据值的服务器执行,作为活动漏洞,使用Ansible jinja2中的过滤器,这将使基础设施工程师能够在几分钟内修复该漏洞。试想一下,如果安全扫描器将这种元数据标记作为其扫描器的一个功能,它将对安全性产生巨大帮助。
云元数据还有许多其他用例,例如在服务器上使用所有者元数据标签,如果安全团队检测到任何可疑活动,则发送有针对性的电子邮件或警报,或者在使用不可变基础设施时标记服务器进行重新部署以安装新补丁。
被攻破的服务器也可以通过安全监控工具使用元数据标记为隔离。简单来说,元数据允许团队通过元数据设置服务器配置文件,因此可以对其执行各种操作。
如果服务器被标记为隔离状态,可以设置触发器将服务器关闭,并将其迁移到 Overlay 网络中没有外部访问权限的隔离微网段。这将允许安全团队进行根本原因分析,查明服务器被攻破的原因并缓解攻击。
注意
需要注意的重要一点是,所有这些安全过程都可以自动化,以帮助最大化公共云和私有云提供的功能。它们应被视为可以帮助自动化和促进安全过程的工具,而不是妨碍安全的工具。
摘要
在本章中,我们探讨了网络安全以及安全实践如何发展以满足现代软件定义网络的需求,因为行业已经开始逐步远离扁平的二层网络,而是利用虚拟化的 Overlay 网络。
本章还希望揭示一些与保护软件定义网络相关的恐惧和不确定性,同时解决了如测试和生产环境的分离以及使用虚拟防火墙进行微分段的热门话题,而不是物理防火墙。
本章重点转向可以在最低安全要求之上采用的战略,并探讨了如何保护 SDN 控制器并最小化攻击向量的方法。这可以通过隔离网络、为网络设备创建带外网络、适当的身份验证以及使用 TLS 进行网络设备间通信来实现。
本章还探讨了实施软件定义网络带来的收益,例如应用间连接的透明性和可审计性。它还探讨了利用持续集成最佳实践来验证 ACL 策略作为持续集成构建的一部分,而不是完全分开的过程。它还探讨了利用云元数据执行紧急修补以减少手动开销的机会,并涵盖了其他使用云元数据的用例,如隔离服务器和向团队发送安全通知。
本章结束了本书的内容,探讨了如何将 DevOps 和持续交付原则应用于网络。本书希望向读者展示,网络不需要成为拖慢整个持续交付过程的一系列手动任务。
本书涵盖了多种主题,希望能提供一些思考的食物和可以采纳并实施以改善网络运营的想法。尽管网络自动化在行业中仍然相对稀少,但它并非必须如此;开发、基础设施和测试中应用的相同自动化原则同样适用于网络运营。
网络团队不应满足或接受现状,而是要大胆地发起真正的文化变革,并通过拥抱变革和学习新技能来帮助改进行业中的网络运营。
更多信息:
-
什么是软件定义网络:
www.youtube.com/watch?v=lPL_oQT9tmc -
SDN 基础知识:
www.youtube.com/watch?v=Np4p1CDIuzc -
SDN 和 OpenFlow:
www.youtube.com/watch?v=l-DcbQhFAQs







































浙公网安备 33010602011771号