使用Terraform时的最佳做法

Mar*_*ung 91 terraform devops

我正在将我们的基础设施交换成terraform.实际管理terraform文件和状态的最佳实践是什么?我意识到它的基础设施是代码,我会将我的.tf文件提交到git中,但我也提交了tfstate吗?它应该驻留在S3这样的地方吗?我最终希望CI能够管理所有这些,但这已经非常紧张,需要我找出文件的移动部分.

我真的只是想看看那里的人们是如何在生产中使用这种类型的东西的

Yev*_*man 79

我们大量使用Terraform,我们推荐的设置如下:

文件布局

我们强烈建议您将每个环境(例如stage,prod,qa)的Terraform代码存储在单独的模板集中(因此,单独的.tfstate文件).这很重要,这样您的单独环境实际上会在进行更改时彼此隔离.否则,虽然在分段中搞乱了一些代码,但也很容易在prod中炸掉一些东西.请参阅Terraform,VPC以及为什么需要每个env的tfstate文件,以便对其进行丰富多彩的讨论.

因此,我们的典型文件布局如下所示:

stage
  ? main.tf
  ? vars.tf
  ? outputs.tf
prod
  ? main.tf
  ? vars.tf
  ? outputs.tf
global
  ? main.tf
  ? vars.tf
  ? outputs.tf
Run Code Online (Sandbox Code Playgroud)

阶段VPC的所有Terraform代码都进入stage文件夹,prod VPC的所有代码都进入prod文件夹,并且生活在VPC之外的所有代码(例如IAM用户,SNS主题,S3存储桶)都进入global文件夹.

请注意,按照惯例,我们通常将Terraform代码分解为3个文件:

  • vars.tf:输入变量.
  • outputs.tf:输出变量.
  • main.tf:实际资源.

模块

通常,我们在两个文件夹中定义基础架构:

  1. infrastructure-modules:此文件夹包含小型,可重复使用的版本化模块.将每个模块视为如何创建单个基础架构(如VPC或数据库)的蓝图.
  2. infrastructure-live:此文件夹包含实际的实时运行基础结构,它是通过组合模块创建的infrastructure-modules.将此文件夹中的代码视为您根据蓝图构建的实际房屋.

一个Terraform模块仅仅是任意一组的文件夹中Terraform模板.例如,我们可能有一个名为vpcin 的文件夹,infrastructure-modules它定义了单个VPC的所有路由表,子网,网关,ACL等:

infrastructure-modules
  ? vpc
    ? main.tf
    ? vars.tf
    ? outputs.tf
Run Code Online (Sandbox Code Playgroud)

然后我们可以在该模块中使用该模块infrastructure-live/stageinfrastructure-live/prod创建舞台和prod VPC.例如,以下是infrastructure-live/stage/main.tf可能的样子:

module "stage_vpc" {
  source = "git::git@github.com:gruntwork-io/module-vpc.git//modules/vpc-app?ref=v0.0.4"

  vpc_name         = "stage"
  aws_region       = "us-east-1"
  num_nat_gateways = 3
  cidr_block       = "10.2.0.0/18"
}
Run Code Online (Sandbox Code Playgroud)

要使用模块,请使用module资源并将其source字段指向硬盘驱动器上的本地路径(例如source = "../infrastructure-modules/vpc"),或者如上例中的Git URL(请参阅模块源).Git URL的优点是我们可以指定特定的git sha1或tag(ref=v0.0.4).现在,我们不仅将基础架构定义为一堆小模块,而且我们可以对这些模块进行版本化,并根据需要仔细更新或回滚.

我们已经创建了许多可重用,经过测试和记录的基础架构软件包,用于创建VPC,Docker集群,数据库等等,而且大多数都只是版本化的Terraform模块.

当您使用Terraform创建资源(例如EC2实例,数据库,VPC)时,它会记录有关它在.tfstate文件中创建的内容的信息.要对这些资源进行更改,团队中的每个人都需要访问同一个.tfstate文件,但是您不应该将其检入Git(请参阅此处以获取解释原因).

