首页 文章

使用Terraform时的最佳做法

提问于
浏览
63

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

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

6 回答

  • 0

    如果您仍在寻找更好的解决方案,请查看可以替换维护不同环境文件夹结构的工作空间可以具有工作空间特定变量 .

    as Yevgeniy Brikman mentioned最好有一个模块结构 .

  • 61

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

    我一直非常依赖官方的Terraform examples和多次试错,以充实我不确定的领域 .

    .tfstate files

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

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

    Developer control

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

    • 共同AMI的基础,包括可重复使用的模块,例如木偶 .

    • DevOps使用Terraform提供的核心基础架构 .

    • 开发人员根据需要在Git中更改Terraform配置(实例数;新VPC;添加区域/可用区等) .

    • 推送Git配置并提交拉取请求以由DevOps小队成员检查 .

    • 如果获得批准,请调用webhook到CI进行构建和部署(此时不确定如何对多个环境进行分区)

    Edit 1 - Update on current state

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

    Layout

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

    Modules

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

    tree -L 1 . . ├── README.md ├── aws-asg ├── aws-ec2 ├── aws-elb ├── aws-rds ├── aws-sg ├── aws-vpc └── templates

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

    Glue

    我们有 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

    在客户端级别内,我们拥有AWS账户特定的 .tf 文件,用于配置全局资源(如IAM角色);接下来是EC2 SSH公钥的区域级别;最后在我们的环境中( devstgprod 等)是我们的VPC设置,实例创建和对等连接等 .

    旁注:正如你所看到的那样,我反对自己的建议,而不是将 terraform.tfstate 保留在git中 . 这是一个临时措施,直到我转移到S3但适合我,因为我目前是唯一的开发人员 .

    Next Steps

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

    Edit 2 - Changes

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

    State

    人们一再告诉我,国家不应该进入Git - 而且他们是正确的 . 我们将此作为一个临时措施,与一个依赖开发人员沟通和纪律的双人团队 . 通过更大的分布式团队,我们现在可以充分利用S3中的远程状态和DynamoDB提供的locking . 理想情况下,这将迁移到 Consul 现在是v1.0来削减跨 Cloud 提供商 .

    Modules

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

    File structure

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

    ├── main.tf ├── dev │ ├── main.tf │ ├── output.tf │ └── variables.tf └── prod ├── main.tf ├── output.tf └── variables.tf

    Planning

    再加上分布式团队的额外挑战,我们现在总是保存 terraform plan 命令的输出 . 我们可以检查和了解什么将运行,没有 planapply 阶段之间的一些变化的风险(虽然锁定有助于此) . 请记住删除此计划文件,因为它可能包含纯文本"secret"变量 .

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

  • 9

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

    文件布局

    我们强烈建议您将每个环境(例如stage,prod,qa)的Terraform代码存储在单独的模板集中(因此,单独的 .tfstate 文件) . 这很重要,这样您的单独环境实际上会在进行更改时彼此隔离 . 否则,虽然在分段中搞乱了一些代码,但是也很容易在prod中炸掉一些东西 . 有关原因的详细讨论,请参见Terraform, VPC, and why you want a tfstate file per env .

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

    stage
      └ main.tf
      └ vars.tf
      └ outputs.tf
    prod
      └ main.tf
      └ vars.tf
      └ outputs.tf
    global
      └ main.tf
      └ vars.tf
      └ outputs.tf
    

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

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

    • vars.tf :输入变量 .

    • outputs.tf :输出变量 .

    • main.tf :实际资源 .

    模块

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

    • infrastructure-modules :此文件夹包含小型,可重复使用的版本化模块 . 将每个模块视为如何创建单个基础架构(如VPC或数据库)的蓝图 .

    • infrastructure-live :此文件夹包含实际的实时运行基础架构,它是通过组合 infrastructure-modules 中的模块创建的 . 将此文件夹中的代码视为您根据蓝图构建的实际房屋 .

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

    infrastructure-modules
      └ vpc
        └ main.tf
        └ vars.tf
        └ outputs.tf
    

    然后我们可以在 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"
    }
    

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

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

    国家

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

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

    为了解决这个问题,我们创建了一个名为Terragrunt的开源工具,它是Terraform的一个瘦包装器,它使用Amazon DynamoDB提供锁定(大多数团队应该完全免费) . 查看Add Automatic Remote State Locking and Configuration to Terraform with Terragrunt了解更多信息 .

    进一步阅读

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

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

  • 55

    使用 remote config ,现在变得更加简单:

    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
    

    有关详细信息,请参阅docs .

  • 4

    由@Yevgeny Brikman更深入地介绍,但具体回答了OP的问题:

    What's the best practice for actually managing the terraform files and state?
    

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

    but do I commit tfstate as well?
    

    没有 .

    Should that reside somewhere like S3?
    

  • 0

    我知道这里有很多答案,但我的方法却截然不同 .

    ⁃   Modules
    ⁃   Environment management 
    ⁃   Separation of duties
    

    Modules

    • 为逻辑资源集合创建模块 . 示例:如果您的目标是部署API,这需要DB,HA VM,自动扩展,DNS,PubSub和对象存储,那么所有这些资源都应该在单个模块中进行模板化 .

    • 避免创建使用单个资源的模块 . 这可以而且已经完成,并且注册表中的许多模块都是这样做的,但这是一种有助于资源可访问性而不是基础架构编排的实践 . 示例:AWS EC2的模块通过使复杂配置更易于调用来帮助用户访问EC2,但是类似于1中的示例的模块在协调应用程序,组件或服务驱动的基础结构时协助用户 .

    • 避免工作区中的资源声明 . 这更多的是保持您的代码整洁有序 . 由于模块很容易进行版本控制,因此您可以更好地控制版本 .

    Environment management

    IaC使SDLC流程与基础架构管理相关,并且期望拥有开发基础架构和开发应用程序环境是不正常的 .

    • 不要使用文件夹来管理您的IaC环境 . 这导致了漂移,因为您的基础架构没有通用模板 .

    • 使用单个工作空间和变量来控制环境规范 . 示例:编写模块,以便在更改环境变量(var.stage很受欢迎)时,计划会更改以满足您的要求 . 通常情况下,环境应尽可能少地变化,数量,暴露和容量通常是可变配置 . Dev可能在私有拓扑中部署1个具有1个核心和1GB RAM的VM,但 生产环境 可能是具有2个核心的3个VM和具有额外公共拓扑的4GB RAM . 您当然可以有更多变化:dev可以在与应用程序相同的服务器上运行数据库进程以节省成本,但 生产环境 可能有一个专用的数据库实例 . 所有这些都可以通过改变单个变量,三元语句和插值来管理 .

    Separation of duties

    如果您在一个小型组织或运行个人基础设施,这不是真正适用,但它将帮助您管理您的运营 .

    • 按职责,责任或团队细分基础设施 . 示例:中央IT控制基础共享服务(虚拟网络,子网,公共IP地址,日志组,治理资源,多租户DB,共享密钥等),而API团队仅控制其服务所需的资源(VM,LB) ,PubSub等)并通过数据源和远程状态查找消耗中央IT服务 .

    • 管理团队访问权限 . 示例:中央IT可能具有管理员权限,但API团队只能访问一组受限制的公共 Cloud API .

    这也有助于释放问题,因为您会发现一些资源很少改变,而其他资源一直在变化 . 分离消除了风险和复杂性 .

    该策略与AWS的多账户策略相似 . 阅读更多信息 .

    CI/CD

    这是一个自己的主题,但Terraform在良好的管道中运作良好 . 这里最常见的错误是将CI视为银弹 . 技术上Terraform应该只是在装配管道阶段配置基础设施 . 这与CI阶段中发生的情况是分开的,其中人们通常验证和测试模板 .

    注:写在手机上,请原谅任何错误 .

相关问题