《基础设施即代码,模式和实践》第一章:引入基础设施即代码

495 阅读24分钟

第一章:引入基础设施即代码

如果您刚开始使用公共云提供商或数据中心基础设施,您可能会感到不知所措,需要学习很多东西才能完成工作!在数据中心基础设施概念、新的公共云服务、容器编排器、编程语言和软件开发等方面,您需要进行大量的研究。

除了尽可能多地学习,您还必须满足公司创新和增长的要求。构建支持所有这些的系统变得具有挑战性。您需要一种支持更复杂系统、最小化维护工作量并避免对使用您的应用程序的客户造成干扰的方法。

要使用云计算或数据中心基础设施,您需要了解什么?如何在团队和组织中扩展您的系统?答案是基础设施即代码(IaC),它是以可编码方式自动化基础设施更改以实现可扩展性、可靠性和安全性的过程。

无论是系统管理员、站点可靠性工程师、DevOps工程师、安全工程师还是软件开发人员、质量保证工程师,每个人都可以使用IaC。无论您是刚刚运行了第一个IaC教程还是通过了公共云认证(祝贺!),您都可以将IaC应用于更大的系统和团队,以简化、持续和扩展您的基础设施。

本书通过将软件开发实践和模式应用于基础设施管理,提供了一种实用的IaC方法。本书介绍了测试、持续交付、重构和设计模式等实践,并赋予了基础设施的特点。您将找到一些实践和模式,帮助您管理基础设施,无论是自动化、工具、平台还是技术。

本书分为三个部分(图1.1)。第1部分介绍了您可以应用于编写IaC的实践,第2部分描述了团队在此上面进行协作的模式和实践。第3部分涵盖了跨组织扩展IaC的一些方法。

image.png

本书中的许多模式和实践涉及这三个方面的交集。个别编写良好的IaC有助于您更好地在团队和组织中共享和扩展。写得好的IaC有助于解决在IaC协作方面的问题,特别是随着越来越多的人采用它。

第1部分首先定义了基础设施,并解释了常见的IaC设计模式。这些主题涉及基础概念,帮助您将IaC扩展到团队中。您可能已经对本部分的一些材料很熟悉,因此请查看这些章节,为更高级的概念打下基础。

在第2部分和第3部分,您将学习到扩展系统和支持关键应用基础设施所需的模式和实践。这些实践从个人延伸到团队和组织,从为一个应用程序创建一个应用程序度量警报到在一个5万人组织中实施网络变更。这些部分的许多术语和概念相互构建,因此按顺序阅读章节可能会更有帮助。

什么是基础设施?

在我深入介绍IaC之前,让我们先从基础设施的定义开始。当我开始在数据中心工作时,文献通常将基础设施定义为提供网络、存储或计算能力的硬件或设备。图1.2显示了应用程序在服务器(计算)上运行,通过交换机(网络)连接,并在磁盘(存储)上维护数据。

image.png

这三个分类与我们在数据中心中管理的物理设备相匹配。我们通过刷身份证进入建筑物,插入设备,输入命令,并希望一切仍然正常来进行更改。随着云计算的出现,我们继续使用这些类别来讨论特定设备的虚拟化。

然而,数据中心对基础设施的定义并不完全适用于当今的服务和产品。想象一下,另一个团队请求你帮助他们将他们的应用程序交付给用户进行生产。你按照一个包括以下设置的清单进行操作:

  • 足够的服务器

  • 用户的网络连接

  • 用于存储应用程序数据的数据库

完成这个清单意味着团队可以在生产环境中运行该应用程序吗?未必如此。你不知道是否设置了足够的服务器或正确的访问权限来登录应用程序。你还需要知道网络延迟是否会影响应用程序的数据库连接。

在这个狭义的基础设施定义中,你忽略了一些对于生产就绪性至关重要的任务,包括以下内容:

  • 监控应用程序指标
  • 导出用于业务报告的指标
  • 为操作应用程序的团队设置警报
  • 为服务器和数据库添加健康检查
  • 支持用户认证
  • 记录和汇总应用程序事件
  • 在密钥管理器中存储和轮换数据库密码

你需要这些待办事项才能将一个可靠且安全的应用程序交付到生产环境中。你可能会将它们视为运营要求,但它们仍然需要基础设施资源。