相反,我们建议.tfstate通过启用Terraform Remote State将文件存储在S3中,Terraform Remote State会在每次运行Terraform时自动推送/拉取最新文件.确保在S3存储桶中启用版本控制,以便您可以回滚到较旧的.tfstate文件,以防您以某种方式损坏最新版本.但是,一个重要的注意事项:Terraform不提供锁定.因此,如果两个团队成员terraform apply同时在同一个.tfstate文件上运行,他们最终可能会覆盖彼此的更改.

为了解决这个问题,我们创建了一个名为Terragrunt的开源工具,它是Terraform的一个瘦包装器,它使用Amazon DynamoDB提供锁定(大多数团队应该完全免费).退房添加自动遥控状态下进行锁定和配置与Terragrunt对terraform获取更多信息.

进一步阅读

我们刚刚开始了一系列名为"Terraform综合指南"的博客文章,详细描述了我们在现实世界中使用Terraform所学到的所有最佳实践.

更新:Terraform博客文章系列综合指南非常受欢迎,我们将其扩展为一本名为Terraform:Up&Running的书!


Ewa*_*wan 73

我也处于将现有AWS基础架构迁移到Terraform的状态,因此我的目标是在我开发时更新答案.

我一直非常依赖官方Terraform的例子和多次反复试验来充实我不确定的领域.

.tfstate

Terraform配置可用于在不同的基础架构上配置多个盒子,每个盒子可以具有不同的状态.由于它也可以由多个人运行,因此该状态应该位于集中位置(如S3),而不是 git.

这可以通过Terraform来确认.gitignore.

开发者控制

我们的目标是为开发人员提供更多的基础架构控制,同时保持完整的审计(git日志)和完整性检查更改(拉取请求)的能力.考虑到这一点,我的目标是新的基础设施工作流程:

  1. 常见AMI的基础包括可重复使用的模块,例如puppet.
  2. DevOps使用Terraform提供的核心基础架构.
  3. 开发人员根据需要在Git中更改Terraform配置(实例数;新VPC;添加区域/可用区等).
  4. 推送Git配置并提交拉取请求以由DevOps小队成员检查.
  5. 如果获得批准,请调用webhook到CI进行构建和部署(此时不确定如何对多个环境进行分区)

编辑1 - 更新当前状态

自从开始这个答案以来,我已经编写了很多TF代码,并且在我们的事态中感觉更舒服.我们在此过程中遇到了漏洞和限制,但我接受这是使用新的,快速变化的软件的一个特征.

布局

我们有一个复杂的AWS基础架构,其中有多个VPC,每个VPC都有多个子网.轻松管理这一点的关键是定义一个灵活的分类,包括区域,环境,服务和所有者,我们可以使用它来组织我们的基础设施代码(terraform和puppet).

模块

下一步是创建一个git存储库来存储我们的terraform模块.我们的模块的顶级目录结构如下所示:

tree -L 1 .
Run Code Online (Sandbox Code Playgroud)

结果:

??? README.md
??? aws-asg
??? aws-ec2
??? aws-elb
??? aws-rds
??? aws-sg
??? aws-vpc
??? templates
Run Code Online (Sandbox Code Playgroud)

每一个都设置一些理智的默认值,但将它们公开为可被我们的"胶水"覆盖的变量.

我们有第二个存储库glue,它使用上面提到的模块.它符合我们的分类标准文件:

.
??? README.md
??? clientA
?   ??? eu-west-1
?   ?   ??? dev
?   ??? us-east-1
?       ??? dev
??? clientB
?   ??? eu-west-1
?   ?   ??? dev
?   ?   ??? ec2-keys.tf
?   ?   ??? prod
?   ?   ??? terraform.tfstate
?   ??? iam.tf
?   ??? terraform.tfstate
?   ??? terraform.tfstate.backup
??? clientC
    ??? eu-west-1
    ?   ??? aws.tf
    ?   ??? dev
    ?   ??? iam-roles.tf
    ?   ??? ec2-keys.tf
    ?   ??? prod
    ?   ??? stg
    ?   ??? terraform.tfstate
    ??? iam.tf
