译者序
- 敏捷开发的出现大大提高了软件开发的效率
-
DevOps
的重点之所以是运维,一个原因是在开发团队实施敏捷开发后,运维团队成了新的瓶颈;另一方面是运维领域的硬件虚拟化(服务器变成了虚拟机,数据中心变成了云计算平台)所带来的挑战—硬件的搭建和改变更加频繁,使原有的思想和技术很难继续支持业务的发展
前言
- 在
Terraform
面世后的5年中,有4年的时间我都在自己的公司Gruntwork
(见参考资料文前[2])里使用这个工具。我们将Terraform
作为核心工具,创建了包含30万行代码的可重复使用的模块库,这些基础设施代码经受了数百家公司生产环境的实战检验 https://github.com/brikis98/terraformupandrunningcode
第1章 为什么使用Terraform
DevOps 的崛起
- 软件只有最终交付给用户才标志着项目的结束
- 软件交付(
softwaredelivery
)是指通过一系列工作使代码最终对客户“可见、可用”的过程,例如,将代码运行在生产服务器之上,使代码能够应对数据流量的激增和意外停机中断,保护代码免受攻击者破坏 - 经过
DevOps
转型的公司往往都有令人震惊的结果
-
Nordstrom
在应用DevOps
最佳实践之后,能够将每月交付的功能数量增加100%,缺陷减少50%,交货时间(从构思创意到将产品运行在生产环境的总时长)缩短60%,生产事故的数量减少60%至90% - 惠普的
LaserJet
固件部门采用DevOps
后,其开发人员花在开发新功能上的时间从5%增加到40%,总体开发成本减少了40%
-
DevOps
有四大核心价值(CAMS
)
- 文化(
culture
) - 自动化(
automation
) - 度量(
measurement
) - 共享(
sharing
)
基础设施即代码(
IaC
):DevOps
自动化的目标是将软件交付过程自动化。所以落实到管理基础设施方面,也要尽可能多地通过代码来进行,减少点击网页或手动执行Shell
命令的方式
什么是基础设施即代码
- 基础设施即代码背后的想法是,通过编写和执行代码来定义、部署、更新和销毁基础设施。这代表着一种观念上的重要转变:将运维的各个工作都视为与软件相关,甚至包括那些明显针对硬件的工作(如设置物理服务器)
-
DevOps
的一个重要观点是,用户应该将所有事物都在代码中进行管理,包括服务器、数据库、网络、日志文件、应用程序配置、文档、自动测试、部署过程等
IaC工具分为5大类
专项脚本
- 自动化最直接的方法是为每一项任务写一个专项脚本
- 专项脚本对那些小规模的、一次性的任务很有效,但如果计划把基础设施作为代码进行管理,那么你应该使用专业的
IaC
工具
配置管理工具
-
Chef
、Puppet
、Ansible
和SaltStack
都属于配置管理工具,它们的目的是在现有服务器上安装和管理软件
服务器模板工具
- “服务器模板化”是向不可变基础设施(
immutableinfrastructure
)迁移的关键步骤
编排工具
服务开通工具
- 通过配置管理、服务器模板和编排工具可以定义服务器上运行的代码,但还是需要
Terraform
、CloudFormation
和OpenStackHeat
等工具,负责创建服务器本身。实际上
例如,下面的
Terraform
代码部署了一台Web
服务器
图1-5:使用服务开通工具,通过云服务提供商提供的接口,来创建服务器、数据库、负载均衡器,以及基础设施的所有其他部分
user_data
:服务器启动时,需要执行的 Bash
脚本
基础设施即代码的好处
- 代码的功能是极其强大的。通过早期投入将手动工作转化为代码,你的软件交付能力将得到显著改善
使用
DevOps
实践(例如IaC
)的组织,部署频率提高了200倍,从故障中恢复的速度提高了24倍,交付周期缩短为原来的1/2555
自助服务
- 大多数手动部署代码的团队,只有极少数的系统管理员(通常只有一个人)知道部署过程的全部细节,并且是唯一有权限访问生产环境的人。随着公司的发展,这将成为一个主要的瓶颈
速度和安全性
- 自动化将大大加速部署过程,因为计算机可以比人更快、更安全地执行部署步骤
文档
- 将基础设施定义为代码之后,就可以将其状态保存并显示在任何人都可以读取的源文件中
版本控制
- 将
IaC
源文件存储在版本控制系统中,基础设施的历史变更记录将在提交日志中被完整保留
验证
- 如果在代码中定义基础设施的状态,则对于每一个更改都可以执行代码评审、运行自动测试
重用
- 基础设施可以打包成可重用的模块,这样针对每个新产品、新环境,可以避免从头编写部署代码,通过利用已知的、经过实战测试的模块[1],达到快速开发的目的
幸福感
- 部署代码和管理基础设施经常是重复且乏味的任务。开发人员和系统管理员都厌恶这种没有创意、没有挑战、不被认可的工作。连续几个月的完美的代码部署,却没有引起任何关注。直到有一天部署出了问题,大家才会意识到你的存在
Terraform 的工作原理
-
Terraform
使用Go
语言编写,是由HashiCorp
公司创建的开源工具
Terraform
配置文件的示例
- 首先调用
AWS
的API
来部署一台服务器。然后调用GoogleCloud
的API
,创建指向AWS
服务器IP
地址的DNS
条目 - 用户可以在
Terraform
配置文件中定义整套基础设施:服务器、数据库、负载均衡器、网络拓扑等,然后将配置文件提交到版本控制系统。接下来,通过运行Terraform
命令,例如terraformapply
命令,来部署该基础设施。terraform
命令将对代码进行解析,将代码转化为云服务提供商的一系列API
调用,并在此过程中优化API
调用
图1-6:
Terraform
工具将用户的配置文件中的内容转换为对云服务提供商的API
调用
Terraform 与其他 Iac 工具的比较
- 以下是要主要的考虑和对比方向
配置管理与服务开通对比
- 诸如
Docker
或Packer
之类的服务器模板工具,已经实现了绝大多数配置管理工具的功能 - 在服务开通阶段,服务开通工具将是最佳选择
可变基础设施与不可变基础设施对比
- 使用诸如
Terraform
之类的服务开通工具来部署由Docker
或Packer
创建的机器映像,大多数“更改”实际上是部署一个全新的服务器 - 这种方法降低了发生配置漂移错误的可能性,使你更准确地知道每个服务器上正在运行的软件,并允许用户轻松地将部署恢复到之前的任何版本(通过使用以前的映像)
过程性语言与声明性语言对比
-
Terraform
、CloudFormation
、SaltStack
、Puppet
和OpenStackHeat
都鼓励使用声明性编程语言,在这种语言中,用户可以编写代码来指示工具所要达到的最终状态,而IaC
工具将负责决定具体的实现步骤 - 如果利用声明性代码,你要做的就是声明所需的最终状态,然后由
Terraform
自己决定如何达到该最终状态,Terraform
也会记录它过去创建的任何状态。因此,对于部署5台服务器,你要做的就是使用相同的Terraform
配置,并将数量从10更新到15 - 如果应用这个配置,
Terraform
将意识到它已经创建了10台服务器,因此要做的就是再创建5台新的服务器 - 可以使用
Terraform
的plan
命令来预览将要发生的变更
过程性程序代码限制可重用性
- 过程性的程序代码的重用性是十分有限的,因为你必须考虑基础设施的当前状态
- 使用
Terraform
的声明性语言,代码始终代表基础设施的最新状态。通过阅读代码,你可以确定当前环境的部署内容及配置细节,不必担心历史记录或时间顺序
影响安全性
-
Ansible
、CloudFormation
、Heat
和Terraform
均为无主控服务器软件。更准确地说,其中一些可能依赖于主控服务器,但是这些服务器已经是你正在使用的基础设施的一部分,而不需要你去管理额外的组件。例如,Terraform
使用云服务提供商的API
与云平台进行通信,从某种意义上讲,API
服务器就扮演着主控服务器的角色
大型社区与小型社区对比
- 比较了流行的
IaC
工具,比较项目包括开源和闭源、所支持的云服务提供商、GitHub
上的贡献者和得星评级总数、在一个月内(4月中旬到5月中旬)活跃的提交总数、一个月内错误报告总数、有多少开源库可供该工具使用、在StackOverflow
上针对该工具列出的提问数,以及该工具在Indeed.com
上的职位数
表1-1:
IaC
社区的比较
表1-2:
IaC
社区自2016年9月至2019年5月之间的变化
同时使用多个工具
- 搭配使用
Terraform
和Ansible
,如图19所示。你可以使用Terraform
部署所有基础设施,包括网络拓扑(如虚拟私有云VPC
、子网、路由表)、数据存储(如MySQL
、Redis
)、负载均衡器和服务器。然后使用Ansible
将应用程序部署在这些服务器之上
图19:搭配使用
Terraform
和Ansible
- 使用
Packer
创建包括Docker
和Kubernetes
服务的虚拟机映像。然后通过Terraform
部署服务器集群,每个服务器都运行此虚拟机映像,以及其余基础设施,包括网络拓扑(即VPC
、子网、路由表)、数据存储(如MySQL
、Redis
)和负载均衡器
图1-11:搭配使用
Terraform
、Packer
、Docker
和Kubernetes
第2章 Terraform入门
设置 AWS 账户
- 几乎每个
AWS
资源都需要部署到VPC
中才能工作,如果未明确指定目标VPC
,则资源将被部署到默认VPC
中
安装 Terraform
- 为了使
Terraform
能够对你的AWS
账户进行直接操作,需要将环境变量AWS_ACCESS_KEY_ID
和AWS_SECRET_ACCESS_KEY
设置为之前创建的IAM
用户的访问ID
和密钥
- 除了通过环境变量进行身份验证,
Terraform
也支持与所有AWS
命令行工具和SDK
工具相同的身份验证机制,使用$HOME/.aws/credentials
文件中的密钥,密钥信息可以通过在AWS
命令行或IAM
角色上运行configure
命令自动生成
部署单个服务器
-
Terraform
代码是以HashiCorp
配置语言(HashiCorpConfigurationLanguage
,HCL
)编写的,扩展名为.tf
。[1]HCL
是一种声明性语言,目标是描述所需的基础设施,Terraform
将自动计算生成创建它的方法 - 大多数编辑器也提供对
Terraform
语法的支持(需要在网上搜索单词“HCL
”而不是“Terraform
”来获取相关信息),包括vim
、Emacs
、SublimeText
、Atom
、VisualStudioCode
和IntelliJ
(IntelliJ
甚至支持重构、查找用法和声明跳转) - 使用
Terraform
的第一步通常是配置要使用的提供商。创建一个空文件夹,并在其中放置一个名为main.tf
的文件,该文件包含以下内容
- 在
Terraform
中创建资源的一般语法如下
例如,如果想在
AWS
中部署单个EC2
(虚拟)服务器实例,则需要将aws_instance
资源配置在main.tf
中
-
aws_instance
资源支持许多不同的参数,但只有两个参数是必须要设置的
- ami:运行在
EC
2实例上的AmazonMachineImage
(AMI
) - instance_type:
EC2
运行实例的类型。每种类型的EC2
实例都提供不同数量的CPU
、内存、磁盘空间和网络带宽
我们很难记住每个提供商所支持的众多资源,以及每个资源的全部参数。在编写
Terraform
代码时,你需要定期参考Terraform
文档,查找可供使用的资源及其使用方法
- 运行
terraform init
命令
- 第一次开始使用
Terraform
时,需要运行terraforminit
命令,指示Terraform
扫描代码,找出用到的提供商,并下载它们需要使用的代码库。在默认情况下,提供商代码将被下载到.terraform
文件夹中,该文件夹是Terraform
的临时目录(用户或许需要将其添加到.gitignore
,以防止将这个临时目录上传到版本控制系统) - 现在你已经下载了提供商代码,请运行
terraform plan
命令
-
plan
命令可以让你在任何实际更改之前对Terraform
进行预览,以便代码在发布给外界之前进行最后的检查
- 加号(+)代表任何新添加的内容
- 减号(-)代表删除的内容
- 波浪号(〜)代表所有将被修改的内容
- 要创建这个实例,请运行
terraform apply
命令
- 还需要创建一个名为
.gitignore
的文件,它会告诉Git
忽略某些类型的文件,以免你无意中将临时文件存入版本控制系统中
- 前面的
.gitignore
文件的内容,指示Git
忽略Terraform
临时目录.terraform
文件夹,以及Terraform
用来存储状态的*.tfstate
文件
部署可配置的 Web 服务器
-
EC
2实例启动时,将执行以用户数据方式传递进来的Shell
脚本或cloudinit
指令。Terraform
脚本使用user_data
参数,将Shell
脚本作为对象,传递给AMI
用户数据,如下所示
- 引用(reference)是一种特别有用的表达式类型,它使用户可以从代码的其他部分访问该值。如果要访问安全组资源 ID,需要使用资源属性引用(resource attribute reference),语法如下
- 当在一个资源内引用另一个资源时,会创建隐式依赖关系。
Terraform
可以通过分析这些依赖关系,构建依赖关系图,并使用该关系图自动确定资源的创建顺序 - 可以通过运行
terraform graph
命令显示依赖关系图
- 以上输出的格式为
DOT
图形描述语言,通过使用桌面应用,例如Graphviz
,或Web
应用GraphvizOnline
- 当
Terraform
遍历你的依赖关系树时,它会尽量使用并行方式创建尽可能多的资源,从而更有效地实现变更 - 计划输出中的/+符号表示“替换”。通过在计划输出中查找
forcesreplacement
(强制替换)字段,可以得到Terraform
进行强制替换的原因
- 声明变量的语法
-
description
:描述参数用来说明如何使用这个变量 -
default
:有多种方法可以为变量赋值,包括通过命令行(使用var
选项),通过属性文件(使用varfile
选项)或通过环境变量(Terraform
能够查找并识别前缀为TF_VAR
_的环境变量)。如果未传入任何值,变量将使用默认值。如果没有默认值,Terraform
将以交互方式提示用户输入一个值 -
type
:允许对用户输入的变量类型进行强制约束。Terraform
支持许多类型约束,包括string
、number
、bool
、list
、map
、set
、object
、tuple
和any
-
Terraform
会设置默认约束类型为any
- 通过类型约束来验证输入的值为数字
- 检查输入值是否为列表
- 所有的列表值为数字
- 使用类型约束创建更复杂的对象和元组结构类型
- 尝试将
enabled
变量设置为字符串而不是一个布尔值
- 会得到以下错误
- 请注意,
server_port
输入变量没有默认值,因此,如果运行apply
命令,Terraform
将提示输入server_port
的值,并显示变量中的description
值
- 如果不想每次都处理交互式提示,可以通过命令行的
var
参数为输入变量提供初始值
- 也可以通过环境变量来设置输入变量初始值。命名规范是
TF_VAR
_,其中是你要设置的输入变量的名称
- 如果不想在每次运行
plan
或apply
时都记住额外的命令行参数,也可以指定一个默认值
- 使用一种被称为变量引用(
variablereference
)的新型表达式,语法如下
- 将安全组资源的
from_port
和to_port
参数,设置为变量server_port
的值的示例
- 要在字符串文字中使用变量引用,需要通过一种被称为插值(
interpolation
)的表达式,其语法如下
- 用户可以在花括号中放置任何有效的变量引用,
Terraform
会把它转换为字符串。例如,使用以下方法可以将var.server_port
的取值作为字符串插入到用户数据中
-
Terraform
还允许通过使用以下语法来定义输出变量
-
NAME
是输出变量的名字,VALUE
是任何你希望输出的Terraform
表达式
举例来说,你可以将新创建的服务器的
IP
地址作为变量输出在命令行上
- 还可以在无须进行任何更改的情况下,使用
terraformoutput
命令列出所有的输出变量
- 运行
terraformoutput
命令来查看名为的特定输出变量的取值
部署 Web 服务器集群
- 每个
Terraform
资源都支持生命周期设置,这些生命周期设置用于定义如何创建、更新和删除该资源。一个特别有用的生命周期设置是create_before_destroy
。如果将create_before_destroy
设置为true
,那么Terraform
将反转其替换资源的顺序,首先创建替换资源(包括将指向旧资源的所有外部引用,更新为指向替换资源),然后删除旧资源
- 使用数据源的语法与使用资源的语法非常相似
-
PROVIDER
是提供商的名称(例如aws
),TYPE
是要使用的数据源的类型(例如vpc
),NAME
是可以在整个Terraform
代码中引用该数据源的标识符,CONFIG
包含一个或多个针对该数据源的参数
- 要从数据源中读取数据,请使用属性引用语法
- 例如,要从
aws_vpc
数据源中获取VPC
的ID
信息,可以使用以下格式
第3章 如何管理Terraform的状态
什么是 Terraform 状态
- 每次运行
Terraform
命令,它都会把创建的基础设施的信息记录在Terraform
状态文件中。默认情况下,当你在/foo/bar
文件夹中运行Terraform
命令时,Terraform
将创建状态文件/foo/bar/terraform.tfstate
。Terraform
状态文件使用自定义JSON
格式,记录了资源配置文件中的定义与现实世界中的部署的对应关系。例如,假设Terraform
配置包含以下内容
- 运行
terraformapply
命令之后,以下是生成的terraform.tfstate
文件 -
plan
命令的输出是:计算机上存储的代码与现实世界中部署的基础设施之间的区别,这些区别是通过状态文件中的ID
来发现的 - 如果仅仅将
Terraform
用于个人项目,使用本地计算机保存terraform.tfstate
文件就足够了 -
Terraform
包含许多内置函数,可以通过以下的表达式执行这些函数
-
terraformconsole
命令打开一个交互式控制台,通过交互式控制台可以很好地实验内置函数的功能
- 这里有许多内置函数可以操作字符串、数字、列表和映射。[3]
file
函数是其中之一
第4章 使用Terraform模块创建可重用基础设施
图43:将代码放入模块中可以在多个环境中重复使用该代码
- 模块化是编写可重用、可维护和可测试的
Terraform
代码的关键要素。一旦开始使用,你一定会喜欢上模块并开始尝试:将所有代码功能模块化,在公司中创建模块共享库,使用网上发现的模块,甚至将整个基础设施看成可重复使用的模块的集合
模块基础知识
-
Terraform
模块非常简单:位于同一文件夹中的任何Terraform
配置文件的集合都是一个模块 - 真正体现模块功能的方法是,从一个模块中调用另一个模块
图44:最终具有模块和预发布环境的文件夹结构
- 打开
modules/services/webservercluster
目录下的main.tf
文件,删除provider
定义。因为提供商的相关定义应该出现在调用模块的用户代码中,而不是模块本身的配置中 - 可以在
stage/services/webservercluster/main.tf
中创建一个新文件,通过以下方式调用webservercluster
模块
- 无论何时将模块添加到
Terraform
配置中或修改source
模块的参数,都需要在运行plan
或apply
命令之前重新运行init
命令
- 在运行
apply
之前,请注意webservercluster
模块存在以下问题:文件中所有名称都是静态编码的。包括安全组、ALB
和其他资源的名称都是静态编码的,因此,如果你多次使用此模块,则会出现命名冲突错误。数据库详细信息也是静态编码的 - 要解决这些问题,需要向
webservercluster
模块添加可配置的输入,使其在不同的环境中有不一样的表现
模块的输入
-
Terraform
的模块也可以具有输入参数。要定义它们,可以使用一种你已经熟悉的机制:输入变量。打开modules/services/webservercluster/variables.tf
并添加3个新的输入变量
- 请注意这里是如何将
name
参数设置为"${var.cluster_name}alb"
的
- 在预发布环境的
stage/services/webservercluster/main.tf
文件中,需要相应地设置这些新的输入变量
- 所以除了使用输入变量,你还可以将它们定义为局部变量,放在
locals
模块中
- 要读取本地的值,需要使用本地引用,该引用使用以下语法
模块的输出
- 如果你在
webservercluster
模块中定义了计划操作,它同时既适用于预发布环境,又适用于生产环境。因为你不需要在预发布环境中进行缩放,所以你可以在生产环境的配置文件中定义自动缩放 - 将以下两个关于
aws_autoscaling_schedule
的资源添加到prod/services/webservercluster/main.tf
文件中
模块中的陷阱
文件路径
- 使用被称为路径引用(
pathreference
)的表达式,其形式为path
.。Terraform
支持以下类型的路径引用 -
path.module
返回定义表达式的模块的文件系统路径 - 在
modules/services/webservercluster/main.tf
文件中的template_file
数据源中,应该使用path.module
表达式
内联块
-
aws_security_group
资源允许你通过内联块定义入口和出口规则,如在webservercluster
模块(modules/services/webservercluster/main.tf
)中所见到的
- 应该使用完全独立的
aws_security_group_rule
资源改写模块,来配置相同的入口和出口规则
- 尝试混合使用内联块和独立资源,会因为路由规则冲突和互相覆盖而出现错误
模块版本控制
图4-5:在不同的环境中使用模块的不同版本
- 需要将
stage
、prod
和global
文件夹移到一个名为live
的文件夹中。接下来,将live
和modules
文件夹配置为独立的Git
存储库。以下是将modules
文件夹配置为Git
存储库的示例
- 使用
Git CLI
创建标签
第5章 Terraform技巧和窍门:循环、if表达式、部署和陷阱
-
Terraform
提供了一些原语:count
元参数、for_each
和for
表达式、一个被称为create_before_destroy
的生命周期块、三元运算符及大量函数 - 每个
Terraform
资源都有一个叫作count
的元参数。count
是Terraform
最古老、最简单和最有限的迭代构造器:它所做的只是定义要创建的资源副本个数。下面是使用count
参数创建3个IAM
用户的方法
- 在
for
循环中通过调用索引值i
,为每个用户提供唯一的名称
- 可以使用
count.index
变量,获取循环中每次迭代的索引值
- 可以通过索引值
i
在数组var.user_names
中的取值,为每个IAM
用户设置不同的名称
- 数组查找语法
- 内联块中不支持使用
count
参数 - 注意这里使用
toset
函数将var.user_names
从列表转换为集合,这是因为for_each
在用于资源时仅支持集合和映射 - 当
for_each
循环此集合时,通过each.value
可以获取每个用户名 - 用户名也可以通过
each.key
取得,尽管通常只有在使用映射的键值对时,才会用到each.key
对象
- 使用内置函数
values
(从映射中返回映射的值)和splat
表达式来提取ARN
值
第6章 生产级Terraform代码
为什么构建生产级基础设施需要漫长的过程
- 生产级基础设施(
productiongradeinfrastructure
)包括服务器、数据存储、负载平衡器、安全功能、监视和警报工具、构建管道,以及经营业务所需的所有其他技术
表6-1:从零开始构建生产级基础设施需要的时间
- 生产级基础设施模块特点
- 模块要小型化
- 可组合的模块
- 可测试的模块
- 可发布的模块
-
Terraform
模块之外的内容
- 软件项目的时间估计都是非常不准确的,
DevOps
项目的时间估算只会更糟糕。以为只需要5min
的快速修改,往往会占用一整天的时间;估计需要一天完成的简单功能却持续了两个星期
生产级基础设施检查清单
- 如果我们把所有工作列在一个检查清单上,绝大多数开发人员都不了解清单中的各项内容。因此当他们对项目进行评估时,会忽略大量关键且耗时的细节
表6-2:生产级基础设施检查清单
- 大多数开发人员都知道前几个任务:安装、配置、服务开通和部署。紧随其后的那些条目往往使他们措手不及
函数的第一个规则是它们应该很小;函数的第二个规则是它们应该更小
- 将相对复杂的
AWS
架构重构为许多小型模块
图6-1:相对复杂的
AWS
架构
图6-2:将相对复杂的
AWS
架构重构为许多小型模块
UNIX
的哲学思想是:每个程序只做一件事并做得很完美,再编写程序让它们协同工作
- 函数组合(
functioncomposition
)是达到这一点的一种方法。在函数组合中,可以将一个函数的输出,作为输入传递给另一个函数 - 如果将此示例(包括
README.md
)提交到版本控制系统中,则团队的其他成员可以通过它来了解模块的工作原理,并在不编写代码的情况下就可以试用模块 - 一个非常有用的做法:版本固定(
versionpinning
) -
Terraform
版本。至少需要设定Terraform
的主要版本号
-
Terraform
的每个主要发行版并不向后兼容:例如,从0.11.x
升级到0.12.x
需要进行许多代码更改,升级版本需要专门的计划 - 对于生产级代码,我建议执行更严格的版本固定
- 建议锁定所有的提供商程序版本
- 发布模块的另一种方法是,将它们发布到
Terraform
注册中心
图6-4:
Terraform
注册中心中的HashiCorpVault
模块
- 通过在
source
参数中使用较短的注册中心URL
,在version
参数中指定版本,语法细节如下
图6-5:
Terraform
注册中心会自动解析并显示模块的输入变量和输出变量
一个使用来自
Terraform
注册中心的Vault
模块的示例
第7章 如何测试Terraform代码
强烈建议为每个团队设置一个隔离的沙箱环境,允许开发者按需求创建和删除基础设施,而不必担心影响其他人。实际上,为了减少多个开发人员之间发生冲突的机会(例如,两个开发人员试图创建一个同名的负载均衡器),黄金法则是每个开发人员都拥有完全隔离的沙箱环境
- 应该养成一种习惯,开发人员在完成测试部署后,要通过运行
terraform destroy
清理所有内容
cloudnuke
(见参考资料第7章[1])一个开源工具,可以删除云环境中的所有资源每天在沙箱环境中以
cron
作业方式运行一次cloudnuke
,删除超过两天的所有资源。这是基于一个假设:开发人员为手动测试启动的任何基础设施,超过两天就不再需要了。命令如下
JanitorMonkey
(见参考资料第7章[2])一个开源工具,它通过可配置的时间表清除AWS
资源(默认每周一次)。通过可配置规则,确定是否应清除资源,甚至可以在删除前几天,将通知发送给资源所有者
第8章 如何在团队环境下使用Terraform
- 与其告诉老板
Terraform
是声明性的,不如说明团队将如何使用它来更快地完成项目。与其谈论Terraform
是支持多云环境的,不如描述一下,如果有一天迁移云环境时,老板不需要担心潜在的工具变更。与其向老板解释Terraform
是开源的,不如帮助老板了解,从一个活跃的大型开源社区中,可以很容易地为团队雇用开发人员 - 当与老板交谈时,不要只是谈论
Terraform
的功能或好处,请用以下方式开始对话:“我有一个方法可以将停机次数减少一半”。我保证这会引起老板的注意
我在职业生涯中学到的最重要的教训之一是:大多数大型软件项目最终失败了。大约有四分之三的小型
IT
项目(小于100万美元)成功完成,而只有十分之一的大项目(大于1000万美元)最终按时并在预算之内完成,而超过三分之一的大项目从来没有完成
- 增量主义至关重要。项目的每个部分都应该提供一定的价值,这样即使项目没有完成,无论实现到了哪一步,仍然可以输出一定的价值。最好的方法是,每一次集中解决单一的、小规模的、具体的问题
- 如果通过快速解决一个真实的具体问题,让团队收获成功,你会开始赢得口碑。该团队可以成为你的啦啦队员,帮助说服其他团队加入迁移
- 只有得到所有人的支持,提供了详尽的学习资源(文档、视频教程,当然还有本书!),并为团队成员安排专门学习的时间,才能实现这一目标
TerraformEnterprise
-
HashiCorp
的企业产品提供了一个WebUI
,可用于运行terraformplan
和terraform apply
Terragrunt
- 这是一个开源的、基于
Terraform
的外壳工具,它填补了Terraform
功能上的一些空白。本章稍后将会介绍,如何通过最少的复制/粘贴,在多个环境中部署版本化的Terraform
代码
表8-1:应用程序代码和基础设施代码工作流程比较