对于不需要携带的系统,将基础结构以可重复文本格式的代码形式呈现是一种简单的最佳实践。 该实践的名称为“基础结构即代码” ,到目前为止,有两种流行的工具可用于其实现,尤其是在AWS中: Terraform和CloudFormation 。

比较Terraform和CloudFormation的经验
在加入Twitch (又名Amazon Jr. )之前,我在一家初创公司工作,并使用了Terraform三年。 在新的地方,我也将Terraform与may和main一起使用,然后该公司将过渡推进到包括CloudFormation在内的所有亚马逊公司。 我努力为两者开发最佳实践,并且在整个组织中非常复杂的工作流中使用了这两种工具。 后来,经过深思熟虑地考虑了从Terraform迁移到CloudFormation的后果,我确信Terraform可能是该组织的最佳选择。
Beta软件
Terraform甚至没有发布1.0版,这是不使用它的一个很好的理由。 自从我自己进行测试以来,它已经发生了很大的变化,但是后来经过多次更新或仅运行了几年后, terraform apply
经常崩溃。 我会说“现在一切都不同了”,但是...所以每个人似乎都说不? 有一些与先前版本不兼容的更改,尽管它们是适当的,甚至感觉到现在您需要的是资源存储的语法和抽象。 该工具似乎更好,但是...:-0
另一方面,AWS在保持与先前版本的兼容性方面做得很好。 可能全部是因为他们的服务通常在组织中经过良好的测试,然后才被重命名,发布。 所以“苦苦尝试”仍然微弱地说。 对于像AWS这样的多变量和复杂系统,要保持与API先前版本的兼容性非常困难。 任何必须支持使用范围广泛的公共可用API的人都应该了解这么多年来的困难。 但是多年来,我记忆中的CloudFormation行为从未改变。
遇见腿...这是子弹头
据我所知,不可能从我的CF堆栈中删除第三方CloudFormation堆栈资源。 Terraform的情况与此类似。 它允许您将现有资源导入堆栈。 有人可能会说,这个功能很棒,但是功能强大,责任也就越大。 一个人只需要将资源放在堆栈上,而在使用堆栈时,就不能删除或更改此资源。 一旦它来了。 不知何故,在Twitch站点上,有人在未发现任何错误的情况下无意中将AWS安全组导入了自己的Terraform堆栈。 我输入了几个命令,然后……安全组(以及传入的流量)消失了。
部分恢复
有时,CloudFormation无法完全从一种状态过渡到另一种状态。 同时,他将尝试返回上一个。 抱歉,这并不总是可行的。 然后调试发生的事情是令人恐惧的-您永远不知道CloudFormation是否会对它被破解感到高兴-即使是进行修复。 但是他会成功还是不回到以前的状态,他真的不知道如何确定,并且默认情况下会挂几个小时等待奇迹。
相反,Terraform倾向于更优雅地从失败的过渡中恢复,并提供高级的调试工具。
更清晰的文档状态更改
“好的,负载均衡器,您正在改变。但是如何?”
—一位担心的工程师准备按“接受”按钮。
有时,我需要对CloudFormation堆栈中的负载均衡器进行一些操作-例如,添加端口号或更改安全组。 CloudFormation更改显示较弱。 我像针一样,仔细检查yaml文件十次,以确保没有擦除所需的任何内容,并且也没有添加太多内容。
Terraform在这方面更加透明。 有时它甚至太透明了(阅读:得到它)。 幸运的是,最新版本包含改进的更改显示-现在您可以清楚地看到正在更改的内容。
柔韧性
相反地编写软件。
坦率地说,寿命长的软件最重要的区别特征是其适应变化的能力。 编写相反的任何软件。 我经常打扰说我接受了“简单”服务,然后开始将所有内容推送到单个CloudFormation或Terraform堆栈中。 当然,几个月后,我发现我理解所有错误,而且服务实际上并不简单! 因此,我需要以某种方式将大型堆栈分解成小的组件。 当您使用CloudFormation时,只能通过首先重新创建现有堆栈来执行此操作,但是我不对数据库执行此操作。 另一方面,Terraform使解剖堆栈并将其分成更易于理解的较小部分成为可能。
git中的模块
跨多个堆栈共享Terraform代码比共享CloudFormation代码容易得多。 使用Terraform,您可以将代码放入git存储库中,并使用语义版本控制对其进行访问。 有权访问此存储库的任何人都可以重用共享代码。 与CloudFormation等效的是S3,但是它没有相同的优点,并且没有一个唯一的原因为什么我们应该完全放弃git来支持S3。
组织不断壮大,共享共享堆栈的能力达到了关键水平。 借助Terraform,这一切都是自然而简单的,而CloudFormation将使您在获得类似东西之前先从戒指中跳出来。
以代码形式进行操作
“让我们写剧本,好吧。”
-在发明Terraform自行车之前3年的一名工程师。
在软件开发方面,Go或Java程序不仅仅是代码。

