如何仅基于Terraform环境加载某些文件?

时间:2018-02-05 12:31:41

标签: terraform terraform-template-file

要运行我的terraform脚本,我会terraform apply -var 'ENV=dev' -var-file="dev.tfvars"

dev.tfvars内,我想加载其他只有dev环境变量的文件。

我应该能够对staging.tfvars等做同样的事情。

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

在我看来,你有两个选择:

  • 使用TF工作区,可以在环境中设置较小的差异。如docs中所述,您需要更改资源以使用插值序列terraform.workspace。我觉得这很难维护。
  • 创建TF包装器

包装器将接收环境并且TF命令将链接依赖于环境的.tf文件并调用terraform加载.tfvars文件。例如,您可以在此文件中包含env/目录:

env/
 | dev.tf
 | staging.tf
 | prod.tf

您的包装器将在项目根目录中链接正确的文件,如下所示:

env.tf -> env/dev.tf

然后它将调用terraform $2 -var-file="$1.tfvars" -var 'ENV=$1'

这样,terraform会读取env.tf文件内容并将其加载到您的其他.tf文件中。

答案 1 :(得分:1)

而不是这种方法,我改为重写Terraform代码库的结构,因此dev / staging / prod环境等都在不同的目录中,并且只有每个目录中的terraform.tfvars文件不同。

在我看来,最好的方法就是大量使用模块和符号链接。我在my answer中讨论了有关Terraform多租户的相关问题。

示例布局可能如下所示:

$ tree -a
.
├── dev
│   ├── eu-west-1
│   │   ├── bar
│   │   │   ├── bar.tf -> ../../../stacks/bar.tf
│   │   │   ├── eu-west-1.tf -> ../../../providers/aws/eu-west-1.tf
│   │   │   └── terraform.tfvars
│   │   └── foo
│   │       ├── eu-west-1.tf -> ../../../providers/aws/eu-west-1.tf
│   │       ├── foo.tf -> ../../../stacks/foo.tf
│   │       └── terraform.tfvars
│   ├── global
│   │   └── baz
│   │       ├── baz.tf -> ../../../stacks/baz.tf
│   │       └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
│   └── us-east-1
│       ├── bar
│       │   ├── bar.tf -> ../../../stacks/bar.tf
│       │   ├── terraform.tfvars
│       │   └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
│       └── foo
│           ├── foo.tf -> ../../../stacks/foo.tf
│           ├── terraform.tfvars
│           └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
├── modules
│   ├── bar
│   │   └── main.tf
│   └── foo
│       ├── main.tf
│       ├── outputs.tf
│       └── vars.tf
├── production
│   ├── eu-west-1
│   │   ├── bar
│   │   │   ├── bar.tf -> ../../../stacks/bar.tf
│   │   │   ├── eu-west-1.tf -> ../../../providers/aws/eu-west-1.tf
│   │   │   └── terraform.tfvars
│   │   └── foo
│   │       ├── eu-west-1.tf -> ../../../providers/aws/eu-west-1.tf
│   │       ├── foo.tf -> ../../../stacks/foo.tf
│   │       └── terraform.tfvars
│   ├── global
│   │   └── baz
│   │       ├── baz.tf -> ../../../stacks/baz.tf
│   │       └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
│   └── us-east-1
│       ├── bar
│       │   ├── bar.tf -> ../../../stacks/bar.tf
│       │   ├── terraform.tfvars
│       │   └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
│       └── foo
│           ├── foo.tf -> ../../../stacks/foo.tf
│           ├── terraform.tfvars
│           └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
├── providers
│   └── aws
│       ├── eu-west-1.tf
│       └── us-east-1.tf
├── stacks
│   ├── bar.tf
│   ├── baz.tf
│   └── foo.tf
└── staging
    ├── eu-west-1
    │   ├── bar
    │   │   ├── bar.tf -> ../../../stacks/bar.tf
    │   │   ├── eu-west-1.tf -> ../../../providers/aws/eu-west-1.tf
    │   │   └── terraform.tfvars
    │   └── foo
    │       ├── eu-west-1.tf -> ../../../providers/aws/eu-west-1.tf
    │       ├── foo.tf -> ../../../stacks/foo.tf
    │       └── terraform.tfvars
    ├── global
    │   └── baz
    │       ├── baz.tf -> ../../../stacks/baz.tf
    │       └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
    └── us-east-1
        ├── bar
        │   ├── bar.tf -> ../../../stacks/bar.tf
        │   ├── terraform.tfvars
        │   └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf
        └── foo
            ├── foo.tf -> ../../../stacks/foo.tf
            ├── terraform.tfvars
            └── us-east-1.tf -> ../../../providers/aws/us-east-1.tf

这使您可以在一个地方(stacks目录)定义Terraform代码的确切配置,并且只允许覆盖每个目录的terraform.tfvars文件。在上面的布局中,我们有一个foo和一个bar模块,我们希望在所有dev / staging / production中的2个不同的AWS区域中应用,还有一些应该全局应用的不可配置的Terraform代码。每个环境级别(想想像IAM角色等)。

我们在modules文件夹下定义我们的模块(foo可能是一个完整的模块,而bar可能是来自第三方位置的来源模块,例如另一个Git仓库或Terraform's module registry )。然后,我们为stacks文件夹中的模块提供了一个瘦包装器,可能如下所示:

variable "name" {}

variable "count" {
  default = 2
}

module "foo" {
  source = "../../../foo"
  name   = "${var.name}"
  count  = "${var.count}"
}

然后在每个${environment}/${region}/foo/terraform.tfvars中我们总是定义一个名称(因为它是必需的)并且可选地定义一个计数(默认):

name  = dev-foo
count = 1

name = production-foo

上面的布局也让您可以一目了然地看到所有环境和配置,并且可以简化您使用Terraform设置状态配置的任何包装脚本,只需使用目录路径即可。