首页 文章

Terraform:多租户的州管理

提问于
浏览
7

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

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

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

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

2 回答

  • 7

    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
    

    在这里你从root级别运行你的计划/ 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 文件中,并且在更改之前更容易测试更改,因为每个文件夹与另一个文件夹几乎相同 .

  • 2

    您建议的方法听起来对我来说,但您可能会考虑做更多的事情 .

    将原始Terraform模板(下面的树中的 _template )保留为版本化工件(例如git repo),并传递键值属性以便能够重新创建基础结构 . 这样,您将在目录中放置非常少量的复制粘贴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
    ...
    

    需要两个帮助脚本:

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

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

相关问题