如何在单一的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技术支持和数据分析服务。如果有其他需求,请随时与我沟通!

 

广告
将在 10 秒后关闭
bannerAds