第 1 章 挑战与原则

第 1 章 挑战与原则

新一代的基础设施管理技术有望改变 IT 基础设施的管理方式。但是,许多组织目前并没有看到显著的差异,有些甚至认为这些工具让管理更为混乱。我们将在本书中看到,基础设施即代码的方法提供了有效应用这些技术的原则、实践与模式。

1.1 为什么采用基础设施即代码

虚拟化、云、容器、服务器自动化和软件定义网络(software-defined network,SDN)理应简化 IT 运维工作。服务的置备、配置、更新和维护理应花费更少的时间和精力。问题应该被迅速地发现和解决,系统配置应该全部一致并且及时更新。IT 人员应该减少在日常苦差事上投入的时间,有余暇快速地执行变更和改进,以帮助组织适应现实世界里不断变化的需求。

然而,即便拥有最新、最好的工具和平台,IT 运维团队也很难完成每天的工作。他们没有时间去解决系统长期存在的问题,更没有时间去掌握这些最新的工具。事实上,云和自动化往往让事情变得更糟。新基础设施的置备(provision)很容易,导致系统组合不断增长,而防止这一切崩溃又需要投入越来越多的时间。

采用云和自动化工具立刻降低了基础设施变更的门槛,但这些工具并没有可以提高一致性和可靠性的现成方法来管理变更。这需要人们去思考如何使用这些工具,并且形成高效使用它们的系统、流程和习惯。

一些 IT 组织使用他们在云和自动化时代以前用于管理基础设施和软件的流程、结构和治理方式来应对挑战。但是,那些原则在需要花费几天或几周来置备新服务器的时代或许有效,而在当今这个只需要几分钟甚至几秒钟就能完成同一任务的时代,它们已经力不从心了。

急着完成任务的人们往往会忽略、绕过或者否决传统的变更管理流程。1 可以越来越多地看到,成功推行这些流程的组织被技术上更灵活的竞争对手超越。

1“影子 IT”是指人们绕过正式的 IT 管理,使用自己的设备,并且购买和安装未受认可的软件,或者采用云托管服务。这个迹象表明内部 IT 无法跟上所服务组织的需求。

传统的变更管理方法难以应对云和自动化提供的变更节奏。尽管云和自动化工具导致系统日益增长、不断变化,我们仍然需要积极应对。这就是基础设施即代码 2 的用武之地。

2“基础设施即代码”(infrastructure as code)这个说法并没有明确的来源或作者。在写作本书时,我关注了一群影响了这一概念的人,而每个人都说自己没有创造这个概念,只是提供了一些建议。他们之间互相进行了借鉴。我能找到对其的最早引用出于 2009 年 Andrew Clay Shafer 和 Adam Jacob 在 Velocity 大会上的演讲。John Willis 可能是第一个记录了这一说法的人,详见其在 IT Knowledge Exchange 上关于此次大会的文章“Infrastructure as Code”。Luke Kaines 承认他可能也参与其中,是最接近于接受这个荣誉的人。

“铁器时代”和“云时代”

在 IT 的“铁器时代”,系统都直接安装在物理硬件上。基础设施的置备和维护都是手动作业,迫使人们花费时间点击鼠标、输入命令来保持系统运转。由于变更涉及很多工作,变更管理流程强调细致的前期考虑、设计和审查工作。因为错误的代价非常昂贵,所以这个流程是合理的。

在 IT 的“云时代”,系统与物理硬件解耦了。日常的置备和维护可以委托给软件系统,让人类从苦差事中解放出来。在几分钟甚至几秒钟之内就能做出变更。变更管理可以利用这样的速度,提供更快的上市速度和更高的可靠性。

1.2 什么是基础设施即代码

基础设施即代码是一种基于软件开发实践的基础设施自动化方法。它强调系统及其配置的日常置备和变更具有一致性和可重复性。先修改配置的定义代码,再通过包括全面验证的无人值守过程应用到系统中去。

这种方法的前提是,现代工具可以把基础设施作为软件和数据进行处理。这允许人们在管理基础设施时应用软件开发工具,如版本控制系统(VCS)、自动化测试类库和部署编排工具。这也为利用诸如测试驱动开发(TDD)、持续集成(CI)和持续交付(CD)等开发实践打开了大门。