Run Code Online (Sandbox Code Playgroud)

在客户端级别内,我们拥有AWS账户特定.tf文件,可以提供全局资源(如IAM角色); 接下来是具有EC2 SSH公钥的区域级别; 最后,在我们的环境中(dev,stg,prod等)是我们的VPC设置,例如创建和对等连接等存储.

旁注:正如你所看到的那样,我违背自己的建议,而不是terraform.tfstate坚持使用git.这是一个临时措施,直到我转移到S3但适合我,因为我目前是唯一的开发人员.

下一步

这仍然是一个手动过程,而不是詹金斯,但我们正在移植一个相当大,复杂的基础设施,到目前为止一直很好.就像我说的那样,很少有错误,但进展顺利!

编辑2 - 更改

我写这个初步答案差不多一年了,Terraform和我的状态都发生了很大变化.我现在处于一个新的位置,使用Terraform管理Azure集群,现在就是Terraform v0.10.7.

人们一再告诉我的状态应该不会在Git中去-他们是正确的.我们将此作为一项临时措施,由两人团队依赖开发人员沟通和纪律.对于较大的,分布式的团队,我们正在充分利用远程状态S3与锁定由DynamoDB提供.理想情况下,这将迁移到consul现在是v1.0来削减跨云提供商.

模块

以前我们创建并使用了内部模块.情况仍然如此,但随着Terraform注册表的出现和发展,我们尝试将这些作为至少一个基础.

文件结构

新职位的分类更为简单,只有两个infx环境 - dev而且prod.每个都有自己的变量和输出,重用我们上面创建的模块.该remote_state供应商还有助于在环境之间共享创建的资源的输出.我们的方案是不同Azure资源组中的子域与全球管理的TLD.

??? main.tf
??? dev
?   ??? main.tf
?   ??? output.tf
?   ??? variables.tf
??? prod
    ??? main.tf
    ??? output.tf
    ??? variables.tf
Run Code Online (Sandbox Code Playgroud)

规划

再加上分布式团队的额外挑战,我们现在总是保存terraform plan命令的输出.我们可以检查并知道将运行什么,而不会在阶段planapply阶段之间发生某些变化(尽管锁定有助于此).请记住删除此计划文件,因为它可能包含纯文本"秘密"变量.

总的来说,我们对Terraform非常满意,并继续学习和改进添加的新功能.

  • 我很好奇为什么您认为tfstate文件不应该存储在git中?仅仅是因为旧状态不值得保存,还是还有其他问题? (2认同)
  • @agbodike - 当作为一个开发人员或一个非常小的团队的一部分工作时,tfstate可以保存在git中,只要它经常被提交并推动以避免冲突.我的下一步是根据他们在S3中的[远程状态](https://terraform.io/docs/state/remote.html)文档进行设置(其中也说:"它使团队中的Terraform工作变得复杂因为它是合并冲突的常见来源.远程状态有助于缓解这些问题.").与大多数事情一样,虽然良好的团队沟通可以帮助缓解大多数/所有问题,无论保持状态的策略如何:-) (2认同)
  • 在Git repo @Ewan上运气好吗?我很想看看你在做什么. (2认同)

Sha*_*anu 9

以前remote config允许这个,但现在已被" 后端 " 取代,因此terraform遥控器不再可用.

terraform remote config -backend-config="bucket=<s3_bucket_to_store_tfstate>" -backend-config="key=terraform.tfstate" -backend=s3
terraform remote pull
terraform apply
terraform remote push
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅文档.


Sno*_*ash 6

@Yevgeny Brikman 进行了更深入的介绍,但专门回答了 OP 的问题:

实际管理 terraform 文件和状态的最佳实践是什么?

对 TF 文件使用 git。但不要检查状态文件(即 tfstate)。而是Terragrunt用于将状态文件同步/锁定到 S3。

但我也提交 tfstate 吗?

不。

它应该位于像 S3 这样的地方吗?

是的