代码即代码
毕竟,仍然有可以运行的基础架构。

基础架构即代码
但是她来自哪里? 如何监控呢? 您的代码在哪里? 开发人员需要访问权限吗?

以代码形式进行操作
成为软件开发人员不仅要编写代码。
不是AWS One:您必须使用其他提供程序。 SignalFx,PagerDuty或Github。 也许您具有用于CI / CD的内部Jenkins服务器或用于监视的内部Grafana控制面板。 选择Infra as Code的原因有多种,对于与软件相关的所有事物,同等重要。
在Twitch工作时,我们在Amazon的混合嵌入式系统和AWS系统中加速了服务。 我们为许多微服务加盖印章并提供支持,从而增加了运营成本。 围绕以下方面进行了讨论:
- 我 :该死,许多手势分散了一个微服务。 我将不得不使用此垃圾创建一个AWS账户(我们为微服务创建了2个账户),然后该账户设置了警报,此账户用于代码存储库,此账户用于设置电子邮件地址,好吧,这个.. 。
- 负责人 :让我们编写脚本,好的。
- 我 :很烦,但是脚本本身会改变。 您将需要一种方法来验证所有这些内置的Amazon gizmos是否是最新的。
- 主管 :听起来不错。 为此,我们将编写一个脚本。
- 我 :太好了! 而且脚本可能仍需要设置参数。 他会接受吗?
- 负责人 :是的,他会的,他会去哪里!
- 我 :过程可能会更改,向后兼容性会丢失。 这将需要一些语义版本控制。
- 领导 :好主意!
- 我 :可以在用户界面内手动更改工具。 我们需要一种方法来验证和解决此问题。
... 3年后:
寓言的寓意是这样的:即使您在所有亚马逊游戏中一头雾水 ,您仍然会使用不是来自AWS的东西,并且这些服务具有一种状态,该语言使用该状态来进行配置以同步该状态。
lambda是CloudFormation针对自定义逻辑问题的解决方案。 使用lambda,您可以创建宏或自定义资源 。 这种方法带来了Terraform在git模块的语义版本控制中没有的其他困难。 对我来说,最紧迫的问题是管理所有这些自定义lambda(包括数十个AWS账户)的权限。 另一个重要的问题是一个问题,例如“之前发生了什么-鸡还是鸡蛋?”:它与lambda代码有关。 此功能本身是基础结构和代码,它本身需要监视和更新。 棺材中的最后一个亮点是语义上更新lambda代码更改的难度; 还必须确保没有直接命令的堆栈操作在两次启动之间不会改变。
我记得我想以某种方式使用经典的负载均衡器为Elastic Beanstalk环境创建一个canary部署。 最简单的方法是在生产环境旁边对EB进行第二次部署,这又迈出了一步:通过将可自动伸缩的Canary部署组与部署LB组合到生产环境中。 而且由于Terraform使用ASG beantalk作为输出 ,因此在Terraform中将需要额外的4行代码。 当我问到CloudFormation中是否有一个可比的解决方案时,他们指出我在git中的整个存储库,其中包含一个部署管道以及更多内容:所有这些都是为了不幸的4行Terraform代码可以做什么。
他更好地检测到漂移
确保现实符合期望。
漂移检测作为代码是一项非常强大的操作,因为它有助于确保现实满足期望。 CloudFormation和Terraform均可使用。 但是随着工作堆栈的增长,CloudFormation的漂移搜索返回了越来越多的误报。
使用Terraform,您可以使用更高级的生命周期挂钩来进行漂移检测。 例如,如果要忽略特定任务定义中的更改,而又不忽略整个ECS部署中的更改,则直接在ECS任务的定义中输入ignore_changes命令。
CloudFormation很难在较大的跨基础架构规模上进行管理。 人们认识到了许多困难,该工具需要aws-cdk之类的东西,该框架用于在代码中定义云基础架构,并将其通过AWS CloudFormation传递。 他很想知道aws-cdk将来会有什么,但是他很难与Terraform的其他优势竞争。 为了加强CloudFormation,将需要进行全局更改。
这是“将基础结构作为CODE”,而不是“作为文本”。
我对Terraform的第一印象非常糟糕。 我想我只是不了解这种方法。 几乎所有的工程师起初都不由自主地将其视为必须转换为所需基础结构的文本格式。 不要这样。
我已经看到在Terraform中忽略了用于创建良好代码的许多实践。 您学习了多年,成为一名优秀的程序员。 不要仅仅因为使用Terraform而放弃这种体验。 良好软件开发的常见真理也适用于Terraform。
代码如何无法记录?
我遇到了巨大的Terraform堆栈,根本没有任何文档。 如何在页面中编写代码-完全没有文档? 添加说明您的Terraform 代码 (此处重点放在“代码”一词),为什么这部分如此重要以及您做什么的文档。
您如何部署曾经是主要main()函数的服务?
我遇到了非常复杂的Terraform堆栈,以单个模块的形式呈现。 我们为什么不部署这样的软件? 为什么将大型功能分解为较小的功能? 相同的答案适用于Terraform。 如果模块太大,则需要将其分成较小的模块。
您的公司不使用图书馆吗?
我看到工程师如何使用Terraform分解一个新项目,然后将其他项目中的大块内容愚蠢地复制粘贴到自己的项目中,然后挑选它们直到开始工作。 那么,您将使用“作战”代码在公司工作吗? 我们不仅使用库。 是的, 不是所有内容都应该是一个库,但是原则上没有共享库,我们在哪里呢?
您不使用PEP8或gofmt吗?
大多数语言都有标准的可接受格式设置方案。 在Python中,这是PEP8。 在Go中-gofmt。 Terraform有其自己的: terraform fmt
。 为了健康!
您会在不了解JavaScript的情况下使用React吗?
Terraform模块可以简化正在创建的复杂基础结构的某些部分,但这并不意味着您可以完全跳过它。 是否想在不了解资源的情况下正确使用Terraform? 你注定了:时间会过去,但你不会精通Terraform。
您编写单调代码还是引入依赖项?
依赖注入是公认的软件开发最佳实践,单调首选。 这在Terraform中有什么用? 我遇到了取决于远程状态的Terraform模块。 与其编写从远程状态提取的模块,不如编写一个接受参数的模块。 然后将这些参数传递给模块。
您的图书馆做十件事好还是做一件事好?
专注于一项任务的图书馆表现最好。 与其编写大型的Terraform模块来尝试一次完成所有事情,不如将其中的一部分做得很好。 然后将它们组合为您想要的方式。
在不向后兼容的情况下,如何更改库?
像常规库一样,常规Terraform模块需要以某种方式通知用户有关更改的信息,而无需向后兼容。 当库中发生此类更改时,这很烦人,就像在Terraform模块中进行不具有向后兼容性的更改时一样。 当使用Terraform模块时,建议使用git标签和semver。
生产服务是在笔记本电脑上还是在数据中心中启动的?
Hashicorp具有诸如地形云之类的工具来启动您的地形。 这些集中式服务有助于对地形变更进行管理,审核和批准。
你不写测试吗?
工程师承认代码需要进行测试,但是在使用Terraform时,他们自己经常会进行检查。 对于基础设施而言,这充满了阴险的时刻。 我建议您使用可以在CI / CD期间正确部署以进行验证的模块“测试”或“创建示例”。
微服务公司的生死取决于新微服务工作堆栈的速度,更新和销毁。
与微服务体系结构相关的最常见的负面点是无法与工作联系在一起,而与代码无关,这是无法以任何方式消除的。 如果您将Terraform用作仅使微服务体系结构的基础架构方面自动化的一种方式,那么您将丧失该系统的真正优势。 现在, 一切都像代码 。