除了与运营相关的基础设施外,公共云提供商还提供了基础网络、计算和存储的管理抽象,并提供平台即服务(PaaS)的解决方案,从存储桶等对象存储到托管的Apache Kafka等事件流平台。提供商甚至提供函数即服务(FaaS)或容器即服务等附加的计算资源抽象。不断增长的软件即服务(SaaS)市场,例如托管的应用性能监控软件,也可能需要支持生产中的应用程序,也可以视为基础设施。

由于服务的种类繁多,我们不能仅仅通过计算、网络和存储类别来描述基础设施。我们需要在应用程序交付中包括操作基础设施、PaaS或SaaS解决方案。图1.3调整了基础设施模型,包括额外的SaaS和PaaS服务提供,以帮助我们交付应用程序。

由于数据中心管理的不断复杂化、不同的运营模型和用户抽象,你不能将基础设施的定义局限于与计算、网络或存储相关的硬件或物理设备。

下面是一个非详尽的基础设施列表,你可能会遇到:

  • 服务器
  • 工作负载编排平台(例如Kubernetes,HashiCorp Nomad)
  • 网络交换机
  • 负载均衡器
  • 数据库
  • 对象存储
  • 缓存
  • 队列
  • 事件流平台
  • 监控平台
  • 数据流水线系统
  • 支付平台

扩展基础设施的定义为不同目的的资源管理团队提供了一种通用语言。例如,负责管理组织的持续集成(CI)框架的团队可以使用来自持续集成SaaS或公共云的计算资源的基础设施。另一个团队在该框架上进行构建,因此使其成为关键基础设施。

image.png

什么是基础设施即代码

基础设施的手动配置

作为网络团队的一员,我学会了通过从文本文档中复制和粘贴命令来更改网络交换机的配置。有一次,我不小心粘贴了"shutdown"而不是"no shutdown",结果关闭了一个网络接口!我赶紧将其重新打开,希望没有人注意到,也没有对任何事情产生影响。然而,一周后,我发现它关闭了与一个关键应用程序的连接,并影响了一些客户请求。

回顾起来,我在手动复制和粘贴命令以及基础设施配置方面遇到了一些问题。首先,我不知道我的更改会影响哪些资源(也被称为爆炸半径)。我不知道哪些网络或应用程序使用了该接口。

其次,网络交换机在没有测试其效果或检查其意图的情况下接受了我的命令。最后,没有其他人知道影响应用程序处理客户请求的原因,他们花了一个星期的时间才确定问题根源是我的命令错误。

将基础设施以编码方式编写如何帮助发现我误复制的网络交换机命令?我可以将配置和自动化存储在源代码控制下以记录命令。为了避免未来出现类似错误,我创建了一个虚拟交换机和一个测试,运行我的脚本并检查接口的健康状况。

在测试通过后,我将更改推进到生产环境,因为测试会检查正确的命令。如果应用了错误的命令,我可以搜索基础设施配置,确定哪些应用程序在受影响的网络上运行。关于测试实践,您可以参考第6章,关于还原更改,您可以参考第11章。

除了配置错误的风险外,手动配置基础设施有时会导致开发的进展变慢。曾经,我花了近两个月的时间来测试我的应用程序与数据库的配合。在这两个月里,我的团队提交了超过10个与创建数据库、配置新的路由连接应用程序和打开防火墙规则以允许我的应用程序相关的工单。平台团队在公共云中手动配置了所有内容。由于安全问题,开发团队没有直接访问权限。

换句话说,随着系统和团队的增长,手动配置基础设施通常无法扩展。手动更改增加了系统的变更失败率,减慢了开发速度,并使系统容易受到潜在的安全漏洞的攻击。您总是会有更新某些值的诱惑,但这些更改会逐渐累积。

对系统进行更改的下一个人可能会引入系统故障,而故障难以进行故障排除,因为更改未经过审计或组织。比如,在开发过程中更新防火墙以允许某些流量可能会意外地使系统容易受到攻击。

基础设施即代码

如果不进行手动更改,您应该如何改变基础设施?您可以使用基础设施资源和配置的软件开发生命周期,以IaC的形式进行应用。然而,基础设施的开发生命周期超越了配置文件和脚本。

基础设施需要进行扩展,处理故障,支持快速软件开发,并保护应用程序。基础设施的开发生命周期涉及更具体的模式和实践,以支持协作、部署和测试。在图1.4中,通过使用配置文件或脚本并将其提交到版本控制,简化的工作流程可以改变基础设施。提交操作会自动启动工作流程,对基础设施的更改进行部署和测试。

