Terraform:多租户的州管理

Arc*_*eno 7 amazon-ec2 amazon-web-services terraform

由于我们正在评估Terraform以替换(部分)我们的多租户SaaS的Ansible供应流程,我们意识到Terraform的便利性,性能和可靠性,因为我们可以顺利地处理基础设施变更(添加/删除),保持跟踪红外状态(非常酷).

我们的应用程序是多租户SaaS,我们为客户提供单独的实例 - 在Ansible,我们拥有自己的动态库存(与EC2动态库存完全相同).我们经历了很多Terraform书籍/教程和最佳实践,其中很多人建议多环境状态应该在Terraform中单独和远程管理,但所有这些状态看起来都像静态环境(如Dev/Staging/Prod).

是否存在管理多租户应用程序的状态动态库存的最佳实践或实际示例?我们希望跟踪每个客户实例集的状态 - 轻松填充对它们的更改.

一种方法可能是我们为每个客户创建一个目录,并在其中放置*.tf脚本,这将调用托管在全球某个地方的模块.状态文件可能会被放到S3,这样我们就可以根据需要为每个客户填充更改.

yda*_*coR 8

Terraform在文件夹级别上工作,拉入所有.tf文件(默认情况下为terraform.tfvars文件).

所以我们做了一些类似于Anton回答,但是在使用sed模仿事物时要做一些复杂的事情.因此,作为一个基本示例,您的结构可能如下所示:

$ tree -a --dirsfirst
.
??? components
?   ??? application.tf
?   ??? common.tf
?   ??? global_component1.tf
?   ??? global_component2.tf
??? modules
?   ??? module1
?   ??? module2
?   ??? module3
??? production
?   ??? customer1
?   ?   ??? application.tf -> ../../components/application.tf
?   ?   ??? common.tf -> ../../components/common.tf
?   ?   ??? terraform.tfvars
?   ??? customer2
?   ?   ??? application.tf -> ../../components/application.tf
?   ?   ??? common.tf -> ../../components/common.tf
?   ?   ??? terraform.tfvars
?   ??? global
?       ??? common.tf -> ../../components/common.tf
?       ??? global_component1.tf -> ../../components/global_component1.tf
?       ??? global_component2.tf -> ../../components/global_component2.tf
?       ??? terraform.tfvars
??? staging
?   ??? customer1
?   ?   ??? application.tf -> ../../components/application.tf
?   ?   ??? common.tf -> ../../components/common.tf
?   ?   ??? terraform.tfvars
?   ??? customer2
?   ?   ??? application.tf -> ../../components/application.tf
?   ?   ??? common.tf -> ../../components/common.tf
?   ?   ??? terraform.tfvars
?   ??? global
?       ??? common.tf -> ../../components/common.tf
?       ??? global_component1.tf -> ../../components/global_component1.tf
?       ??? terraform.tfvars
??? apply.sh
??? destroy.sh
??? plan.sh
??? remote.sh
Run Code Online (Sandbox Code Playgroud)

在这里,您可以从根级别运行您的计划/ apply/destroy,其中包装程序shell脚本处理诸如进入目录并运行terraform get -update=true但还运行terraform init该文件夹之类的内容,以便您获得S3的唯一状态文件密钥,允许您跟踪独立的每个文件夹的状态.

上面的解决方案具有通用模块,它们包装资源以提供事物的通用接口(例如,我们的EC2实例根据某些输入变量以特定方式标记,并且还提供了专用的Route53记录),然后是"已实现的组件".

这些组件包含一组模块/资源,这些模块/资源将由Terraform在同一文件夹中应用.所以我们可能会把一个ELB,一些应用程序服务器和一个数据库application.tf放在一个位置然后进行符号链接到一个位置给我们一个地方来控制Terraform.如果我们可能在某个地点的资源方面存在一些差异,那么它们就会被分开.在上面的例子中,你可以看到staging/global有一个global_component2.tf未在生产中出现.这可能只适用于非生产环境,例如某些网络控制,以防止Internet访问环境.

这里的真正好处是,所有内容都可以直接在开发人员的源代码控制中轻松查看,而不是具有生成所需Terraform代码的模板步骤.

它还有助于关注DRY,其中环境之间的唯一真正差异在于位置中的terraform.tfvars文件,并且在更改之前更容易测试更改,因为每个文件夹与另一个文件夹几乎相同.


Ant*_*nko 2

您建议的方法对我来说听起来不错,但您还可以考虑做一些其他事情。

\n\n

保留原始 Terraform 模板(_template在下面的树中)作为版本化工件(例如 git 存储库),并仅传递键值属性以便能够重新创建您的基础设施。这样,您将在目录中放置非常少量的复制粘贴 Terraform 配置代码。

\n\n

它看起来是这样的:

\n\n
/tf-infra\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 _global\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 global\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README.md\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 main.tf\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 outputs.tf\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 terraform.tfvars\n\xe2\x94\x82\xc2\xa0\xc2\xa0     \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 variables.tf\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 staging\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 eu-west-1\n        \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 saas\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 _template\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 dynamic.tf.tpl\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 customer1\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 auto-generated.tf\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 terraform.tfvars\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 customer2\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 auto-generated.tf\n        \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 terraform.tfvars\n...\n
Run Code Online (Sandbox Code Playgroud)\n\n

需要两个辅助脚本:

\n\n
    \n
  1. 模板渲染。使用sed生成模块的源属性或使用更强大的工具(例如,它是在 airbnb/streamalert中完成的)中完成的)

  2. \n
  3. 包装脚本。跑步terraform -var-file=...通常

  4. \n
\n\n

共享的 terraform 状态文件以及应该是全局的资源(目录_global上面的目录)可以存储在 S3 上,以便其他层可以访问它们。

\n\n

PS:我非常愿意对提议的解决方案发表评论,因为这是一项有趣的任务:)

\n