Terraform:多云、混合云环境下实现基础设施即代码

译者序

  • 敏捷开发的出现大大提高了软件开发的效率
  • DevOps的重点之所以是运维,一个原因是在开发团队实施敏捷开发后,运维团队成了新的瓶颈;另一方面是运维领域的硬件虚拟化(服务器变成了虚拟机,数据中心变成了云计算平台)所带来的挑战—硬件的搭建和改变更加频繁,使原有的思想和技术很难继续支持业务的发展

前言

  • Terraform面世后的5年中,有4年的时间我都在自己的公司Gruntwork(见参考资料文前[2])里使用这个工具。我们将Terraform作为核心工具,创建了包含30万行代码的可重复使用的模块库,这些基础设施代码经受了数百家公司生产环境的实战检验
  • https://github.com/brikis98/terraformupandrunningcode

第1章 为什么使用Terraform

DevOps 的崛起

  • 软件只有最终交付给用户才标志着项目的结束
  • 软件交付(softwaredelivery)是指通过一系列工作使代码最终对客户“可见、可用”的过程,例如,将代码运行在生产服务器之上,使代码能够应对数据流量的激增和意外停机中断,保护代码免受攻击者破坏
  • 经过DevOps转型的公司往往都有令人震惊的结果
  1. Nordstrom在应用DevOps最佳实践之后,能够将每月交付的功能数量增加100%,缺陷减少50%,交货时间(从构思创意到将产品运行在生产环境的总时长)缩短60%,生产事故的数量减少60%至90%
  2. 惠普的LaserJet固件部门采用DevOps后,其开发人员花在开发新功能上的时间从5%增加到40%,总体开发成本减少了40%
  • DevOps有四大核心价值(CAMS
  1. 文化(culture
  2. 自动化(automation
  3. 度量(measurement
  4. 共享(sharing

基础设施即代码(IaC):DevOps自动化的目标是将软件交付过程自动化。所以落实到管理基础设施方面,也要尽可能多地通过代码来进行,减少点击网页或手动执行Shell命令的方式

什么是基础设施即代码

  • 基础设施即代码背后的想法是,通过编写和执行代码来定义、部署、更新和销毁基础设施。这代表着一种观念上的重要转变:将运维的各个工作都视为与软件相关,甚至包括那些明显针对硬件的工作(如设置物理服务器)
  • DevOps的一个重要观点是,用户应该将所有事物都在代码中进行管理,包括服务器、数据库、网络、日志文件、应用程序配置、文档、自动测试、部署过程等

IaC工具分为5大类

专项脚本

  • 自动化最直接的方法是为每一项任务写一个专项脚本
  • 专项脚本对那些小规模的、一次性的任务很有效,但如果计划把基础设施作为代码进行管理,那么你应该使用专业的IaC工具

配置管理工具

  • ChefPuppetAnsibleSaltStack都属于配置管理工具,它们的目的是在现有服务器上安装和管理软件

服务器模板工具

  • “服务器模板化”是向不可变基础设施(immutableinfrastructure)迁移的关键步骤

编排工具

服务开通工具

  • 通过配置管理、服务器模板和编排工具可以定义服务器上运行的代码,但还是需要TerraformCloudFormationOpenStackHeat等工具,负责创建服务器本身。实际上

例如,下面的Terraform代码部署了一台Web服务器

image-20211207091229174

图1-5:使用服务开通工具,通过云服务提供商提供的接口,来创建服务器、数据库、负载均衡器,以及基础设施的所有其他部分

image-20211207091251594

user_data:服务器启动时,需要执行的 Bash脚本

基础设施即代码的好处

  • 代码的功能是极其强大的。通过早期投入将手动工作转化为代码,你的软件交付能力将得到显著改善

使用DevOps实践(例如IaC)的组织,部署频率提高了200倍,从故障中恢复的速度提高了24倍,交付周期缩短为原来的1/2555

自助服务

  • 大多数手动部署代码的团队,只有极少数的系统管理员(通常只有一个人)知道部署过程的全部细节,并且是唯一有权限访问生产环境的人。随着公司的发展,这将成为一个主要的瓶颈

速度和安全性

  • 自动化将大大加速部署过程,因为计算机可以比人更快、更安全地执行部署步骤

文档

  • 将基础设施定义为代码之后,就可以将其状态保存并显示在任何人都可以读取的源文件中

版本控制

  • IaC源文件存储在版本控制系统中,基础设施的历史变更记录将在提交日志中被完整保留

验证

  • 如果在代码中定义基础设施的状态,则对于每一个更改都可以执行代码评审、运行自动测试

重用

  • 基础设施可以打包成可重用的模块,这样针对每个新产品、新环境,可以避免从头编写部署代码,通过利用已知的、经过实战测试的模块[1],达到快速开发的目的

幸福感

  • 部署代码和管理基础设施经常是重复且乏味的任务。开发人员和系统管理员都厌恶这种没有创意、没有挑战、不被认可的工作。连续几个月的完美的代码部署,却没有引起任何关注。直到有一天部署出了问题,大家才会意识到你的存在

Terraform 的工作原理

  • Terraform使用Go语言编写,是由HashiCorp公司创建的开源工具

Terraform配置文件的示例

image-20211207091929671
  1. 首先调用AWSAPI来部署一台服务器。然后调用GoogleCloudAPI,创建指向AWS服务器IP地址的DNS条目
  2. 用户可以在Terraform配置文件中定义整套基础设施:服务器、数据库、负载均衡器、网络拓扑等,然后将配置文件提交到版本控制系统。接下来,通过运行Terraform命令,例如terraformapply命令,来部署该基础设施。terraform命令将对代码进行解析,将代码转化为云服务提供商的一系列API调用,并在此过程中优化API调用

图1-6:Terraform工具将用户的配置文件中的内容转换为对云服务提供商的API调用

image-20211207092003055

Terraform 与其他 Iac 工具的比较

  • 以下是要主要的考虑和对比方向

配置管理与服务开通对比

  • 诸如DockerPacker之类的服务器模板工具,已经实现了绝大多数配置管理工具的功能
  • 在服务开通阶段,服务开通工具将是最佳选择

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

  • 使用诸如Terraform之类的服务开通工具来部署由DockerPacker创建的机器映像,大多数“更改”实际上是部署一个全新的服务器
  • 这种方法降低了发生配置漂移错误的可能性,使你更准确地知道每个服务器上正在运行的软件,并允许用户轻松地将部署恢复到之前的任何版本(通过使用以前的映像)

过程性语言与声明性语言对比

  • TerraformCloudFormationSaltStackPuppetOpenStackHeat都鼓励使用声明性编程语言,在这种语言中,用户可以编写代码来指示工具所要达到的最终状态,而IaC工具将负责决定具体的实现步骤
  • 如果利用声明性代码,你要做的就是声明所需的最终状态,然后由Terraform自己决定如何达到该最终状态,Terraform也会记录它过去创建的任何状态。因此,对于部署5台服务器,你要做的就是使用相同的Terraform配置,并将数量从10更新到15
  • 如果应用这个配置,Terraform将意识到它已经创建了10台服务器,因此要做的就是再创建5台新的服务器
  • 可以使用Terraformplan命令来预览将要发生的变更

过程性程序代码限制可重用性

  • 过程性的程序代码的重用性是十分有限的,因为你必须考虑基础设施的当前状态
  • 使用Terraform的声明性语言,代码始终代表基础设施的最新状态。通过阅读代码,你可以确定当前环境的部署内容及配置细节,不必担心历史记录或时间顺序

影响安全性

  • AnsibleCloudFormationHeatTerraform均为无主控服务器软件。更准确地说,其中一些可能依赖于主控服务器,但是这些服务器已经是你正在使用的基础设施的一部分,而不需要你去管理额外的组件。例如,Terraform使用云服务提供商的API与云平台进行通信,从某种意义上讲,API服务器就扮演着主控服务器的角色

大型社区与小型社区对比

  • 比较了流行的IaC工具,比较项目包括开源和闭源、所支持的云服务提供商、GitHub上的贡献者和得星评级总数、在一个月内(4月中旬到5月中旬)活跃的提交总数、一个月内错误报告总数、有多少开源库可供该工具使用、在StackOverflow上针对该工具列出的提问数,以及该工具在Indeed.com上的职位数

表1-1:IaC社区的比较

image-20211207092259924

表1-2:IaC社区自2016年9月至2019年5月之间的变化

image-20211207092332832

同时使用多个工具

  • 搭配使用TerraformAnsible,如图19所示。你可以使用Terraform部署所有基础设施,包括网络拓扑(如虚拟私有云VPC、子网、路由表)、数据存储(如MySQLRedis)、负载均衡器和服务器。然后使用Ansible将应用程序部署在这些服务器之上

图19:搭配使用TerraformAnsible

image-20211207092406691
  • 使用Packer创建包括DockerKubernetes服务的虚拟机映像。然后通过Terraform部署服务器集群,每个服务器都运行此虚拟机映像,以及其余基础设施,包括网络拓扑(即VPC、子网、路由表)、数据存储(如MySQLRedis)和负载均衡器

图1-11:搭配使用TerraformPackerDockerKubernetes

image-20211207092430609

第2章 Terraform入门

设置 AWS 账户

  • 几乎每个AWS资源都需要部署到VPC中才能工作,如果未明确指定目标VPC,则资源将被部署到默认VPC

安装 Terraform

  • 为了使Terraform能够对你的AWS账户进行直接操作,需要将环境变量AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY设置为之前创建的IAM用户的访问ID和密钥
image-20211207092732118
  • 除了通过环境变量进行身份验证,Terraform也支持与所有AWS命令行工具和SDK工具相同的身份验证机制,使用$HOME/.aws/credentials文件中的密钥,密钥信息可以通过在AWS命令行或IAM角色上运行configure命令自动生成

部署单个服务器

  • Terraform代码是以HashiCorp配置语言(HashiCorpConfigurationLanguageHCL)编写的,扩展名为.tf。[1]HCL是一种声明性语言,目标是描述所需的基础设施,Terraform将自动计算生成创建它的方法
  • 大多数编辑器也提供对Terraform语法的支持(需要在网上搜索单词“HCL”而不是“Terraform”来获取相关信息),包括vimEmacsSublimeTextAtomVisualStudioCodeIntelliJIntelliJ甚至支持重构、查找用法和声明跳转)
  • 使用Terraform的第一步通常是配置要使用的提供商。创建一个空文件夹,并在其中放置一个名为main.tf的文件,该文件包含以下内容
image-20211207092834743
  • Terraform中创建资源的一般语法如下
image-20211207092847553

例如,如果想在AWS中部署单个EC2(虚拟)服务器实例,则需要将aws_instance资源配置在main.tf

image-20211207092932273
  • aws_instance资源支持许多不同的参数,但只有两个参数是必须要设置的
  1. ami:运行在EC2实例上的AmazonMachineImageAMI
  2. instance_type:EC2运行实例的类型。每种类型的EC2实例都提供不同数量的CPU、内存、磁盘空间和网络带宽

我们很难记住每个提供商所支持的众多资源,以及每个资源的全部参数。在编写Terraform代码时,你需要定期参考Terraform文档,查找可供使用的资源及其使用方法

  • 运行terraform init命令
image-20211207093102288
  • 第一次开始使用Terraform时,需要运行terraforminit命令,指示Terraform扫描代码,找出用到的提供商,并下载它们需要使用的代码库。在默认情况下,提供商代码将被下载到.terraform文件夹中,该文件夹是Terraform的临时目录(用户或许需要将其添加到.gitignore,以防止将这个临时目录上传到版本控制系统)
  • 现在你已经下载了提供商代码,请运行terraform plan命令
image-20211207093120433
  • plan命令可以让你在任何实际更改之前对Terraform进行预览,以便代码在发布给外界之前进行最后的检查
  1. 加号(+)代表任何新添加的内容
  2. 减号(-)代表删除的内容
  3. 波浪号(〜)代表所有将被修改的内容
  • 要创建这个实例,请运行terraform apply命令
image-20211207093158475
  • 还需要创建一个名为.gitignore的文件,它会告诉Git忽略某些类型的文件,以免你无意中将临时文件存入版本控制系统中
image-20211207093226905
  • 前面的.gitignore文件的内容,指示Git忽略Terraform临时目录.terraform文件夹,以及Terraform用来存储状态的*.tfstate文件

部署可配置的 Web 服务器

  • EC2实例启动时,将执行以用户数据方式传递进来的Shell脚本或cloudinit指令。Terraform脚本使用user_data参数,将Shell脚本作为对象,传递给AMI用户数据,如下所示
image-20211207093307508
  • 引用(reference)是一种特别有用的表达式类型,它使用户可以从代码的其他部分访问该值。如果要访问安全组资源 ID,需要使用资源属性引用(resource attribute reference),语法如下
image-20211207093433232
image-20211207093441161
  • 当在一个资源内引用另一个资源时,会创建隐式依赖关系。Terraform可以通过分析这些依赖关系,构建依赖关系图,并使用该关系图自动确定资源的创建顺序
  • 可以通过运行terraform graph命令显示依赖关系图
image-20211207093506659
  • 以上输出的格式为DOT图形描述语言,通过使用桌面应用,例如Graphviz,或Web应用GraphvizOnline
image-20211207093531525
  • Terraform遍历你的依赖关系树时,它会尽量使用并行方式创建尽可能多的资源,从而更有效地实现变更
  • 计划输出中的/+符号表示“替换”。通过在计划输出中查找forcesreplacement(强制替换)字段,可以得到Terraform进行强制替换的原因
image-20211207093636907
  • 声明变量的语法
image-20211207093718787
  • description:描述参数用来说明如何使用这个变量
  • default:有多种方法可以为变量赋值,包括通过命令行(使用var选项),通过属性文件(使用varfile选项)或通过环境变量(Terraform能够查找并识别前缀为TF_VAR_的环境变量)。如果未传入任何值,变量将使用默认值。如果没有默认值,Terraform将以交互方式提示用户输入一个值
  • type:允许对用户输入的变量类型进行强制约束。Terraform支持许多类型约束,包括stringnumberboollistmapsetobjecttupleany
  • Terraform会设置默认约束类型为any
  • 通过类型约束来验证输入的值为数字
image-20211207205230352
  • 检查输入值是否为列表
image-20211207205240643
  • 所有的列表值为数字
image-20211207205415720
  • 使用类型约束创建更复杂的对象和元组结构类型
image-20211207205436240
  • 尝试将enabled变量设置为字符串而不是一个布尔值
image-20211207205453050
  • 会得到以下错误
image-20211207205509322
  • 请注意,server_port输入变量没有默认值,因此,如果运行apply命令,Terraform将提示输入server_port的值,并显示变量中的description
image-20211207205539998
image-20211207205548749
  • 如果不想每次都处理交互式提示,可以通过命令行的var参数为输入变量提供初始值
image-20211207205600461
  • 也可以通过环境变量来设置输入变量初始值。命名规范是TF_VAR_,其中是你要设置的输入变量的名称
image-20211207205621618
  • 如果不想在每次运行planapply时都记住额外的命令行参数,也可以指定一个默认值
image-20211207205631148
  • 使用一种被称为变量引用(variablereference)的新型表达式,语法如下
image-20211207205710463
  • 将安全组资源的from_portto_port参数,设置为变量server_port的值的示例
image-20211207205722154
  • 要在字符串文字中使用变量引用,需要通过一种被称为插值(interpolation)的表达式,其语法如下
image-20211207205732229
  • 用户可以在花括号中放置任何有效的变量引用,Terraform会把它转换为字符串。例如,使用以下方法可以将var.server_port的取值作为字符串插入到用户数据中
image-20211207212228688
  • Terraform还允许通过使用以下语法来定义输出变量
image-20211207212239983
  • NAME是输出变量的名字,VALUE是任何你希望输出的Terraform表达式

举例来说,你可以将新创建的服务器的IP地址作为变量输出在命令行上

image-20211207212258905
  • 还可以在无须进行任何更改的情况下,使用terraformoutput命令列出所有的输出变量
image-20211207212319356
  • 运行terraformoutput命令来查看名为的特定输出变量的取值

部署 Web 服务器集群

  • 每个Terraform资源都支持生命周期设置,这些生命周期设置用于定义如何创建、更新和删除该资源。一个特别有用的生命周期设置是create_before_destroy。如果将create_before_destroy设置为true,那么Terraform将反转其替换资源的顺序,首先创建替换资源(包括将指向旧资源的所有外部引用,更新为指向替换资源),然后删除旧资源
image-20211207213207855
  • 使用数据源的语法与使用资源的语法非常相似
image-20211207213220424
  • PROVIDER是提供商的名称(例如aws),TYPE是要使用的数据源的类型(例如vpc),NAME是可以在整个Terraform代码中引用该数据源的标识符,CONFIG包含一个或多个针对该数据源的参数
image-20211207213231756
  • 要从数据源中读取数据,请使用属性引用语法
image-20211207213254100
  • 例如,要从aws_vpc数据源中获取VPCID信息,可以使用以下格式
image-20211207213305211
image-20211207213317117

第3章 如何管理Terraform的状态

什么是 Terraform 状态

  • 每次运行Terraform命令,它都会把创建的基础设施的信息记录在Terraform状态文件中。默认情况下,当你在/foo/bar文件夹中运行Terraform命令时,Terraform将创建状态文件/foo/bar/terraform.tfstateTerraform状态文件使用自定义JSON格式,记录了资源配置文件中的定义与现实世界中的部署的对应关系。例如,假设Terraform配置包含以下内容
image-20211207213435920
  • 运行terraformapply命令之后,以下是生成的terraform.tfstate文件
  • plan命令的输出是:计算机上存储的代码与现实世界中部署的基础设施之间的区别,这些区别是通过状态文件中的ID来发现的
  • 如果仅仅将Terraform用于个人项目,使用本地计算机保存terraform.tfstate文件就足够了
  • Terraform包含许多内置函数,可以通过以下的表达式执行这些函数
image-20211207214511722
  • terraformconsole命令打开一个交互式控制台,通过交互式控制台可以很好地实验内置函数的功能
image-20211207214523986
  • 这里有许多内置函数可以操作字符串、数字、列表和映射。[3]file函数是其中之一

第4章 使用Terraform模块创建可重用基础设施

图43:将代码放入模块中可以在多个环境中重复使用该代码

image-20211207214707885
  • 模块化是编写可重用、可维护和可测试的Terraform代码的关键要素。一旦开始使用,你一定会喜欢上模块并开始尝试:将所有代码功能模块化,在公司中创建模块共享库,使用网上发现的模块,甚至将整个基础设施看成可重复使用的模块的集合

模块基础知识

  • Terraform模块非常简单:位于同一文件夹中的任何Terraform配置文件的集合都是一个模块
  • 真正体现模块功能的方法是,从一个模块中调用另一个模块

图44:最终具有模块和预发布环境的文件夹结构

image-20211207214821094
  • 打开modules/services/webservercluster目录下的main.tf文件,删除provider定义。因为提供商的相关定义应该出现在调用模块的用户代码中,而不是模块本身的配置中
  • 可以在stage/services/webservercluster/main.tf中创建一个新文件,通过以下方式调用webservercluster模块
image-20211207214850770
  • 无论何时将模块添加到Terraform配置中或修改source模块的参数,都需要在运行planapply命令之前重新运行init命令
image-20211207214917886
  • 在运行apply之前,请注意webservercluster模块存在以下问题:文件中所有名称都是静态编码的。包括安全组、ALB和其他资源的名称都是静态编码的,因此,如果你多次使用此模块,则会出现命名冲突错误。数据库详细信息也是静态编码的
  • 要解决这些问题,需要向webservercluster模块添加可配置的输入,使其在不同的环境中有不一样的表现

模块的输入

  • Terraform的模块也可以具有输入参数。要定义它们,可以使用一种你已经熟悉的机制:输入变量。打开modules/services/webservercluster/variables.tf并添加3个新的输入变量
image-20211207214954992
  • 请注意这里是如何将name参数设置为"${var.cluster_name}alb"
image-20211207215018028
  • 在预发布环境的stage/services/webservercluster/main.tf文件中,需要相应地设置这些新的输入变量
image-20211207215044448
  • 所以除了使用输入变量,你还可以将它们定义为局部变量,放在locals模块中
image-20211207215102995
  • 要读取本地的值,需要使用本地引用,该引用使用以下语法
image-20211207215118805

模块的输出

  • 如果你在webservercluster模块中定义了计划操作,它同时既适用于预发布环境,又适用于生产环境。因为你不需要在预发布环境中进行缩放,所以你可以在生产环境的配置文件中定义自动缩放
  • 将以下两个关于aws_autoscaling_schedule的资源添加到prod/services/webservercluster/main.tf文件中
image-20211207215153386

模块中的陷阱

文件路径

  • 使用被称为路径引用(pathreference)的表达式,其形式为path.。Terraform支持以下类型的路径引用
  • path.module返回定义表达式的模块的文件系统路径
  • modules/services/webservercluster/main.tf文件中的template_file数据源中,应该使用path.module表达式
image-20211207215437760

内联块

  • aws_security_group资源允许你通过内联块定义入口和出口规则,如在webservercluster模块(modules/services/webservercluster/main.tf)中所见到的
image-20211207215502586
  • 应该使用完全独立的aws_security_group_rule资源改写模块,来配置相同的入口和出口规则
image-20211207215516331
  • 尝试混合使用内联块和独立资源,会因为路由规则冲突和互相覆盖而出现错误

模块版本控制

图4-5:在不同的环境中使用模块的不同版本

image-20211207215555595
  • 需要将stageprodglobal文件夹移到一个名为live的文件夹中。接下来,将livemodules文件夹配置为独立的Git存储库。以下是将modules文件夹配置为Git存储库的示例
image-20211207215619150
  • 使用Git CLI创建标签
image-20211207215628391

第5章 Terraform技巧和窍门:循环、if表达式、部署和陷阱

  • Terraform提供了一些原语:count元参数、for_eachfor表达式、一个被称为create_before_destroy的生命周期块、三元运算符及大量函数
  • 每个Terraform资源都有一个叫作count的元参数。countTerraform最古老、最简单和最有限的迭代构造器:它所做的只是定义要创建的资源副本个数。下面是使用count参数创建3个IAM用户的方法
image-20211208092910567
  • for循环中通过调用索引值i,为每个用户提供唯一的名称
image-20211208092953426
  • 可以使用count.index变量,获取循环中每次迭代的索引值
image-20211208093004885
  • 可以通过索引值i在数组var.user_names中的取值,为每个IAM用户设置不同的名称
image-20211208093023561
  • 数组查找语法
image-20211208093037041
  • 内联块中不支持使用count参数
  • 注意这里使用toset函数将var.user_names从列表转换为集合,这是因为for_each在用于资源时仅支持集合和映射
  • for_each循环此集合时,通过each.value可以获取每个用户名
  • 用户名也可以通过each.key取得,尽管通常只有在使用映射的键值对时,才会用到each.key对象
image-20211208093143610
  • 使用内置函数values(从映射中返回映射的值)和splat表达式来提取ARN
image-20211208093125279

第6章 生产级Terraform代码

为什么构建生产级基础设施需要漫长的过程

  • 生产级基础设施(productiongradeinfrastructure)包括服务器、数据存储、负载平衡器、安全功能、监视和警报工具、构建管道,以及经营业务所需的所有其他技术

表6-1:从零开始构建生产级基础设施需要的时间

image-20211208093222165
  • 生产级基础设施模块特点
  1. 模块要小型化
  2. 可组合的模块
  3. 可测试的模块
  4. 可发布的模块
  5. Terraform模块之外的内容
  • 软件项目的时间估计都是非常不准确的,DevOps项目的时间估算只会更糟糕。以为只需要5min的快速修改,往往会占用一整天的时间;估计需要一天完成的简单功能却持续了两个星期

生产级基础设施检查清单

  • 如果我们把所有工作列在一个检查清单上,绝大多数开发人员都不了解清单中的各项内容。因此当他们对项目进行评估时,会忽略大量关键且耗时的细节

表6-2:生产级基础设施检查清单

image-20211208123811735
  • 大多数开发人员都知道前几个任务:安装、配置、服务开通和部署。紧随其后的那些条目往往使他们措手不及

函数的第一个规则是它们应该很小;函数的第二个规则是它们应该更小

  • 将相对复杂的AWS架构重构为许多小型模块

图6-1:相对复杂的AWS架构

image-20211208123924589

图6-2:将相对复杂的AWS架构重构为许多小型模块

image-20211208123950956

UNIX的哲学思想是:每个程序只做一件事并做得很完美,再编写程序让它们协同工作

  • 函数组合(functioncomposition)是达到这一点的一种方法。在函数组合中,可以将一个函数的输出,作为输入传递给另一个函数
  • 如果将此示例(包括README.md)提交到版本控制系统中,则团队的其他成员可以通过它来了解模块的工作原理,并在不编写代码的情况下就可以试用模块
  • 一个非常有用的做法:版本固定(versionpinning
  • Terraform版本。至少需要设定Terraform的主要版本号
image-20211208124041199
  • Terraform的每个主要发行版并不向后兼容:例如,从0.11.x升级到0.12.x需要进行许多代码更改,升级版本需要专门的计划
  • 对于生产级代码,我建议执行更严格的版本固定
image-20211208124057104
  • 建议锁定所有的提供商程序版本
  • 发布模块的另一种方法是,将它们发布到Terraform注册中心

图6-4:Terraform注册中心中的HashiCorpVault模块

image-20211208124141058
  • 通过在source参数中使用较短的注册中心URL,在version参数中指定版本,语法细节如下

图6-5:Terraform注册中心会自动解析并显示模块的输入变量和输出变量

image-20211208124215342

一个使用来自Terraform注册中心的Vault模块的示例

image-20211208124227340

第7章 如何测试Terraform代码

强烈建议为每个团队设置一个隔离的沙箱环境,允许开发者按需求创建和删除基础设施,而不必担心影响其他人。实际上,为了减少多个开发人员之间发生冲突的机会(例如,两个开发人员试图创建一个同名的负载均衡器),黄金法则是每个开发人员都拥有完全隔离的沙箱环境

  • 应该养成一种习惯,开发人员在完成测试部署后,要通过运行terraform destroy清理所有内容

cloudnuke(见参考资料第7章[1])一个开源工具,可以删除云环境中的所有资源

每天在沙箱环境中以cron作业方式运行一次cloudnuke,删除超过两天的所有资源。这是基于一个假设:开发人员为手动测试启动的任何基础设施,超过两天就不再需要了。命令如下

JanitorMonkey(见参考资料第7章[2])一个开源工具,它通过可配置的时间表清除AWS资源(默认每周一次)。通过可配置规则,确定是否应清除资源,甚至可以在删除前几天,将通知发送给资源所有者


第8章 如何在团队环境下使用Terraform

  1. 与其告诉老板Terraform是声明性的,不如说明团队将如何使用它来更快地完成项目。与其谈论Terraform是支持多云环境的,不如描述一下,如果有一天迁移云环境时,老板不需要担心潜在的工具变更。与其向老板解释Terraform是开源的,不如帮助老板了解,从一个活跃的大型开源社区中,可以很容易地为团队雇用开发人员
  2. 当与老板交谈时,不要只是谈论Terraform的功能或好处,请用以下方式开始对话:“我有一个方法可以将停机次数减少一半”。我保证这会引起老板的注意

我在职业生涯中学到的最重要的教训之一是:大多数大型软件项目最终失败了。大约有四分之三的小型IT项目(小于100万美元)成功完成,而只有十分之一的大项目(大于1000万美元)最终按时并在预算之内完成,而超过三分之一的大项目从来没有完成

  • 增量主义至关重要。项目的每个部分都应该提供一定的价值,这样即使项目没有完成,无论实现到了哪一步,仍然可以输出一定的价值。最好的方法是,每一次集中解决单一的、小规模的、具体的问题
  • 如果通过快速解决一个真实的具体问题,让团队收获成功,你会开始赢得口碑。该团队可以成为你的啦啦队员,帮助说服其他团队加入迁移
  • 只有得到所有人的支持,提供了详尽的学习资源(文档、视频教程,当然还有本书!),并为团队成员安排专门学习的时间,才能实现这一目标

TerraformEnterprise

  • HashiCorp的企业产品提供了一个WebUI,可用于运行terraformplanterraform apply

Terragrunt

  • 这是一个开源的、基于Terraform的外壳工具,它填补了Terraform功能上的一些空白。本章稍后将会介绍,如何通过最少的复制/粘贴,在多个环境中部署版本化的Terraform代码

表8-1:应用程序代码和基础设施代码工作流程比较

image-20211208124703737
image-20211208124716190
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容