image.png

为什么您需要记住开发生命周期呢?您可以将其作为一种通用模式来管理变更,并验证这些变更不会影响您的系统。生命周期捕获了基础设施即代码的概念,它以一种编码的方式自动化基础设施变更,并应用了诸如版本控制和持续交付等DevOps实践。

我经常发现IaC被引用为DevOps的一种必要实践。它确实解决了CAMS模型(文化、自动化、度量和共享)中的自动化部分。图1.5将IaC定位为DevOps模型中自动化实践和理念的一部分。代码作为文档、版本控制、软件开发模式和持续交付的实践与我们之前讨论的开发生命周期工作流相吻合。

image.png

为什么将IaC作为DevOps模型中自动化的一部分进行关注?您的组织不必采用DevOps来使用IaC。它的好处可以提高DevOps的采用率和指标,但仍适用于任何基础设施配置。您仍然可以使用IaC的实践方法来改进基础设施变更的流程,而不会影响生产环境。

本书涵盖了一些将基础设施编码化的方法,以消除规模扩展时的阻力,同时为应用程序用户保持基础设施的可靠性和安全性,无论您使用数据中心还是云。软件开发实践,例如配置文件的版本控制、持续集成(CI)流水线和测试,可以帮助扩展和演进基础设施的变更,同时减少停机时间并构建安全的配置。

什么不是基础设施即代码?

如果您在文档中键入一些配置,那么您是否可以将其视为基础设施即代码(IaC)?您可能认为IaC包括在变更记录中添加配置说明。您可以认为构建队列的教程或配置服务器的Shell脚本都可以视为IaC。如果您能够使用这些示例来完成以下操作,则它们都可以是IaC的形式:

  • 可靠而准确地重现所表达的基础设施
  • 将配置还原到特定的版本或时间点
  • 沟通和评估对资源的变更的影响范围

然而,这些配置或脚本通常已经过时、未经版本控制或意图不明确。您甚至可能发现自己难以理解和修改用IaC工具编写的配置。该工具可以促进IaC工作流程,但并不一定包含允许系统增长并减少运维责任和变更失败的实践和方法。您需要一套原则来识别IaC。

基础设施即代码的原则

正如我之前提到的,与基础设施相关的每个代码或配置都不能保证可扩展性或减少停机时间。在本书中,我强调了IaC原则如何适用于特定的代码清单或实践。您甚至可以使用这些原则来评估您的IaC。

尽管其他人可能会增加或减少这些原则的列表,但我记住了四个最重要的原则,使用了“RICE”这个记忆法。这代表了可重现性(Reproducibility)、幂等性(Idempotency)、组合性(Composability)和可演进性(Evolvability)的首字母缩写。我在下面的部分中定义并应用了每个原则。

可重现性

想象一下,有人请您创建一个带有队列和服务器的开发环境。您与您的团队成员共享一组配置文件。他们使用这些配置文件在不到一个小时内重新创建了一个新的环境。图1.6显示了您如何共享您的配置并使您的团队成员能够复制一个新的环境。您发现了可重现性的威力,这是IaC的第一个原则!

为什么IaC需要符合可重现性原则呢?能够复制和重用基础设施配置可以节省您和团队的初始工程时间。您不必重新发明轮子来创建新的环境或基础设施资源。

image.png

然而,坚持可重现性原则比复制粘贴配置更加复杂。为了说明这种细微差别,想象一下您需要将网络地址空间从/16减小到/24。您已经编写了表达网络的IaC。然而,您决定选择简单的方法,直接登录到云提供商,并在文本框中键入/24。

在登录到云提供商之前,您反思一下您的变更工作流程是否符合可重现性。您向自己提出以下问题:

  • 您的团队成员会知道您已更新了网络吗?
  • 如果运行您的配置,网络地址空间会返回到/16吗?
  • 如果使用版本控制中的配置创建一个新的环境,它的地址空间将为/24吗?

您对这些问题的回答都是否定的。您无法保证您能成功重现手动更改。

如果您继续在云提供商的控制台中输入/24,那么您的网络就会偏离其在IaC中表达的期望状态(图1.7)。为了符合可重现性,您决定将版本控制的配置更新为/24并应用自动化。

image.png

这个场景展示了符合可重现性的挑战。您需要最小化预期和实际基础设施配置之间的不一致,也称为配置漂移。

