How Terraform Compares to Other IaC Tools

文章对比了Terraform、Chef、Puppet、Ansible、SaltStack、CloudFormation和OpenStackHeat等IaC工具,强调了配置管理与资源供给、可变基础设施与不可变基础设施、程序式与声明式语言等关键区别。Terraform因其声明式语法和管理资源的优势被作者的公司Gruntwork选用。文章还探讨了混合使用多种工具的可能性和优缺点。
摘要由CSDN通过智能技术生成

How Terraform Compares to Other IaC Tools

翻译自 Terraform Yevgeniy Brikman 此材料可能受版权保护。

IaC技术虽好,但选取合适的IaC工具的过程充满抉择。众多的IaC工具的功能范围都是彼此交叠在一起,一部分是开源的、一部分提供商业支持。除非您自己使用过它们,否则并没有清晰的标准去帮你选择哪种工具更适合。更困难的是,您发现这些工具之间的大多数比较工作只不过是列出了各自工具的特性,并让它听起来好像你可以使用其中任何一个工具均可达到目的。这有点像告诉一个编程新手,你可以使用PHP、C语言以及汇编语言都可以成功构建网站——这句话在技术上是正确的,但却省略了如何正确选择一个语言所需的大量的必要信息。

在接下来的章节,我将详细比较最流行的配置管理和供给工具:Terraform、Chef、Puppet、Ansible、SaltStack、CloudFormation和OpenStack Heat。我的目标是通过解释我的公司Gruntwork选择Terraform的原因,并基于此帮助您决定是否采用Terraform作为IaC工具。从某种意义上说,这也是我为什么要写这本书的原因。与所有技术决策一样,这是一个权衡和优先级的问题,即使您的特定优先级可能与我的不同,我希望分享这个思考过程将帮助你做出自己的决定。

以下是需要考虑的主要因素:

  • 配置管理与资源供给(Configuration management versus provisioning)
  • 可变基础设施与不可变基础设施(Mutable infrastructure versus immutable infrastructure)
  • 程序式语言与声明式语言(Procedural language versus declarative language)
  • 有管理节点与无管理节点(Master versus masterless)
  • 有代理与无代理(Agent versus agentless)
  • 大型社区与小型社区(Large community versus small community)
  • 成熟与前沿(Mature versus cutting-edge)
  • 混合使用多种工具(Using multiple tools together)

配置管理与资源供给

如前所述,Chef、Puppet、Ansible和SaltStack都是配置管理工具,而CloudFormation、Terraform和OpenStack Heat都是资源供给工具。

两类工具并非泾渭分明,配置管理工具通常可以做一些供给层面的工作(例如,您可以通过Ansible去部署服务器)和资源供给工具通常也可以完成一定程度的配置工作(例如,您可以在使用Terraform供给的服务器上运行配置脚本),通常希望选择最适合您的工具。

特别是如果您使用Docker或Packer等服务器模板工具,绝大多数配置管理需求已经得到关注。一旦从Dockerfile或Packer Template创建图像后,仅需要为运行这些镜像提供运行基础环境即可。那么资源供给工具是解决基础设施供给的最优选择。

也就是说,如果您没有使用模版工具封装镜像,那么一个平替方案是混合使用配置工具和资源供给工具。例如,您可以使用Terraform来配置服务器并运行Chef来配置它们达到想要的状态。

可变基础设施与不可变基础设施

Chef、Puppet、Ansible和SaltStack等配置管理工具通常默认为可变基础设施范式。

例如,当您使用Chef安装新版本的OpenSSL,它将在已发布的服务器上就地运行该软件更新程序。随着时间的推移,应用服务器不断累积各种更新,使得每台服务器都有其独特的变更历史。最终每台服务器都变得与其它服务器略有不同,导致出现大量的难以诊断或重现的细微配置差异。(这与手工管理服务器时代,引起的配置漂移问题,大同小异。尽管当使用配置管理工具时,可以一定程度的减少漂移,但很难杜绝)。即使进行自动测试,这些配置错误也很难被发现;一种变更在测试服务器上可能效果很好,但相同的变更在生产上可能表现不同。因为生产服务器积累了数月的更改,而这些更改几乎不可能反映在测试环境中。

当然,也可以强制配置管理工具进行不可变的部署,但这不是它们的惯用方法,而是资源供给工具的标准用法。也值得一提的是不可变基础设施范式有其自身的缺点。例如,为了一个很小的配置变化而从服务器模板重建映像和重新部署所有服务器进行可能需要很长时间。

程序式语言与声明式语言

