2017-04-04 45 views
5

正如我们在评估Terraform更换(部分)我们Ansible配置过程中的多租户SaaS的进步,我们意识到Terraform的便利性,性能和可靠性,我们可以处理基础设施的变化(增加/删除)顺利,跟踪基础设施状态(非常酷)。Terraform:状态管理多租户

我们的应用程序是一个多租户SaaS的,我们提供单独的实例为我们的客户 - 在Ansible我们有自己的动态库存(不太一样EC2动态库存)。我们翻阅大量的书籍Terraform /教程和最佳实践,其中许多建议多环境状态,应在Terraform分别&远程管理,但所有的人都像静态ENV(如开发/分期/生产)。

是否有任何的最佳做法或管理状态的动态库存多租户应用程序的实际例子吗?我们希望跟踪每个客户实例集的状态 - 轻松地为其添加更改。

一种方法可能是我们创建内部每个客户和地区* .tf脚本,它将调用托管某处全球我们的模块的目录。状态文件可能被放到S3中,这样我们可以根据需要为每个单独的客户填充更改。

回答

2

你的建议的方法听起来我的权利,但也有少数,你可以考虑做更多的事情。

保留原始Terraform模板(在下面的树_template)作为版本神器(混帐回购协议,为EG),只是通过键值性能能够重新创建你的基础设施。通过这种方式,您将拥有非常少量的复制粘贴的Terraform配置代码,并将其放置在目录中。

这是它的外观:需要

/tf-infra 
├── _global 
│   └── global 
│    ├── README.md 
│    ├── main.tf 
│    ├── outputs.tf 
│    ├── terraform.tfvars 
│    └── variables.tf 
└── staging 
    └── eu-west-1 
     ├── saas 
     │   ├── _template 
     │   │   └── dynamic.tf.tpl 
     │   ├── customer1 
     │   │   ├── auto-generated.tf 
     │   │   └── terraform.tfvars 
     │   ├── customer2 
     │   │   ├── auto-generated.tf 
     │   │   └── terraform.tfvars 
... 

两个辅助脚本:

  1. 模板渲染。二者必选其一sed产生module's source attribute或使用更强大的工具(如例如它airbnb/streamalert完成)

  2. 包装脚本。运行terraform -var-file=...通常就足够了。

共用terraform状态文件作为这应该是很好的全球资源(目录以上_global)可以存储在S3,使其它层可以访问它们。

PS:我很开放的建议方案的意见,因为这是一个有趣的任务,以对工作:)

5

Terraform工作在一个文件夹级别,在所有.tf文件拉动(和默认为terraform.tfvars文件)。

所以我们做了类似于Antonanswer的东西,但是放弃了使用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 

在这里,你运行你的计划/应用/从根级破坏,其中包装shell脚本处理类似cd'ing进入该目录并运行terraform get -update=true的东西,但也为该文件夹运行terraform init,以便为S3获取唯一的状态文件密钥,使您可以独立跟踪每个文件夹的状态。

上面的解决方案具有通用模块,它们打包资源以提供通用接口(例如,我们的EC2实例根据某些输入变量以特定方式进行标记,并且还给出了私有Route53记录),然后执行组件”。

这些组件包含一组模块/资源,这些模块/资源将由Terraform在同一文件夹中应用。因此,我们可以将一个ELB,一些应用程序服务器和一个数据库放在application.tf下,然后将它们链接到一个位置,这样我们就可以使用Terraform来控制一个位置。如果我们可能在某个位置的资源上存在某些差异,那么它们将被分离出来。在上例中,您可以看到staging/globalglobal_component2.tf不存在于生产中。这可能仅适用于非生产环境,例如某些网络控制,以防止互联网访问环境。

这里真正的好处是,所有东西都可以直接在开发人员的源代码控制中直接查看,而不需要使用生成所需Terraform代码的模板步骤。

它还有助于遵循DRY,其中环境之间的唯一真正区别在于位置中的terraform.tfvars文件,并且使它们在生效之前更容易测试,因为每个文件夹几乎与其他文件夹相同。

+0

使用这种方法,您将在每个文件夹内或从根目录运行terraform?我问,因为根据这个,状态文件可能存储在根路径或每个文件夹中。 –

+0

您无法从父文件夹运行Terraform。 Terraform仅适用于当前目录中的内容。正如它发生的那样,我们有一些帮助程序脚本,它们位于repo的根目录,cd'到我们想要执行的位置,然后从那里运行'terraform' CLI命令。 – ydaetskcoR

+0

是的,你可以,我一直这么做......'terraform plan path/to/something' –