作为一种实践,您可以通过将配置文件放入版本控制,并尽可能保持版本控制的更新来确保可重现性原则。保持可重现性原则有助于更好地进行协作,并管理与生产环境类似的测试环境。

在第6章中,您将学习有关基础设施测试环境的更多内容,这些环境受益于可重现性。您还将在测试和升级基础设施的实践和模式中应用可重现性,从创建模拟生产环境的测试基础设施到部署新的基础设施以替换旧系统(蓝绿部署)。

幂等性

有些基础设施即代码包括可重复性作为一个原则,这意味着运行相同的自动化代码会产生一致的结果。但我认为基础设施即代码需要更严格的要求。运行自动化代码应该导致基础设施资源达到相同的最终状态。毕竟,我编写自动化代码的主要目标就是能够多次运行并获得相同的结果。

让我们来思考一下为什么基础设施即代码需要更严格的要求。假设你编写了一个网络脚本,首先配置一个接口,然后重启交换机。第一次运行该脚本时,交换机会配置接口并重启。你将这个脚本保存为版本1。

几个月后,你的队友让你再次在交换机上运行该脚本。你运行脚本,交换机重新启动。然而,重新启动导致一些关键应用程序断开连接!你已经配置了网络接口,为什么需要重新启动交换机?

你找到了一种方法,可以在已经配置了网络接口的情况下避免交换机重启。在图1.8中,你创建了脚本的版本2,并添加了一个条件判断语句。该语句在重新启动交换机之前检查是否已经配置了接口。当你再次运行版本2的脚本时,不会导致应用程序断开连接。

条件判断语句符合幂等性原则。幂等性确保除非你改变配置或发生了漂移,否则可以重复运行自动化代码而不会影响基础设施。如果基础设施的配置或脚本具有幂等性,你可以多次运行自动化代码而不会影响资源的状态或可操作性。

image.png

在基础设施即代码中遵循幂等性原则,例如在网络脚本的案例中,有什么好处呢?在这个示例中,你希望避免重新启动网络交换机,以保持网络的正常运行。你已经配置了网络接口,为什么还要再次配置它呢?只有在接口不存在或发生更改时,才需要配置接口。

如果没有幂等性,你的自动化可能会意外地出现问题。例如,你可能重复运行一个脚本并创建了一组新的服务器,使它们的数量加倍。更严重的是,你可能自动化了一个数据库更新,结果却将一个关键数据库删除了!

你可以通过检查脚本和配置的可重复性来确保幂等性原则。作为一般实践,在运行自动化之前,包含一些条件语句来检查配置是否与预期相匹配。条件语句有助于在需要时应用更改,并避免可能影响基础设施可操作性的副作用。

设计具有幂等性的自动化能够降低风险,因为它鼓励包含逻辑来保持系统的最终预期状态。如果自动化失败一次并导致系统中断,组织可能不再希望自动化,因为它被认为存在风险。在第11章中,当你学习如何在部署之前安全地向前滚动更改并预览自动化更改时,幂等性将成为一个指导原则。

组合性

你希望可以混合匹配任何工具或配置的基础设施组件集。你还需要更新各个配置而不影响整个系统。这两个要求都促进了模块化和解耦基础设施依赖关系,你将在第3章和第4章中学到更多相关内容。

例如,想象一下,你为一个应用程序创建基础设施,该应用程序通过 hello-world.com 进行访问。下面是一个安全且适用于生产环境的最低配置所需的资源:

  • 一个服务器
  • 一个负载均衡器
  • 一个为服务器创建的私有网络
  • 一个为负载均衡器创建的公共网络
  • 一个用于允许私有网络中的流量出口的路由规则
  • 一个用于允许公共流量到达负载均衡器的路由规则
  • 一个用于允许负载均衡器流量到达服务器的路由规则
  • 一个用于 hello-world.com 的域名

你可以从头开始编写这个配置。然而,如果你找到了预先构建的模块,这些模块可以将基础设施组件组合在一起使用来构建系统,会怎么样呢?现在你有了多个模块,可以创建以下内容:

  • 网络(私有网络和公共网络,用于从私有网络中路由流量的网关,用于允许私有网络中流量出口的路由规则)
  • 服务器
  • 负载均衡器(域名,用于允许负载均衡器流量到达服务器的路由规则)

在图1.9中,你选择了网络、服务器和负载均衡器模块来构建你的生产环境。后来,你意识到你需要一个高级负载均衡器。你将标准负载均衡器替换为高级负载均衡器,以便能够提供更多的流量。服务器和网络继续运行,不会影响用户。