基础设施即代码已在最苛刻的环境中得到了验证。对于像亚马逊、Netflix、谷歌、Facebook 和 Etsy 这样的公司,IT 系统不仅是业务的关键,而且本身就是业务。宕机是无法容忍的。亚马逊的系统每天处理数亿美元的交易。因此,诸如此类的组织为大规模、高可靠性的 IT 基础设施开拓新的实践不足为奇。

本书旨在解释如何利用云时代的基础设施即代码方法来管理 IT 基础设施。本章探讨了组织在采用新一代基础设施技术时经常掉进的陷阱,详述了避开这些陷阱的核心原则以及基础设施即代码的关键实践。

基础设施即代码的目标

很多团队和组织期待通过基础设施即代码实现如下目标。

  • IT 基础设施支持并允许变更,而不是成为阻碍或者约束。
  • 对系统的变更是家常便饭,不应该对用户或者 IT 人员造成惊吓或者压力。
  • IT 人员把时间花费在体现自身能力的有价值的事情上,而不是花费在处理日常的重复性工作上。
  • 用户可以自行定义、置备和管理他们需要的资源,不需要 IT 人员参与。
  • 团队能够轻松、快速地从故障中恢复,而不是假设可以完全避免故障。
  • 持续地改进,而不是通过昂贵且危险的“大爆炸”项目去改进。
  • 通过实施、测试和测量来验证问题解决方案,而不是利用会议和文件进行讨论。

基础设施即代码不仅仅适用于云

基础设施即代码经常和云一起出现,因为在云上不这么做很难管理好服务器。但是基础设施即代码的原则和和实践不仅可以应用在云和虚拟化系统上,甚至可以直接应用在物理硬件上。

我使用“动态基础设施”一词指代程序化创建和销毁服务器的能力,第 2 章会着重介绍这个主题。云可以很自然地处理这些,虚拟化平台也可以通过配置来实现同样的功能。即便是硬件,也可以自动化置备,从而以完全动态的方式使用。有时候这也叫作“裸机云”。

静态基础设施也可以使用基础设施即代码的很多概念。手动置备的服务器可以通过服务器配置工具进行配置和更新。然而,对于本书中描述的很多高级实践,毫不费力地销毁并重建服务器的能力是不可或缺的。

1.3 动态基础设施的挑战

本节关注团队采用动态基础设施和自动化配置工具时常见的一些问题。这些问题是基础设施即代码要着力解决的,因此充分了解它们是学习后续原则和概念的基础。

1.3.1 服务器蔓延

利用云和虚拟化,从资源池置备新的服务器可谓小菜一碟。这会导致服务器的数量飞速增长,甚至超过团队能够管理或者希望管理的规模。

当这种情况发生时,团队会忙于给服务器打补丁并且让它们保持更新,系统容易受到已知漏洞的影响。当发现问题时,补丁无法及时地应用到可能受影响的所有系统上。服务器之间的版本和配置差异意味着在一些机器上运行良好的软件和脚本无法在其他机器上运行。

这会导致服务器之间的不一致,也叫作配置漂移

1.3.2 配置漂移

即便服务器在最初创建和配置的时候是一致的,其差异也会随着时间而增加。

  • 有人在一台 Oracle 服务器上做了一次修改,修复了一个特定用户的问题,现在它和其他的 Oracle 服务器就不同了。
  • 新版本的 JIRA 需要新版本的 Java,但是没有时间去测试其他所有基于 Java 的应用是否都可以升级。
  • 3 个人在几个月内分别在不同的 Web 服务器上安装了 IIS,并且每个人配置得都不一样。
  • 某台 JBoss 服务器比其他服务器接受了更多的流量并且开始出现性能问题,有人对它进行了性能调优,之后它的配置就和其他 JBoss 服务器不同了。

不一样并非不好。相比负载较低的服务器,负载高的 JBoss 服务器理应有不同的调优配置。但是这些变化应该以一种易于重现和重建服务器及服务的方式进行捕获和管理。

服务器间未经管理的变化会导致雪花服务器的产生和对自动化的恐惧。

1.3.3 雪花服务器

雪花服务器和网络中的其他所有服务器都不同。它非常特殊,无法复制。

