如何在单一的Terraform根目录中控制多个环境
首先
这篇文章是 terraform Advent Calendar 2022 的第19天。
如果你是一个使用Terraform的工程师,你应该曾经考虑过如何组织Terraform这一IaC工具的目录结构。我也在两年前的Advent Calendar上发表过这方面的文章(文章链接)。
关于在Terraform的目录结构中需要考虑的问题,可以提到”在存在多个环境(例如Production环境和Staging环境)的情况下,如何构建Root目录的结构”。
对此,有一些相关文章提到:
“应该避免使用Workspace功能”。
“最好通过目录来区分Production环境和Staging环境”。
“然而,吸收Production环境和Staging环境代码差异很麻烦,甚至经常会出错”。
如此等等。
然而,最终来看,你不觉得”不分目录,能够表示和执行环境差异是最好的”吗?我想这样做。
所以,我考虑着能不能以某种方式实现。
本文介绍了如何利用”-backend-config”和”-var-file”这两个选项,在单个Terraform根目录中控制多个环境的方法。
设备都正常运作。
请以以下内容为前提条件(如果上下文不同,请根据实际情况适当重新阐述或应用)。
-
- prd環境とstg環境の2環境を単一のTerraform Rootディレクトリで表現したい
Terragrunt は使わない
結果
尽管使用Terragrunt可能更方便,但尚未验证完成。
如果只使用原始的Terraform进行工作,目录结构如下所示:
(repository)
├─ root # 本文で ${TERRAFORM_ROOT} を指す
│ ├─ envs
│ │ ├─ prd.tfbackend # backendの設定として渡す値
│ │ ├─ prd.tfvars # variableとして渡す値
│ │ ├─ stg.tfbackend
│ │ └─ stg.tfvars
│ ├─ state.tf
│ ├─ variables.tf
│ ├─ ...
: :
在Terraform Init中,我们执行以下命令:
cd ${TERRAFORM_ROOT}
terraform init -backend-config=envs/${ENV}.tfbackend
在Terraform计划/应用过程中使用以下命令:
# applyの場合
cd ${TERRAFORM_ROOT}
terraform apply -var-file=envs/${ENV}.tfvars
请参考以下链接中的GitRepository获取示例代码。
(示例代码使用本地后端以确保可执行。在解释中,我们假定实际部署使用s3后端。)
hkak03key/advent-calendar-sample-code//terraform-2022-root-dir
解释
使用外部文件进行变量设置及其限制
如果您有使用Terraform的经验,您可能会有一种想要在运行时从外部注入变量的感觉。这可以通过适当定义变量并使用 terraform apply -var-file=${FILE_PATH} 来实现。
我想你可能意识到了在这种情况下,如果能够注入外部变量,那么也想对后端进行变量控制。
然后,我们会写出如下的代码:
terraform {
backend "s3" {
bucket = "${var.account_name}-${var.env}-terraform-backend"
key = "terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "${var.account_name}-${var.env}-terraform-backend"
}
}
此时的Terraform Init执行结果如下:
$ terraform init
Initializing the backend...
╷
│ Error: Variables not allowed
│
│ on state.tf line 3, in terraform:
│ 3: bucket = "${var.account_name}-${var.env}-terraform-backend"
│
│ Variables may not be used here.
...
我认为这是一个必然发生的情况,直到达到“嘿——真的吗——”的地步。
这是事实,后端设置无法使用变量,这是一个悲伤的现实。然后,我们开始遵循“将生产环境和暂存环境区分为不同的目录”这样的技巧(我所涉及的大部分环境也是如此)。
通过使用-backend-config选项,可以利用外部文件对后端进行变量设置。
然而,将生产环境和暂存环境分开设置目录,说实话并不是很开心。
而且,在阅读文档时发现了一个名为-backend-config的选项。
通过使用它,可以从外部提供后端配置。
以下是利用方法的示例:
state.tf 的定义
首先,只需在 ${TERRAFORM_ROOT}/state.tf 中写明要使用的后端。
请注意不要写入后端参数。
terraform {
backend "s3" {
# 本section内に記述する設定は .tfbackend ファイルに記載
# initは以下のコマンドで実行する必要がある:
# `terraform init -backend-config={{.tfbackend ファイルパス}}`
}
}
${ENV}的tfbackend定义
接下来,我们将在${TERRAFORM_ROOT}/envs/${ENV}.tfbackend文件中,以hcl格式编写后端参数。
在这个例子中,我们假设为prd环境。
bucket = "some-product-prd-terraform-backend"
key = "terraform.tfstate"
region = "ap-northeast-1"
dynamodb_table = "some-product-prd-terraform-backend"
执行terraform init
最后,执行命令terraform init -backend-config=envs/${ENV}.tfbackend。
cd ${TERRAFORM_ROOT}
terraform init -backend-config=envs/prd.tfbackend
只要命令完成了,就表示成功了。
─
请将以下内容以中文母语改写,只需一个选项:
如果想要设置stg环境的后端,请准备好${TERRAFORM_ROOT}/envs/stg.tfbackend并执行。请注意,如果已经在不同的环境中执行了terraform init,则需要使用-reconfigure选项。
cd ${TERRAFORM_ROOT}
# 既に terraform init した環境と異なる環境について terraform init する場合は -reconfigure optionを与える
terraform init -backend-config=envs/stg.tfbackend -reconfigure
总结
在单个Terraform根目录中,我们展示了可以进行多个环境的terraform init。同时,通过在terraform init时使用-backend-config选项,在terraform apply时使用-var-file选项,可以在单个Terraform根目录中实现多个环境的部署。
一方面,也存在着一些问题。
-
- 設定ファイルが .tfbackend .tfvars の2種類がどうしても必要
どうしようもないけどダサい
Route53のような、 「保持する環境すべての中で唯一であるべきリソース」 を管理する場合は、単一のTerraform Rootディレクトリではかえって都合が悪い
こういうものについてはディレクトリを分けて対応するべき
其实,像 Terragrunt 这样的工具已经出现了(在 Advent Calender 中也被介绍过:通过引入 Terragrunt 来使 Terraform 代码更加干净),虽然还没有完全验证,但可能会给我们带来很好的体验,所以可能会有一种感觉是“用原生 Terraform 努力到这个程度真的值得吗?”或许可以说是“当然是值得的”。
然而,我认为在决定 Terraform 的目录结构时,即使把“用原生 Terraform 努力到这个程度会是这样子”的想法放在心里,也是可以的,希望对决定 Terraform 的目录结构提供一些线索。
请用中文翻译以下内容,只需给出一种选项:
──
我们的Terraform目录结构之旅仍在继续。
广告
这是其中一个选项: YouTube已经发布。
我在特别火热的Snowflake日本用户群YouTube频道上做了一个DevOps回的嘉宾出演。
因为谈到了DevOps,所以也在讨论Terraform,非常推荐您观看!请查看以下链接:
我们接受有关工作咨询的询问。
由于我是个人事业主,所以我兼职提供Terraform技术支持和数据分析服务。如果有其他需求,请随时与我沟通!