在 Terraform 0.12 中,或许不需要使用 lookup
我是Terraform的新手,ARM模板真的很难受啊…
标题可能已经有了,但我不知道该如何切入……
太长不看
从Terraform 0.12开始,”${lookup(var.hoge, “terraform.workspace”).fuga}”可以使用var.hoge[terraform.workspace].fuga的形式。
然而,由于Terraform 0.12的语法扩展,此功能在0.11.14及之前的版本无法使用。
截至2019年6月25日,VSCode的Terraform扩展尚不支持0.12版本,因此会导致错误。这有点令人不爽。
请参阅
0.12.0 版发布说明
- https://github.com/hashicorp/terraform/releases/tag/v0.12.0
思考的触发
-
- https://kenzo0107.hatenablog.com/entry/2019/04/17/103558
- https://speakerdeck.com/shogomuranushi/infrastructure-as-code-is-very-tired?slide=26
背景 – (Background)
我想要编写一个tf文件,然后在两个以上的环境中进行部署,但由于s3存储桶等名称不能重复,因此我希望能够很好地定义它们。
当遇到这种情况时,我希望能根据不同的环境定义变量,因此开始学习一般的做法并进行了调查。
我大致找到了这三个左右。
-
- 在工作空间中,不使用模块化(将tf文件按环境分开,并根据需要使用模块)
-
- 工作空间 + 变量(通过Map的键进行分离)
- 变量(通过var文件进行分离)
我经常看到模块化的概念,但感觉有点过度了。我没有尝试太多。
(因为在使用Ansible时,有9成的相同之处,但无法同时涵盖1成的微小差异,所以需要重新书写。可能只是我没有那么强的感知力。)
我看到了一个使用变量查找(var.hoge, “${terraform.workspace}.fuga”)的代码。虽然我认为它与我想要做的事情接近,但有点不太优雅,但实际上,我不明白为什么它采取了这种形式。如果用嵌套Map来写,而不是将其写为一个键”dev.fuga”,不仅外观更整洁,也更容易理解。
愚人会从经验中学习,因此在0.11版本中尝试了许多东西。
我认为这是因为嵌套的Map引用有点麻烦的原因。
以下的代码也会报错,例如var.hoge[“dev”][“fuga”]。如果lookup变量返回的是一个Map类型,也会报错。请看下面的代码。
variable "env" {
default = {
dev = {
service_name = "dev-foo"
s3_name = "dev-foo-s3"
cidrs = "10.0.0.0/24,10.0.1.0/24"
}
prod = {
service_name = "prod-foo-service"
s3_name = "prod-foo-s3"
cidrs = "10.111.0.0/24,10.111.1.0/24"
}
}
}
# これはダメだが、0.12からは有効。
# output "output_service_name1" {
# value = "${var.env[terraform.workspace].service_name}"
# }
# これもダメ。
# output "output_service_name2" {
# value = "${var.env[terraform.workspace]["service_name"]}"
# }
# これもダメ。lookupでmapが返ってくるから。
#output "output_service_name3" {
# value = "${lookup(lookup(var.env, terraform.workspace), "service_name")}"
#}
# これは出来るが2重まで。3重になるとダメ。
output "output_service_name4" {
value = "${lookup(var.env[terraform.workspace], "service_name")}"
}
# 少しはマシだが、localsを毎回定義したくない
locals {
env = "${var.env[terraform.workspace]}"
service_name = "${local.env["service_name"]}"
}
output "output_service_name5" {
value = "${local.service_name}"
}
所以我想着把它命名为 “dev.fuga”,并且对其进行了一键查找的优化,这样就可以立即获取。换句话说,我并没有理解清楚。
如果我们回到嵌套的Map方式,从0.12版本开始是否有一些改进的方法呢?我尝试了一下,发现可以使用var.hoge[terraform.workspace]fuga这种形式。虽然我不确定这种写法有多常见,因为很难在搜索引擎上找到相关信息,可能是因为0.12版本还比较新吧?
确认过的代码
这次我们正在使用workspace,但它并不是必需的。我认为terraform.workspace可以随意替换为一个变量或局部变量。
variable "env" {
default = {
dev = {
service_name = "dev-foo"
s3_name = "dev-foo-s3"
cidrs = "10.0.0.0/24,10.0.1.0/24"
}
prod = {
service_name = "prod-foo-service"
s3_name = "prod-foo-s3"
cidrs = "10.111.0.0/24,10.111.1.0/24"
}
}
}
output "output_service_name" {
value = "${var.env[terraform.workspace].service_name}"
}
output "output_s3_name" {
value = "${var.env[terraform.workspace].s3_name}"
}
output "output_cidrs" {
value = "${split(",", var.env[terraform.workspace].cidrs)}"
}
output "output_cidrs_lookup" {
value = "${split(",", lookup(var.env, "${terraform.workspace}").cidrs)}"
}
顺便提一句,从0.12版本开始,”${var.env[terraform.workspace].service_name}” 的语法也可以写成 var.env[terraform.workspace].service_name 来实现相同的功能,但是由于编辑器不支持,所以并未采用该方式。
以下是执行结果
创建一个名为workspace dev的工作空间,切换到该空间并应用。
$ terraform workspace new dev
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
output_cidrs = [
"10.0.0.0/24",
"10.0.1.0/24",
]
output_cidrs_lookup = [
"10.0.0.0/24",
"10.0.1.0/24",
]
output_s3_name = dev-foo-s3
output_service_name = dev-foo
创建并切换到生产环境,并应用更改。
$ terraform workspace new prod
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
output_cidrs = [
"10.111.0.0/24",
"10.111.1.0/24",
]
output_cidrs_lookup = [
"10.111.0.0/24",
"10.111.1.0/24",
]
output_s3_name = prod-foo-s3
output_service_name = prod-foo-service
顺便说一下,var-file。
如果只是这种程度的用途,使用var-file可能不会有太大问题。在0.11.14版本也能正常运行。
是否需要考虑的是tfstate呢?但这个也可以通过运行参数进行更改,所以将其脚本化可能就没有问题了。
variable "service_name" { }
variable "s3_name" { }
variable "cidrs" {}
output "output_service_name" {
value = "${var.service_name}"
}
output "output_s3_name" {
value = "${var.s3_name}"
}
output "output_cidrs" {
value = "${split(",", var.cidrs)}"
}
service_name = "dev-foo"
s3_name = "dev-foo-s3"
cidrs = "10.0.0.0/24,10.0.1.0/24"
service_name = "prod-foo-service"
s3_name = "prod-foo-s3"
cidrs = "10.111.0.0/24,10.111.1.0/24"
执行示例 lì)
$ terraform apply -var-file dev.tfvars
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
output_cidrs = [
"10.0.0.0/24",
"10.0.1.0/24",
]
output_s3_name = dev-foo-s3
output_service_name = dev-foo
$ terraform apply -var-file prod.tfvars
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
output_cidrs = [
"10.111.0.0/24",
"10.111.1.0/24",
]
output_s3_name = prod-foo-s3
output_service_name = prod-foo-service
到最后还是不知道哪个是最好的。如果规模变得更大,可能会有不同的情况。
还有其他更需要花时间的任务吗?