几年前,我在一家为客户构建 Web 应用的公司里管理服务器,其中大部分 Web 应用都是庞大、复杂的 Perl CGI 脚本。(不要批评我们,那是 .COM 年代,大家都这么做。)我们一开始使用的是 Perl 5.6,但是后来最好的类库都升级到了 Perl 5.8,而且不兼容 5.6。最后,几乎所有的新应用都是基于 Perl 5.8 实现的,但是有一个特别重要的客户应用程序就是无法运行在 5.8 上面。

实际的情况比这更糟糕。这个应用程序在升级共享的预发布服务器到 5.8 时运行正常,但是在升级预发布环境时却崩溃了。不要问我们为什么没有解决预发布环境的问题就把产品环境升级到了 5.8,最后的结果就是这样的。我们有一台特殊的服务器可以运行 Perl 5.8 的应用程序,但其他服务器都不行。

我们就这样可耻地持续了很长时间——在预发布服务器上保留 Perl 5.6,每次部署到产品环境时都祈祷不要出问题。我们不敢触碰产品服务器上的任何东西,害怕解除能使唯一服务器运行客户应用的魔法。

这样的情况促使我们发现了 Infrastructures.org,这个网站为我打开了基础设施即代码的大门。我们确保以可重复的方式构建所有的服务器,用全自动安装(fully automatic installation,FAI)工具安装操作系统,用 CFEngine 配置服务器,并将所有的东西都用版本控制系统管理起来。

大多数 IT 运维团队都有过这样的尴尬:不能触碰或者难以复制服务器。如此脆弱的原因并非总是神秘莫测,有时是因为某个重要的软件运行在与其他服务器完全不同的操作系统上。我记得有个会计软件需要运行在 AIX 上,而另一个运行在 Windows NT 3.51 服务器上的 PBX 系统则是由一个已被遗忘的承包商特别安装的。

再次强调,不一致并非坏事。问题在于拥有服务器的团队对于服务器如何以及为何不一致一无所知,并且无法重建服务器。运维团队应当能够自信、快速地重建基础设施中的任意服务器。如果有任何服务器不能满足这个需求,团队的最高优先级应该是设立一个可复制的全新流程,来构建一台新的服务器并替换掉老的服务器。

1.3.4 脆弱的基础设施

脆弱的基础设施很容易中断,而且不容易修复。这是由于雪花服务器问题扩展到了整个系统组合。

解决方案是逐步将基础设施中的一切迁移到可靠、可复制的基础设施里。Visible Ops Handbook3 一书论述了如何在困难的基础设施上实现稳定性和可预测性。

3于 2005 年出版,由 Gene Kim、George Spafford 和 Kevin Behr 合著,成书的时间早于 DevOps、虚拟化以及自动化配置成为主流的时间,但是很容易看出如何在作者描述的框架中应用基础设施即代码。

不要碰那台服务器,别指它,甚至不要看它

这也许是一个虚构的故事:数据中心里有一台服务器,没有人知道登录的信息,也没有人知道那台服务器的作用。有人以身犯险,将那台服务器的电缆从网络中拔掉。整个网络彻底断了。于是,电缆被重新插回,没有人敢再动那台服务器了。

1.3.5 自动化恐惧症

在 DevOpsDays 大会上关于配置自动化的开放空间演讲中,我问在座的人当中有多少在使用类似 Puppet 或者 Chef 之类的自动化工具。大多数人都举手了。我又问有多少人以无人值守、自动排期的方式运行这些工具。只剩少数人的手还举着。

很多人都存在我在早期使用自动化工具时所遇到的问题。我那时选择性地使用自动化,例如为了构建新的服务器,或者进行特定配置的修改。每次运行自动化工具的时候,我都会调整配置,让它去适应我在做的任务。

我之所以不敢完全信任自动化工具,是因为我对它们做的事情缺乏信心。

我之所以缺乏对自动化的信心,是因为我的服务器不一致。

我的服务器之所以不一致,是因为我没有频繁和一致地执行自动化。

这就是自动化恐惧恶性循环,如图 1-1 所示。基础设施团队需要打破这种恶性循环,才能成功实施自动化。最有效的方式是直面恐惧。挑选一组服务器,调整配置定义,确保它们可以工作,并安排它们至少每小时以无人值守的方式运行一次。然后,挑选另一组服务器并重复这个过程,直到所有的服务器都持续更新。