你的团队甚至可以在环境中添加一个数据库,而不会影响负载均衡器、服务器或网络。你可以以不同的组合方式对基础设施资源进行分组和选择,这符合可组合性的原则。

image.png

你的配置越具有可组合性,创建新系统的难度就越小。可以将你的IaC想象成积木一样的构建块。你希望能够更新或演进资源的子集,而不会使整个系统崩塌!如果你不考虑IaC的可组合性,就有可能因为复杂基础设施系统中的未知依赖关系而导致变更失败的风险。

可组合性的自助服务优势可以帮助你的组织扩展,并使团队能够安全地与基础设施系统进行交互。第3章和第4章将探讨一些模式,帮助你更好地构建模块化基础设施并提高可组合性。

可演进性

你希望考虑到系统的规模和增长,但不要过早或不必要地进行配置优化。基础设施配置很多时候会随着时间的推移而发生变化,包括其架构。

举个实际的例子,你可能最初将一个基础设施资源命名为"example"。后来,你需要将资源名称更改为"production"。你开始进行更改,查找并替换数百个标签、名称、依赖资源等内容。这个查找和替换的过程需要高强度的工作量。

当你应用这些更改时,你注意到有些字段你忘记修改了,导致新的基础设施更改失败。为了确保将来名称、标签和其他元数据的演进,你可以创建一个变量来表示名称,并且配置文件引用该变量。在图1.10中,你更新了全局的NAME变量,这个变化会传播到整个系统中。

image.png

这个例子看起来似乎过于简单了。为什么改变一个名称会有影响呢?以"可演进性"作为原则构建的IaC可以最小化改变系统所需的工作量(时间和成本),并降低变更失败的风险。

系统演进包括超出名称更改等较小变化的变化。基础设施架构中更为重大的变化可能涉及将Google Cloud Bigtable替换为Amazon Elastic Map Reduce(EMR)。需要进行替换的应用程序已经使用Apache HBase进行了未来验证,Apache HBase是一种支持这两种解决方案的开源分布式数据库,只需提供数据库的终端节点即可。

我们通过将数据库终端节点输出为输出,以便检索应用程序,并在幕后完成创建两种解决方案的配置来考虑这种演进。在测试完Amazon Web Services(AWS)数据库后,我们将其终端节点输出供应用程序使用。

注意:本书未对演进架构的理论进行全面介绍。如果您想了解更多信息,我强烈推荐阅读Neal Ford等人的《Building Evolutionary Architectures》(O'Reilly,2017),该书讨论了如何构建基础设施架构以应对变化。

如果您没有使用允许系统变化的模式和实践,可能会发现自己在演进系统方面遇到困难。有用的IaC侧重于使用技术来促进未来的演进。本书中的许多章节展示了帮助保持可演进性并将对关键系统变化的影响降到最低的模式。

应用这些原则

可再现性、幂等性、可组合性和可演化性在其定义上似乎具体明确。然而,它们都有助于限定您的基础设施架构,并定义了许多IaC工具的行为。您的IaC必须与这四个原则保持一致,以实现规模化、协作和变革公司。图1.11总结了这四个重要原则及其定义。

image.png

在编写IaC时,要问自己是否符合这四个原则。这些原则有助于您以更少的努力编写和共享您的IaC,并在理想情况下最小化对系统的更改影响。缺少一个原则可能会阻碍对基础设施资源的更新,或增加潜在故障的影响范围。

在实践IaC时,要问自己您的配置或工具是否与实践相符。例如,可以针对工具提出以下问题:

  • 该工具是否允许您重新创建整个环境?
  • 当您重新运行工具以强制配置时会发生什么?
  • 您是否可以混合和匹配各种配置片段来创建一组新的基础设施组件?
  • 该工具是否提供帮助您在不影响其他系统的情况下演化基础设施资源的能力?

本书使用这些原则来回答这些问题,并为您提供在测试、升级和部署基础设施时考虑弹性和可扩展性的技能。

为什么要使用基础设施即代码

IaC通常被视为DevOps的实践。然而,您并不需要在整个组织中应用DevOps才能使用它。您仍然希望以一种管理基础设施的方式来降低变更失败率和解决故障的平均时间(MTTR),这样作为运维人员,您可以在周末睡个懒觉,作为开发人员,您可以有更多时间编写代码。即使您认为自己不需要,使用IaC仍有几个理由。