resource定義無しのterraform入門

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) 。これの仕様は以下にある。

terraformのドキュメントにあるsyntaxの説明は大して役に立たない1

利用できる組み込みの関数

利用できる組み込みの関数について知りたいときにドキュメントを見るべきなのかもしれないが一覧性が悪い。

雑に言うとgrepしたりなどが出来ない。直接コードを読んだ方が早い。

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"
    }
}

gist


  1. そこからspecへのリンクに飛べるので入り口ページとしては機能している

  2. 単に利用するだけならhclsimpleを使うのが手軽