【Terraform】Terraform ~ Terraformあれこれ ~

■ はじめに

Terraform に関する Tips を徐々にだけど
ここに書き溜めていく

目次

【1】デバッグログレベルを切り替えるには
【2】タイムアウト時間を変更するには
【3】依存関係を指定するには
 1) resourceセクションから別リソースを参照
 2) depends_on を指定
 補足:terraform graphで依存関係を可視化する
【4】同じリソースを複数作成するには
 1)count を使う
 2)for_each を使う
【5】ZIPファイル作成するには
【6】コマンドを実行するには

【1】デバッグログレベルを切り替えるには

* 実行コマンド前に「TF_LOG=<ログレベル>」を付加する

https://developer.hashicorp.com/terraform/internals/debugging

コマンド例

# コマンド一回限りでTF_LOGを設定する場合
TF_LOG=DEBUG terraform plan
# TRACE, DEBUG, INFO, WARN or ERROR

https://www.bioerrorlog.work/entry/terraform-debug-logging

【2】タイムアウト時間を変更するには

https://stackoverflow.com/questions/58771440/how-to-set-timeout-for-terraform-apply

# より抜粋

resource "<resource_name>" "<resource_name>" {
  ...
  # ★ここ★
  timeouts {
    create = "1h30m"
    update = "2h"
    delete = "20m"
  }
}

https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts

【3】依存関係を指定するには

* 以下の2通り
 1) resourceセクションから別リソースを参照
 2) depends_on を指定

https://sdpf.ntt.com/services/docs/terraform/tutorials/rsts/Terraform/tips.html

1) resourceセクションから別リソースを参照

例:VPC

data "aws_region" "current" {}

resource "aws_vpc_ipam" "test" {
  operating_regions {
    region_name = data.aws_region.current.name
  }
}

resource "aws_vpc_ipam_pool" "test" {
  address_family = "ipv4"
  # ★ここに注目★(別ファイルでも可能)
  ipam_scope_id  = aws_vpc_ipam.test.private_default_scope_id
  locale         = data.aws_region.current.name
}

2) depends_on を指定

https://developer.hashicorp.com/terraform/language/meta-arguments/depends_on

例:VPC

resource "aws_vpc_ipam_pool_cidr" "test" {
  ipam_pool_id = aws_vpc_ipam_pool.test.id
  cidr         = "172.2.0.0/16"
}

resource "aws_vpc" "test" {
  ipv4_ipam_pool_id   = aws_vpc_ipam_pool.test.id
  ipv4_netmask_length = 28
  # ★ここに注目★
  depends_on = [
    aws_vpc_ipam_pool_cidr.test
  ]
}

補足:terraform graphで依存関係を可視化する

* terraform graphで、Terraformの依存関係をグラフ化することが可能
 => 詳細は、以下の関連記事を参照のこと

Terraform ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2019/12/09/222057

【4】同じリソースを複数作成するには

https://tellme.tokyo/post/2022/06/12/terraform-count-for-each/

1)count を使う

https://developer.hashicorp.com/terraform/language/meta-arguments/count

resource "aws_instance" "server" {
  count = 4 # create four similar EC2 instances

  ami           = "ami-a1b2c3d4"
  instance_type = "t2.micro"

  tags = {
    Name = "Server ${count.index}"
  }
}

2)for_each を使う

https://developer.hashicorp.com/terraform/language/meta-arguments/for_each

resource "aws_iam_user" "the-accounts" {
  for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
  name     = each.key
}

【Terraform】(初心者向け)for_eachの使い方(実例つき) - 自由気ままに書いちゃおう

【5】ZIPファイル作成するには

* data "archive_file"で行う

https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file
https://registry.terraform.io/providers/hashicorp/archive/latest/docs/resources/file.html

使用上の注意

* Terraform 上で生成したものをZIP化する場合、
 depends_on を指定すること

サンプル

main.tf

resource "local_file" "for_test1" {
  content  = "hello!"
  filename = "${path.module}/test/hello.txt"
}

resource "local_file" "for_test2" {
  content  = "world!"
  filename = "${path.module}/test/world.txt"
}

resource "local_file" "for_test3" {
  content  = "test!"
  filename = "${path.module}/test/test.txt"
}

data "archive_file" "for_zip_file" {
  type        = "zip"
  source_dir = "${path.module}/test"
  output_path = "${path.module}/output.zip"
  excludes = [ "test.txt" ]
  depends_on = [ local_file.for_test1, local_file.for_test2, local_file.for_test3 ]
}

コマンド例

terraform init

terraform apply
# output.zipってファイルができて、
# 解凍すると「hello.txt」「world.txt」ができているはず

【6】コマンドを実行するには

* data "external" を使う

https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external

使用上の注意

* コマンドの戻り値は、Json形式
 => 「Program output must be a JSON encoded map of string keys and string values.」
  って怒られる

サンプル

main.tf

data "external" "hello_world" {
  # 実行したいコマンド
  program = ["python", "hello_world.py"]
  # 他にも、以下のような例がある
  # ex1. program = ["bash", "hello_world.sh"]
  # ex2. program = ["aws", "s3", "ls"]

  # 引数
  query = {
    name = "Mike"
  }
}

output "result" {
  value = data.external.hello_world.result["result"]
}

hello_world.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
import sys

def main():
  input_data = json.load(sys.stdin)
  name = input_data['name']
  json.dump({ "result": f"Hello, {name}!!"}, sys.stdout)

if __name__ == '__main__':
    main()

コマンド例

terraform init

terraform apply
・・・略・・・
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

result = "Hello, Mike!!"

関連記事

Terraform ~ 環境構築編 ~
https://dk521123.hatenablog.com/entry/2023/04/05/000224
Terraform ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2019/12/09/222057
Terraform ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2023/05/03/000000
Terraform ~ テンプレート ~
https://dk521123.hatenablog.com/entry/2023/05/22/101325
Terraform ~ AWS IAM ~
https://dk521123.hatenablog.com/entry/2023/04/12/214311
Terraform ~ AWS S3 ~
https://dk521123.hatenablog.com/entry/2023/04/09/104204
Terraform ~ AWS EC2 ~
https://dk521123.hatenablog.com/entry/2023/05/21/003048
Terraform ~ AWS MSK ~
https://dk521123.hatenablog.com/entry/2023/05/14/122215
Terraform ~ tag あれこれ ~
https://dk521123.hatenablog.com/entry/2023/06/05/224944
Terraform ~ 機密情報の扱いを考える ~
https://dk521123.hatenablog.com/entry/2023/05/18/005103