{%}

图 1-1:自动化恐惧恶性循环

本书第三部分提到了良好的监控和有效的自动化测试制度,有助于我们树立可靠地应用配置以及快速定位问题的信心。

1.3.6 侵蚀

理想情况下,一旦基础设施被自动构建出来,你就永远不需要去触碰它了,除非需要支持更新或者修复问题。可悲的是,熵力 4 意味着即使没有新的需求,基础设施也会随着时间衰败。Heroku 的人们把这称为侵蚀(erosion resistance)。侵蚀的意思是,问题随着时间的推移蔓延到正常工作的系统之中。

4熵力在物理学中是指系统中的一种宏观作用力,其性质表现为整个系统对于熵增加的统计趋势。——编者注

Heroku 列举了以下随着时间侵蚀系统的因素。

  • 操作系统升级、内核补丁以及基础设施软件(如 Apache、MySQL、SSH、OpenSSL)修复安全漏洞的升级补丁。
  • 服务器磁盘被日志文件塞满。
  • 一个或者更多应用进程崩溃或者卡住,需要有人登录并且重启它们。
  • 底层的硬件失败导致一台或者更多服务器以及在它上面运行的应用出现问题。

1.4 基础设施即代码的原则

本节将介绍一些能够帮助团队克服上述挑战的原则。

1.4.1 系统能够轻松复制

我们应该能够毫不费力并且可靠地重建基础设施中的任何元素。毫不费力意味着无须对于如何构建元素做出任何重大的决策。在服务器上安装什么软件、安装软件的什么版本以及选择什么主机名等决策都应该包括在置备基础设施元素的脚本和工具中。

这种毫不费力地创建和重建基础设施任意部分的能力是非常强大的。在变更的时候,风险会更小,无须过多担心。我们可以有信心地快速处理故障,无须花费什么力气即可置备新的服务或环境。

本书的第二部分会讨论如何以可复制的方式置备服务器以及其他基础设施元素。

1.4.2 系统是用完可扔的

动态基础设施的好处之一是可以轻松创建、销毁、替换、扩容和移动资源。为了利用这一点,设计系统时必须假设基础设施始终在变更。即使服务器消失了、出现了或者大小改变了,软件也应该依然正常运行。

这种优雅处理变更的能力让增强和修复正在运行的基础设施变得更容易,也使得服务具有更强的容错性。当共享大规模的云基础设施无法保证底层硬件的可靠性时,这种能力变得尤为重要。

 牲口,而非宠物

有一句流行的话:“将你的服务器视作牲口,而不是宠物。”5 我很怀念那些为服务器名称指定一个主题,然后为每个新置备的服务器小心选择名称的时光。但我一点也不怀念不得不手动调整每台服务器的时光。

5 CloudConnect 的首席技术官 Randy Bias 在演讲“Architectures for Open and Scalable Clouds”中将这个说法归功于前微软员工 Bill Baker。我是在 Gavin McCance 的演讲“CERN Data Centre Evolution”中第一次听到这个说法。这两个演讲都非常精彩。

铁器时代和云时代的根本差异在于,铁器时代是不可靠的软件运行于可靠的硬件之上,而云时代是软件可靠地运行于不可靠的硬件之上。6 第 14 章会详细介绍采用用完可扔的基础设施能如何提升服务的连续性。

6 Sam Johnson 在他的文章“Simplifying Cloud: Reliability”中表述了硬件与软件可靠性的观点。

消失的文件服务器

服务器并不是永久存在的,这个理念需要一段时间才能被人们领会。我们曾在一个团队中使用 VMware 和 Chef 建立起了自动化的基础设施,并且养成了随意删除和替换 VM 的习惯。有个开发人员需要一台 Web 服务器来放置文档并供团队其他成员下载使用,因此在开发环境中的一台服务器上安装了 Web 服务应用程序并放置了文档。几天后,他吃惊地发现这台服务器上的 Web 服务应用程序和文档都不见了。

这名开发人员有些困惑,随后在 Chef 配置中加入了针对其文件仓库的配置,利用该工具的优势把数据持久化到 SAN 中。这个团队最终拥有了一个高度可靠、自动配置的文件共享服务。