Chef和Ansible采用一种程序化编程风格,就是编写达到某种所需状态的每一步代码。Terraform、CloudFormation、SaltStack、Puppet和Open Stack Heat都鼓励声明式编码风格,就是只需通过代码表述您服务器所需的最终状态,而IaC工具本身负责弄清楚如何达到这种状态。为了展示差异,我们来举个例子。假设我们要部署10台服务器,并且运行 ami-0c55b159cbfafe1f0 镜像(Ubuntu 18.04)。以下是Ansible模板的简化示例,使用程序化编程风格做到这一点:

- ec2:
    count: 10
    image: ami-0c55b159cbfafe1f0
    instance_type: t2.micro

以下是Terraform配置的简化示例,该配置使用声明式方法做同样的事情:

resource "aws_instance" "example" {
  count         = 10
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

从表面上看,这两种方法可能看起来很相似,当你第一次使用Ansible或Terraform完成部署时,它们会产生类似的结果。但有趣的是在后续发生配置变化时,两者所表现出的差异。

例如,假设入口流量上升了,你想把服务器数量增加到15台。使用Ansible,您之前编写的程序代码不再有用;如果将前述playbook中服务器数量更新为15台,并重新运行

代码,它将部署15台新服务器,总共给你25台!所以,基于Ansible,您需要知道已经部署了什么(但在很多大规模生产环境,这类信息并不容易准确获得),并基于此编写一个全新的过程脚本,以添加五台新服务器。

使用声明性代码,因为您所做的只是声明您想要的最终状态,Terraform会弄清楚如何达到最终状态,Terraform还将了解它过去已经创建的每一个状态。因此,要再部署五台服务器,您只需回到相同的Terraform配置,并将计数从10更新到15:

resource "aws_instance" "example" {
  count         = 15
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}

如果你应用了这个配置,Terraform会意识到它已经创建了10台服务器,因此只需创建五台新服务器即可。事实上,在应用此配置之前,您可以使用Terraform的plan命令预览它将做出哪些更改:

$ terraform plan

# aws_instance.example[11] will be created
+ resource "aws_instance" "example" {
    + ami            = "ami-0c55b159cbfafe1f0"
    + instance_type  = "t2.micro"
    + (...)
  }

# aws_instance.example[12] will be created
+ resource "aws_instance" "example" {
    + ami            = "ami-0c55b159cbfafe1f0"
    + instance_type  = "t2.micro"
    + (...)
  }

# aws_instance.example[13] will be created
+ resource "aws_instance" "example" {
    + ami            = "ami-0c55b159cbfafe1f0"
    + instance_type  = "t2.micro"
    + (...)
  }

# aws_instance.example[14] will be created
+ resource "aws_instance" "example" {
    + ami            = "ami-0c55b159cbfafe1f0"
    + instance_type  = "t2.micro"
    + (...)
  }

Plan: 5 to add, 0 to change, 0 to destroy.

现在,当您想部署不同版本的应用程序时会发生什么,例如AMI ID ami-02bcbb802e03574ba?采用程序式,你之前的两个Ansible模板又没用了,所以你需要再写一个跟踪您之前部署的10台服务器的模板(还是现在有15台?)并仔细地将每个模版更新到新版本。使用Terraform的声明式方法,您可以再次返回完全相同的配置文件只需将ami参数更改为ami-02bcbb802e03574ba:

resource "aws_instance" "example" {
  count         = 15
  ami           = "ami-02bcbb802e03574ba"
  instance_type = "t2.micro"
}

显然,这些例子被简化了。Ansible确实允许您在部署新参数之前使用标签搜索现有的EC2实例(例如,使用instancetags和counttag参数),但必须手动计算根据每个资源的过去历史记录,您会发现使用Ansible管理的每个资源都会变得出人意料地复杂——不仅通过标签,还可能通过镜像版本、可用区域等特征来查找现有实例。这凸显了程序式IAC工具的两个主要问题:

  • 程序式代码不能完全捕获基础设施的状态

  • 程序式代码限制可重用性

使用Terraform的声明式方法,代码始终代表您的基础设施的最新状态。您可以一目了然的确定当前基础设施部署及配置,而无需担心历史变更或时间推移。这使得创建可重用代码变得容易,因为您无需手动搞清楚当前基础设施状态。相反,您只需专注于描述您想要的最终状态,Terraform就会自动弄清楚如何从一个状态迁移到另一个状态。因此,Terraform代码库往往保持规模小且易于理解。

当然,声明性语言也有缺点。与完整的编程语言相比,声明式编程的表达能力是有限的。例如,某些类型的基础设施变化,例如零停机时间部署,很难用纯粹的声明性术语来表达(但并非不可能,后续会讲解)。同样,声明式语言控制“逻辑”(例如if语句、循环)的能力有限,这对于创建通用、可重用的代码有点难搞。幸运的是,Terraform提供了许多强大的原语,例如输入变量,输出变量,模块,Createbeforedestroy、count、三元语法和内置函数——即使在声明性语言中,也可以创建干净、可配置的模块化代码。

有管理节点与无管理节点

默认情况下,Chef、Puppet和SaltStack都要求您建立一个主服务器来存储您的基础设施状态以及分发更新任务。每次您想更新基础设施中的某些内容时,您都会使用

客户端(例如命令行工具)向主服务器发出新命令,主服务器要么推送更新到所有其他服务器,要么这些服务器定期从主服务器上拉取最新的配置。

采用主服务器的方式提供了一些优势。首先,它是一个单一且集中的管理端,您可以在其中查看和管理全局的基础设施。许多配置管理工具甚至提供了一个Web界面(例如Chef Console、Puppet Enterprise Console),用于更轻松地查看主服务器的工作状态。其次,一些主服务器可以在后台连续运行,并强制执行配置。这样,如果有人手动更改服务器,主服务器可以恢复该更改以防止配置漂移。

然而,运行主服务器也有一些严重的缺点:

  • 额外的基础设施

  • 维护成本

  • 安全性

Chef、Puppet和SaltStack确实对无主模式有不同程度的支持,在这些模式中,您只运行他们的代理每台服务器上的软件,通常定期运行(例如,每五分钟运行一次的cron作业),并使用从版本库(而不是从主服务器)中拉取最新更新。这种方式虽然一定程度上降低了系统复杂,但正如我在下一节中讨论的那样,这仍然留下了一些未回答的问题

问题,特别是关于如何配置服务器并首先在上面安装Agent软件。

默认情况下,Ansible、CloudFormation、Heat和Terraform都是无主模式。或者,更准确地说,其中一些可能会依赖于主服务器,但它已经是您正在使用的基础设施的一部分,而不需要额外的部署。例如,Terraform使用云供应商的API与云服务通信,因此在某种意义上,API服务器是主服务器,只是它们不需要任何额外的基础设施或任何额外的身份验证机制。

有代理和无代理

Chef、Puppet和SaltStack都需要您安装代理软件(例如,Chef Client、Puppet Agent、Salt Minion)在您要配置的每个服务器上。代理通常在每台服务器的后台运行,并负责安装最新的配置管理更新。

有代理模式的几个缺点:

  • 引导问题

首先如何去供给服务器并且安装好代理?一些配置管理工具会把这个问题丢在一边,认为一些外部流程会为他们解决这个问题。(例如,它会假设首先使用Terraform部署一堆带有已经安装好代理的镜像的服务器)其他配置管理工具有一个特殊的引导过程,在其中,您可以运行一次性命令来部署服务器,并通过SSH在这些服务器上安装代理软件。

  • 维护问题

您需要定期仔细地更新代理软件,并确保其与主服务器保持同步。您还需要监控代理软件,并在它崩溃时重新启动它。

  • 安全问题

如果代理软件从主服务器拉去配置(或其他服务器,如果您不使用主服务器),您需要在每台服务器上打开出端口(outbound)。如果主服务器将配置推送到代理,您需要在每台服务器上打开入站端口。无论哪种情况,您都必须授权代理安全访问主服务器。而这些会增大入侵者的攻击面。

Ansible、CloudFormation、Heat和Terraform不需要您安装任何额外的代理。或者,更准确地说,其中一些需要代理,但这些通常已经作为您正在使用的基础设施的一部分安装。例如,AWS、Azure、谷歌云和所有其他云提供商负责在每台物理服务器上安装、管理和认证代理软件。作为一名Terraform用户,您无需担心这些:您只需发出命令,云提供商在您的所有服务器上通过代理即可执行。如果使用Ansible,您的服务器需要运行SSH守护进程,而这在大多数服务器上都是默认运行的。

大型社区与小型社区

每当你选择一项技术时,你也在选择一个社区。在许多情况下,项目的生态系统对您的体验的影响可能比技术本身固有的质量更大。社区决定有多少人为该项目做出贡献,有多少插件、集成以及扩展可用,在线寻求帮助的难易程度(例如,博客文章和StackOverflow等),以及雇用某人(例如员工、顾问或支持公司)是多么容易。

很难在社区之间进行准确的比较,但您可以通过在线搜索发现一些趋势。下表对主流的IaC工具做了比较,数据采集于2019年五月,维度上包含是否开源、支持哪些云供应商、GitHub上的贡献者和评级、四月中到五月中提交的commits和活跃的issues、该工具有多少开源库可用、针对该工具在StackOverflow上列出的问题数量、Indeed.com上提到该工具的工作数量。
在这里插入图片描述

显然,这不是一个严格的比较。比如一些工具不止一个repository,一些采用其它的方法去追踪bug或问题;通过搜索“chef”或“puppet”等通用关键字去寻找相关工作岗位也有点tricky。Terraform在2017年将提供商代码拆分为单独的repos,因此仅看它核心库的活动情况,会大大低估了(至少十倍)Terraform的活跃程度;等等。

同时,有些趋势也是显而易见的。首先,比较中提及的全部IaC工具都是开源且与多种云供应商兼容,除了CloudFormation。其次,Ansible的受欢迎程度最高,SaltStack和Terraform紧随其后。

另一个值得注意的有趣趋势是,自这本书第一版以来,这些数字发生了怎样的变化。下表中显示我在2016年9月收集的数值相较于2019年五月每个数字的变化百分比。

iac
同样,这里的数据并不完美,但它足以发现一个明显的趋势:Terraform和Ansible正在经历爆炸性增长,它们的贡献者、明星、开源库、StackOverflow帖子以及相关岗位的数量直线上涨。今天,这两种工具都具有大型、活跃的社区,从这些趋势来看,它们将来可能会变得更大。

成熟与前沿

选择任何技术时要考虑的另一个关键因素是成熟度。下表中展示各IaC工具的初代发布时间以及当前版本号(截止到2019.5)。


同样,这也不是一个严格比较,因为各工具采用不同的版本管理策略,但一些趋势还是比较清晰的。Terraform是目前最年轻的IaC工具。它还处于pre-1.0.0阶段,所以不能保证稳定或向后兼容的API,bug也相对较多。这是Terraform最大的弱势:尽管它用很短的时间就已经变得很流行,但使用它的代价就是接受它不像其他成熟IaC工具那样的稳定。

混合使用多种工具

虽然整个章节都在比较IaC工具,但现实是,您可能需要使用多个工具构建基础设施。每个工具都有其优点和缺点,所以为合适的工作选择合适的工具才是重点。

以下是我在多家公司看到的三种常见组合。

  • 资源供给+配置管理

比如:Terraform和Ansible。您使用Terraform部署所有底层基础设施,包括网络拓扑(即虚拟私有云[VPC]、子网、路由表)、数据存储(例如MySQL、Redis)、负载均衡器和服务器。再通过那么Ansible将您的应用程序部署在这些服务器上,如下图所示:
在这里插入图片描述
这是一个简单的入门方法,因为不需要额外的基础设施就可以运行(Terraform和Ansible都是client-only应用程序),有很多方法可以让Ansible和Terraform配合工作(例如,Terraform可以给服务器的添加特殊标签,Ansible使用这些标签来查找服务器并配置它们)。主要缺点是使用Ansible通常意味着您需要编写许多过程代码,依旧采用可变服务器,因此随着您的代码库、基础设施以及团队规模增长,维护可能会变得更加困难。

  • 资源供给+镜像管理

以Terraform和Packer配合为例。首先使用Packer将您的应用程序打包为VM映像。然后使用Terraform使用部署这些虚拟机镜像(a)服务器和(b)其余基础设施,包括网络(VPCs、子网、路由表等)和数据存储(MySQL和Redis等)以及负载均衡器,如下图所示:

在这里插入图片描述

这同样是一个简单的入门方法,因为不需要额外的基础设施就可以运行。此外,这是一套基于不可变基础设施的方案,这让运维变得更容易。但也有两个缺点:第一,虚拟机可能需要很长时间来构建和部署,这将减慢您的

迭代速度。第二,正如您将在后面的章节中看到的那样,您可以使用Terraform实现的部署策略比较有限。(比如,您无法在Terraform中原生实现蓝绿色部署)所以你要么最终停止编写复杂的部署脚本,要么转向编排工具,如下所述。

  • 资源供给+镜像管理+编排工具

示例:Terraform, Packer, Docker, and Kubernetes。首先通过Packer去创建一个已安装Docker或K8s的镜像,然后通过Terraform去部署这些镜像。最终,当这些集群被拉启后,它会构建出一套K8s集群以用于运行和管理你的容器化应用。如下图所示:

在这里插入图片描述

这种方法的优点是Docker映像构建得相当快,您可以在本地运行和测试它们,同时可以利用Kubernetes的所有内置功能,包括各种部署策略、自动愈合、自动扩缩容等。缺点是带来额外的复杂性,无论是额外的基础设施(Kubernetes集群的部署和运行既困难又昂贵,尽管大多数主要云提供商现在提供托管Kubernetes服务,可以减轻一部分工作),还是引入几个额外的抽象层(Kubernetes、Docker、Packer)需要学习、管理和调试。

结论

综上所述,表1-4显示了最受欢迎的IaC工具技术栈。请注意,这个表格显示各种IaC工具的默认或最常见使用方式,尽管如本章前面所述,这些IaC工具足够灵活,也可用于其他配置。(例如,Chef也可以不设立主服务器,Salt也可用于不可变基础设施管理)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值