Terraform环境 - 如何让它变干

时间:2018-03-20 16:02:55

标签: amazon-web-services devops terraform

我们正在大量使用Terraform进行AWS Cloud配置。我们的基础terraform结构如下所示:

├─ modules
├── x
├── y
├─ environments
├── dev
│   ├── main.tf
│   ├── output.tf
│   └── variables.tf
└── uat
│   ├── main.tf
│   ├── output.tf
│   └── variables.tf
└── prod
    ├── main.tf
    ├── output.tf
    └── variables.tf

当我们达到了许多模块和许多环境时,代码重复现在变得更加严重,我们希望尽可能多地摆脱它。

我们目前主要关注的是output.tf文件 - 每次我们扩展现有模块或添加新模块时,我们都需要为它设置特定于环境的配置(这是预期的),但我们仍然必须将所需部分复制/粘贴到output.tf以输出配置结果(如IP地址,AWS ARN等)。

有没有办法摆脱重复的output.tf文件?我们可以在模块本身中定义所需的输出,并在我们为特定环境运行terraform时查看所有已定义的输出吗?

3 个答案:

答案 0 :(得分:2)

解决此问题的一种方法是创建base环境,然后对公共元素进行符号链接,例如:

├─ modules
├── x
├── y
├─ environments
├── base
│   ├── output.tf
│   └── variables.tf
├── dev
│   ├── main.tf
│   ├── output.tf -> ../base/output.tf
│   └── variables.tf -> ../base/variables.tf
├── uat
│   ├── main.tf
│   ├── output.tf -> ../base/output.tf
│   └── variables.tf -> ../base/variables.tf
├── super_custom
│   ├── main.tf
│   ├── output.tf # not symlinked
│   └── variables.tf # not symlinked
└── prod
    ├── main.tf
    ├── output.tf -> ../base/output.tf
    └── variables.tf -> ../base/variables.tf

只有当output.tfvariables.tf文件对于每个环境都相同时,这种方法才有效,虽然您可以使用非符号链接的变体(例如上面的super_custom),但这可以变得混乱,因为它不是立即明显哪些环境是自定义的,哪些不是。因人而异。我尝试将环境之间的更改限制为每个环境.tfvars文件。

值得一读Charity Major's excellent post on tfstate files,这让我走上了这条道路。

答案 1 :(得分:2)

我们构建并开源Terragrunt来解决这个问题。 Terragrunt的一项功能是能够下载远程Terraform配置。我们的想法是,您只需在一个仓库中为您的基础架构定义一次Terraform代码,例如,modules

└── modules
 ├── app
 │   └── main.tf
 ├── mysql
 │   └── main.tf
 └── vpc
     └── main.tf

此repo包含典型的Terraform代码,但有一点不同:代码中应该在环境之间存在差异的任何内容都应作为输入变量公开。例如,app模块可能会公开以下变量:

variable "instance_count" {
  description = "How many servers to run"
}

variable "instance_type" {
  description = "What kind of servers to run (e.g. t2.large)"
}

在一个名为live的单独仓库中,您可以为所有环境定义代码,现在每个组件只包含一个.tfvars文件(例如app/terraform.tfvars,{{1等等)。这为您提供了以下文件布局:

mysql/terraform.tfvars

请注意,任何文件夹中都没有Terraform配置(└── live ├── prod │ ├── app │ │ └── terraform.tfvars │ ├── mysql │ │ └── terraform.tfvars │ └── vpc │ └── terraform.tfvars ├── qa │ ├── app │ │ └── terraform.tfvars │ ├── mysql │ │ └── terraform.tfvars │ └── vpc │ └── terraform.tfvars └── stage ├── app │ └── terraform.tfvars ├── mysql │ └── terraform.tfvars └── vpc └── terraform.tfvars 文件)。相反,每个.tf文件指定一个.tfvars块,指定从何处下载Terraform代码,以及该Terraform代码中输入变量的特定于环境的值。例如,terraform { ... }可能如下所示:

stage/app/terraform.tfvars

terragrunt = { terraform { source = "git::git@github.com:foo/modules.git//app?ref=v0.0.3" } } instance_count = 3 instance_type = "t2.micro" 可能如下所示:

prod/app/terraform.tfvars

有关详细信息,请参阅Terragrunt documentation

答案 2 :(得分:1)

如果您的devuatprod环境具有相同的形状但属性不同,您可以利用workspaces分隔您的环境状态,以及单独的{{ 1}}文件来指定不同的配置。

这可能看起来像:

*.tfvars

您可以使用以下命令创建新工作区:

├─ modules
│   ├── x
│   └── y
├── dev.tfvars
├── prod.tfvars
├── uat.tfvars
├── main.tf
├── outputs.tf
└── variables.tf

然后部署更改:

terraform workspace new uat

工作区功能可确保分别管理不同的环境状态,这是一个奖励。

这种方法仅在环境之间的差异足够小以便在单个模块中封装逻辑时才有效(例如,具有terraform workspace select uat terraform apply --var-file=uat.tfvars 标志,为{添加一些额外的冗余基础结构{1}}和high_availability)。