套用一句陈词滥调:消失的服务器是一个特性,而不是bug。过去,人们临时安装工具并随意进行配置,结果导致了雪花式的、难以触碰的、脆弱的基础设施。尽管这名开发人员刚开始并不适应,但最终学会了使用基础设施即代码来构建可复制的可靠服务,即本例中的文件仓库。

1.4.3 系统是一致的

假设两个基础设施元素提供相似的服务,例如同一个集群中的两台应用程序服务器,那么这些服务器应该几乎完全相同。它们的系统软件和配置应该是一样的,除了一点点区分彼此的配置,比如 IP 地址。

基础设施出现不一致会导致人们不相信自动化。如果一台文件服务器拥有 80GB 的分区,另一台拥有 100GB 的分区,还有一台有 200GB 的分区,那么无法信赖相同的操作在这些服务器上都能取得相同的结果。这会促使人们对那些不太一样的服务器做一些特殊处理,从而导致不可靠的自动化。

遵循了可复制性原则的团队可以轻松构建多个完全相同的基础设施元素。如果需要修改其中一个元素(例如一台文件服务器需要更大的磁盘分区),有两种方式可以保持一致性。一是修改对服务器的配置定义,使得所有的文件服务器都拥有足够大的分区。二是添加新的类型或者角色,比如 xl-file-server,其硬盘比标准的文件服务器大得多。每种类型的服务器都能被重复构建,而且保持了一致性。

能够构建和重新构建一致的基础设施,有助于解决配置漂移的问题。但很明显,还需要处理好服务器创建之后所发生的变更。第 8 章会介绍如何确保现有基础设施的一致性。

1.4.4 过程是可重复的

基于可复制性原则,对基础设施执行的任何操作都应该是可重复的。显而易见,使用脚本和配置管理工具比手动修改更容易实现这一点。不过坚持这样做并不容易,尤其对有经验的系统管理员来说更是如此。

假设要实现对硬盘进行分区这样看似一次性的任务,我发现登录机器执行分区比编写并测试脚本更简单。我可以查看系统磁盘,考虑服务器的需求,再结合自己的经验和知识来决定每个分区的大小、使用的文件系统类型等。

问题在于,团队中的其他人可能需要对其他机器的磁盘进行分区,并且可能做出了与之前稍有不同的分区决定。可能我给一台文件服务器的 /var 分区分配了 80GB 的空间,并采用了 ext3 文件系统,而 Priya 给集群中的另一台文件服务器的 /var 分区分配了 100GB 的空间,并采用了 xfs 文件系统。这打破了一致性原则,最终会破坏自动化的能力。

高效的基础设施团队有浓厚的脚本文化。如果任务可以由脚本实现,那么就编写脚本。如果任务难以脚本化,那么就深入探讨能否借助于一些技术或工具,或者换种方式来解决该任务面对的问题。

1.4.5 设计经常变更

在 IT 的铁器时代,对已有系统的变更很困难而且成本很高。因此,当服务器构建完成之后,限制系统的修改听上去很有道理。这需要全面的预先设计,并且考虑各种需求和情况。

由于无法准确预测系统的实际使用情况以及系统的需求会如何变化,因此这种方式自然会产生过度复杂的系统。讽刺的是,这样的复杂度让系统的变更和改进变得更加困难,从而导致系统不太可能长时间运转良好。

借助云时代的动态基础设施,对已有系统的变更比较简单,而且成本很低。然而,前提是一切设计都支持变更。软件和基础设施的设计必须在满足当前需求的同时尽可能简单。变更管理必须能安全和快速地交付变更。

确保系统能够安全和快速变更的首要指标是频繁地做变更。这迫使人人养成管理变更的良好习惯,开发高效、简练的流程,并采用有助于此的工具。

1.5 实践

前一节介绍了总体原则,本节将介绍基础设施即代码的一些通用实践。

1.5.1 使用定义文件

基础设施即代码的基础实践是使用定义文件(definition file)。定义指定了基础设施元素以及应该如何配置它们。定义文件作为输入,供置备或配置这些元素实例的工具使用。

例 1-1 就是一份数据库服务器节点的定义文件。

例 1-1 使用 DSL 的定义文件样例

