terraformの記述の仕方を調べるための個人的なメモ。resourceを定義しないterraformの設定が書けるようになってからterraformに関する苦手意識が消えた。
teraformはIaCのためのものというのはわかっているものの、terraform自体に不慣れな段階の間はただただ試しに書いてみては実行しまくりたい。そのようなときにいちいち実際のprovisioningが走るのを待つというのは耐えられない。
one file terraform
variablesを引数として、outputsを戻り値として、terraform moduleを関数として見るというようなことがドキュメントに書かれている。
同じ理屈で、CLIのエントリーポイントはmain関数。これがmain.tfに当たると解釈してあげれば良い。そんなわけでterraformでの記述の仕方を色々試すときに小さなmain.tfを気軽に作れる様になって置けると良い。以下の様なmain.tfを書いてみる。
main.tf
variable "aws_region" {
default = "us-west-1a"
}
locals {
person = {
name = "foo"
age = 20
}
}
output "json_result" {
value = jsonencode(local.person)
}
output "greeting" {
value = "hello ${local.person.name} from ${var.aws_region}"
}
実行結果
$ terraform apply -auto-approve
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
greeting = "hello foo from us-west-1a"
json_result = "{\"age\":20,\"name\":\"foo\"}"
variableとして定義しておけば terraform apply -var <> で渡す引数を変えられる。xxxに変わった。
$ terraform apply -auto-approve -var='aws_region="xxx"'
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
greeting = "hello foo from xxx"
json_result = "{\"age\":20,\"name\":\"foo\"}"
こんな感じに手元で気軽に試せる環境を作っておいて試しまくるのが一番良い。
HCLの構文
terraformで使われる設定ファイルの記述言語はHCL (正確に言えばHCL2) 。これの仕様は以下にある。
- https://github.com/hashicorp/hcl/blob/main/hclsyntax/spec.md
- https://github.com/hashicorp/hcl/blob/main/spec.md
terraformのドキュメントにあるsyntaxの説明は大して役に立たない1。
利用できる組み込みの関数
利用できる組み込みの関数について知りたいときにドキュメントを見るべきなのかもしれないが一覧性が悪い。
雑に言うとgrepしたりなどが出来ない。直接コードを読んだ方が早い。
- https://github.com/hashicorp/terraform/blob/main/lang/functions.go
- https://github.com/zclconf/go-cty/tree/main/cty/function/stdlib
HCL2はgo-ctyがベースになっている(裏側で使われている)。実際どこかのタイミングでHCLを設定ファイルとして利用して読み込む例を作ってみたい2。
moduleの利用
moduleも同様にちょっとしたファイル群を作ってあげて試行錯誤していけば良い。以下の説明もresourceの利用が前提になっていてだるい。
はじめは以下の様なmain.tfを作ってみる。null_resourceとloca-execでコマンドの実行もできるのでそれくらいから始めると良い。
main.tf
locals {
x = 10
y = 20
z = 30
}
resource "null_resource" "echo" {
triggers = {
x = local.x
y = local.y
z = local.z
}
provisioner "local-exec" {
command = <<EOS
echo x=${local.x} y=${local.y} z=${local.z}
EOS
}
}
実行結果
terraform apply -auto-approve
null_resource.echo: Creating...
null_resource.echo: Provisioning with 'local-exec'...
null_resource.echo (local-exec): Executing: ["/bin/sh" "-c" "echo x=10 y=20 z=30\n"]
null_resource.echo (local-exec): x=10 y=20 z=30
null_resource.echo: Creation complete after 0s [id=2240813459510242007]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
terraform show
# null_resource.echo:
resource "null_resource" "echo" {
id = "2240813459510242007"
triggers = {
"x" = "10"
"y" = "20"
"z" = "30"
}
}
これをmoduleに分ける。
$ tree
.
├── main.tf
└── modules
└── xyz
├── main.tf
└── variables.tf
2 directories, 3 files
main.tf
module "echo1" {
source = "./modules/xyz"
primary_configuration = {
x = 10
y = 20
z = 30
}
}
module "echo2" {
source = "./modules/xyz"
primary_configuration = {
x = 10
y = 20
z = 30
}
}
modules/xyz/variables.tf
variable "primary_configuration" {
type = object({
x = number
y = number
z = number
})
}
modules/xyz/main.tf
resource "null_resource" "echo" {
triggers = {
x = var.primary_configuration.x
y = var.primary_configuration.y
z = var.primary_configuration.z
}
provisioner "local-exec" {
command = <<EOS
echo x=${var.primary_configuration.x} y=${var.primary_configuration.y} z=${var.primary_configuration.z}
EOS
}
}
実行結果
$ terraform apply -auto-approve
module.plain.null_resource.echo: Refreshing state... [id=5834646776835244708]
module.plain.null_resource.echo: Destroying... [id=5834646776835244708]
module.echo2.null_resource.echo: Creating...
module.echo1.null_resource.echo: Creating...
module.plain.null_resource.echo: Destruction complete after 0s
module.echo1.null_resource.echo: Provisioning with 'local-exec'...
module.echo2.null_resource.echo: Provisioning with 'local-exec'...
module.echo1.null_resource.echo (local-exec): Executing: ["/bin/sh" "-c" "echo x=10 y=20 z=30\n"]
module.echo2.null_resource.echo (local-exec): Executing: ["/bin/sh" "-c" "echo x=100 y=200 z=300\n"]
module.echo2.null_resource.echo (local-exec): x=100 y=200 z=300
module.echo1.null_resource.echo (local-exec): x=10 y=20 z=30
module.echo2.null_resource.echo: Creation complete after 0s [id=1269680042276636852]
module.echo1.null_resource.echo: Creation complete after 0s [id=8965362161603827784]
Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
terraform show
# module.echo2.null_resource.echo:
resource "null_resource" "echo" {
id = "1269680042276636852"
triggers = {
"x" = "100"
"y" = "200"
"z" = "300"
}
}
# module.echo1.null_resource.echo:
resource "null_resource" "echo" {
id = "8965362161603827784"
triggers = {
"x" = "10"
"y" = "20"
"z" = "30"
}
}