server: dbnode
  base_image: centos72
  chef_role: dbnode
  network_segment: prod_db
  allowed_inbound:
    from_segment: prod_app
    port: 1521
  allowed_inbound:
    from_segment: admin
    port: 22

基础设施元素可以是一台服务器、服务器的一部分(比如用户账号)、网络配置(比如负载均衡规则),等等。不同的工具对此有不同的术语,例如 playbook(Ansible)、recipe(Chef)或者 manifest(Puppet)。本书使用“配置定义文件”作为这些术语的统称。

定义文件以文本文件的形式进行管理。它们可能会使用标准的格式,如 JSON、YAML 或者 XML,也可能会定义自己的领域特定语言(domain-specific language,DSL)7

7根据 Martin Fowler 和 Rebecca Parsons 在《领域特定语言》一书中的定义,“DSL 是小语言,专注于软件系统的特定方面。你无法用 DSL 构建一个完整的程序,但是在由一门通用语言实现的系统中,你会经常使用多种 DSL”。若想了解 DSL,他们的书是一个不错的参考,尽管这本书的目标读者是考虑如何实现 DSL 的人,而不是使用 DSL 的人。

将规格和配置放在文本文件中,比将它们存储在工具的内部数据库中有更好的可访问性。这些文件也可以被当成软件源代码,适用于很多成熟的开发工具。

1.5.2 自文档化的系统和流程

IT 团队通常要尽全力保持文档的相关性、实用性和准确性。有人可能为一个新的流程起草了一份详尽的文档,但是随着流程的执行方式发生变更和改进,这样的文档很难保持更新。此外,文档也经常存在不足。不同的人会走不同的捷径,也会做出不同的改进。有些人会实现自己的脚本来让部分流程变得更容易一些。

因此,即使文档通常被视为增强一致性和标准化甚至遵守法规的方式,这在实践中却只是对事实的虚幻构想。

有了基础设施即代码,执行流程的步骤会保存在脚本、定义文件以及实现这个过程的工具中。人们只需要添加极少量的文档,就可以开始工作了。已经存在的文档应当离源代码很近,保证这些文档在人们做出变更时触手可及、触目可见。

自动生成文档

在某个项目中,我的同事 Tom Duckering 发现负责部署软件到产品环境的团队坚持采用手动方式。虽然 Tom 用 Apache Ant 实现了自动化部署,但是产品团队仍然希望有一份手写的文档来指导人工操作。

因此,Tom 写了一个自定义的 Ant task,可以打印出自动化部署的每个步骤。这样能生成一份包含具体步骤的文档,细致到要敲入的命令行。他所在团队的持续集成工具为每一次构建都生成了文档,这样可以保证文档的准确性和时效性。对部署脚本的任何修改都会自动包含在文档中,没有任何额外的成本。

1.5.3 一切版本化

版本控制系统(version control system,VCS)是基础设施即代码的一个核心部分。VCS 是基础设施期望状态的真实数据来源。基础设施的变更由提交到 VCS 的变更所触发。

为什么 VCS 对基础设施管理来说至关重要呢?主要有以下原因。

可追溯性

  VCS 提供了变更历史和变更者信息,在理想情况下还会提供变更原因。这些数据在调试问题时都是非常宝贵的。

回滚

  当变更(尤其是多个变更)引发问题时,VCS 有助于恢复到变更之前的状态。

相关性

  当脚本、配置信息、制品以及其他一切都由版本控制并用标签或版本号的方式相互关联时,VCS 非常有助于追踪和修复更复杂的问题。

可见性

  当变更被提交到版本控制系统后,每个人都可以看到,这会帮助团队增强对事态的感知能力。有人可能会注意到某个变更遗漏了一些重要的东西。如果发生了事故,团队成员能够知道最近的哪些提交可能是罪魁祸首。

可执行性

  当变更被提交时,VCS 可以自动触发一些动作。这是实现持续集成和持续交付流水线的关键。

第 4 章将解释 VCS 如何与配置管理工具一起工作,第 10 章则会讨论管理基础设施代码和定义的方法。

1.5.4 持续测试系统和流程

基础设施团队可以从软件开发中借鉴一个重要的实践,那就是高效的自动化测试。自动化测试是高效能开发团队的一个核心实践。他们在编写代码的同时实现测试,并持续运行测试。随着每天对代码库做增量的变更,他们一天通常会运行数十次自动化测试。

为遗留系统编写自动化测试是一件很困难的事情。需要以某种方式对系统的设计进行解耦和结构化,从而形成可独立测试的组件。在实现系统的同时编写测试,有利于驱动整洁、简单的设计以及松散耦合的组件。

在开发过程中持续运行测试可以对变更给出快速的反馈。快速反馈让人们有信心快速、更频繁地进行变更。这在自动化的基础设施中尤其强大,因为一个小小的变更就可以非常快地造成很大的破坏(即 DevOops,详见 12.2 节结尾)。良好的测试实践是消除自动化恐惧的关键因素。

第 11 章会探索将测试作为系统的一部分进行实现的实践和技术,尤其是如何能够有效地针对基础设施进行测试。

1.5.5 小的变更,而不是批量变更

当我第一次参与 IT 系统开发时,直觉告诉我:真正发布之前,需要实现一个完整的任务。等到工作“完成”之后再测试和整理,做好发布的准备,这种方式不无道理。这些收尾工作往往需要花费大量的时间和精力,为什么不在真正需要的时候再做呢?

然而,我慢慢地体会到了小变更的价值。即使针对较大的任务,一个一个地找出可以独立开发、测试和发布的增量变更也是很有帮助的。我们有很多理由选择小的增量变更,而不是大的批量变更。

  • 小的变更更容易测试和确认可靠性,且工作量更少。
  • 与大批量变更相比,小的变更出现问题更容易找到原因。
  • 小的变更修复和回滚起来更迅速。
  • 大批量变更中的一个小问题会造成变更中的所有内容都延迟发布,即使变更中的绝大部分内容都没问题。
  • 问题的修复和改进会鼓舞士气,而堆积如山的待完成工作会让士气低落。

正如许多良好的工作实践一样,一旦拥有了这个习惯,就很难去做正确的事情。这个习惯会让你在发布变更时做得更好。现在,如果在一项任务上花了一个多小时还没有进行发布,我会感到很不舒服。

1.5.6 让服务持续可用

无论基础设施发生了什么,服务总是能够响应请求,做到这一点很重要。如果某台服务器消失,其他服务器应该继续正常运行,新的服务器也应该能快速启动,从而保证服务不会中断。这在 IT 领域并不是新鲜事,不过虚拟化和自动化可以让它变得更简单。

广义上的数据管理可能更棘手。不管服务器发生了什么,服务数据都需要保持完整。这个目标可以通过数据复制和其他一些已经存在了数十年的方法来达到。当设计基于云的系统时,重要的是拓宽“需要留存的数据”的定义,通常包括应用程序配置、日志文件等。

第 14 章会继续讨论保持服务和数据持久可用的技术。

1.6 反脆弱性:超越“稳健性”

稳健的基础设施是 IT 的典型目标,这意味着系统需要很好地应对诸如故障、负载峰值和攻击等异常情况。然而,基础设施即代码使得基础设施不只有稳健性,还有“反脆弱性”。

Nassim Nicholas Taleb 在《反脆弱:从不确定性中获益》一书中创造了这个词,用以描述那些在压力下变得更加强大的系统。此书的主题不是 IT 系统(主要关注点是金融系统),但他的想法与 IT 架构是相通的。

身体压力对人体的影响是反脆弱性的一个实际例子。锻炼给肌肉和骨骼带来压力,本质上是在破坏它们,但反而使它们变得更强壮。通过避免身体压力和锻炼来保护身体,实际上会让身体变得脆弱,更容易在极端压力面前出现问题。

同样,通过减少变更次数来保护 IT 系统,并不会使它更稳健。相反,那些持续变更和改善系统的团队则能更好地应对灾难和事故。

反脆弱 IT 基础设施的关键是,保证对突发事件的默认响应动作是改善。当系统出现问题时,当务之急并不是修复它,而是提高系统在未来对类似事故的响应能力。

反脆弱IT系统的秘诀

人是系统的一部分,能够应对意外情况并修改系统的其他元素,以便下次可以更好地处理类似的情况。这意味着,运行系统的人需要非常理解且能够持续修改系统。

这与自动化的思想并不契合。自动化是指自动运行系统而无须人类参与。也许将来有一天,只要采购标准的企业级 IT 基础设施并直接运行即可,无须查看其内部状态。然而,这在今天仍然是不可能的。IT 技术和方法都在不断演变,甚至在非技术行业中,最成功的企业也都是那些持续改变和改善其 IT 系统的企业。

持续改善 IT 系统的关键在于那些构建并运行它的人,所以要设计可适应变化的系统,秘诀就是围绕人进行设计。8

8Brian L. Troutwin 在 2014 年根特市的 DevOpsDays 大会上发表了名为“Automation, with Humans in Mind”的演讲。他举了一个关于 NASA 的例子,描述了人们如何通过修改阿波罗 13 号的系统应对灾难。同时,他也介绍了切尔诺贝利核电站灾难的细节,在那里工作的人们无法介入自动化系统,从而无法采取措施来阻止或者控制灾难。

1.7 结语

高效基础设施团队的标志在于,它能够很好地处理不断变化的需求。高效团队会将需求分解成小的任务,并在低风险、低影响的快速变更流中流转这些任务,从而轻松地处理变更和新需求。

以下迹象标志着团队做得很好。

  • 基础设施的每一个元素都可以迅速且毫不费力地重建。
  • 所有系统都持续打了补丁,并保持一致和最新。
  • 在没有基础设施团队成员的参与之下,标准的服务请求(包括置备标准的服务器和环境)都可以在几分钟内完成。SLA 不是必要的。
  • 很少需要维护窗口。在工作时间执行包括软件部署和其他高风险活动在内的变更。
  • 团队跟踪平均恢复时间(mean time to recover,MTTR),并重点关注如何改善它。尽管也可以跟踪平均故障间隔时间(mean time between failure,MTBF),但团队并不依赖于它去避免故障。9
  • 团队成员觉得他们的工作给组织增加了可衡量的价值。

9请参阅 John Allspaw 的开创性博客文章“MTTR is more important than MTBF (for most types of F)”。

1.8 下一步

接下来的 4 章将重点关注基础设施即代码的工具。如果你已经熟悉了这些工具,可以快速浏览或跳过这几章,直接进入第二部分。第二部分将描述使用这些工具的基础设施即代码模式。

我将工具介绍分为 4 章。如同任何分类模型一样,这样的划分并不是绝对的。许多工具会跨越边界或者与这些定义不甚相符。这样分组只是为了方便地对运行动态基础设施所涉及的许多工具进行探讨。

动态基础设施平台

  用于提供和管理基本的基础设施资源,尤其是计算(服务器)、存储和网络。这些包括公有和私有的云基础设施服务、虚拟化和物理设备的自动配置。这是第 2 章的主题。

基础设施定义工具

  用于管理服务器、存储设备和网络资源的分配和配置。这些工具在高层次上置备和配置基础设施。这是第 3 章的主题。

服务器配置工具

  这些工具处理服务器本身的细节,包括软件包、用户账号以及各种类型的配置。这组特定的工具包括 CFEngine、Puppet、Chef 和 Ansible。它们也是人们在讨论基础设施自动化和基础设施即代码时会首先想到的。这些工具将在第 4 章中讨论。

基础设施服务

  帮助管理基础设施和应用程序服务的工具和服务,如监控、分布式进程管理及软件部署等。这是第 5 章的主题。

目录

  • 版权声明
  • O'Reilly Media, Inc. 介绍
  • 中文版推荐序
  • 译者序
  • 前言
  • 第一部分 基础
  • 第 1 章 挑战与原则
  • 第 2 章 动态基础设施平台
  • 第 3 章 基础设施定义工具
  • 第 4 章 服务器配置工具
  • 第 5 章 基础服务概述
  • 第二部分 模式
  • 第 6 章 置备服务器的模式
  • 第 7 章 管理服务器模板的模式
  • 第 8 章 服务器更新与变更模式
  • 第 9 章 定义基础设施的模式
  • 第三部分 实践
  • 第 10 章 基础设施的软件工程实践
  • 第 11 章 测试基础设施变更
  • 第 12 章 基础设施的变更管理流水线
  • 第 13 章 基础设施团队的工作流
  • 第 14 章 动态基础设施的连续性
  • 第 15 章 基础设施即代码的组织要求
  • 关于作者
  • 关于封面