Terraformモジュールとリソースアドレス
モジュールの共通定義、呼出しごとの入力、stateのアドレス、実ファイルの対応を説明します。
説明
Terraformのモジュールは、入力変数から資源を宣言し、出力値を返す単位です。同じモジュールを複数回使うときは、それぞれの資源アドレスと実体の名前を分ける必要があります。for_eachのキーは管理対象の識別にも使われます。
frontとadminの2サービスに同じ子モジュールを使い、名前とポートが異なる設定ファイルを作ります。一方だけの入力を変更した後、adminの定義を外して削除対象を確認します。
モジュールの共通定義、呼出しごとの入力、stateのアドレス、実ファイルの対応を説明します。
1共通定義と呼出し側を読む
子モジュールはnameとportを受け取り、名前ごとにファイルを作ります。呼出し側のservicesマップはfront=8080、admin=9090です。
cp modules-main.tf.sample main.tfモジュールを使う定義へ切り替える
cat modules/service/main.tf子モジュールの入力と出力を読む
cat main.tf呼出し側のマップを読む同じ定義を2回コピーする代わりに、for_eachでキーと値を渡しています。出力pathは呼出し側から取得できます。
2モジュールを初期化して計画する
新しいモジュール参照をinitで読み込み、計画を保存します。
terraform initローカルの子モジュールを読み込む -input=false -no-color > init.log
terraform plan2回の呼出しを計画する -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan展開後の資源アドレスを読むmodule.service["admin"]とmodule.service["front"]の別々のアドレスでcreateされます。子モジュール内の資源名が同じでも、呼出し元のアドレスが異なります。
3実ファイルへ反映する
計画を適用し、出力値と実ファイルを確認します。
terraform apply2サービス分を作る -input=false -no-color plan.bin > apply.log
terraform output -json pathsモジュール出力を取得する
cat front.conf admin.conf入力に対応する実ファイルを読む出力はそれぞれのファイルを指し、内容はname=front/port=8080とname=admin/port=9090です。
4frontだけを変更する
servicesのfrontを8081へ変え、adminは9090のままにします。
python3 -cfrontだけの入力値を変える 'import json; json.dump({"services":{"front":8081,"admin":9090}},open("terraform.tfvars.json","w"))'
terraform plan呼出しごとの差分を保存する -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan変更対象のアドレスを読むadminはno-op、frontだけが置換対象です。共通モジュールを使っていても、入力が変わった呼出しを識別できます。
5一方だけの変更を確認する
保存した計画を適用して両ファイルを読みます。
terraform applyfrontの変更を適用する -input=false -no-color plan.bin > apply.log
cat front.conf admin.conf両方の実ファイルを比較するfrontは8081、adminは9090です。変更する必要のない側の値は保持されています。
6マップからadminを外す
servicesにfrontだけを残します。キーの削除は、そのキーで管理する資源の削除計画になります。
python3 -cadminのキーを外す 'import json; json.dump({"services":{"front":8081}},open("terraform.tfvars.json","w"))'
terraform planキー削除の影響を計画する -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py plan削除する資源を確認するadminはdelete、frontはno-opです。表示名を変えるつもりでキーを消すと、資源の削除になり得ます。
7削除後の管理対象と実体
計画どおりadminを削除します。
terraform apply確認した削除計画を適用する -input=false -no-color plan.bin > apply.log
terraform state list残った管理アドレスを読む
python3 -c実ファイルの有無を確認する 'from pathlib import Path; print("front="+str(Path("front.conf").exists())+" admin="+str(Path("admin.conf").exists()))'stateにはfrontだけが残り、admin.confもなくなります。モジュール定義から実資源まで変更範囲が一致しました。
まとめ
モジュールの入力ごとに異なる資源を管理できます。
for_eachのキーは資源アドレスの一部です。
キー削除は単なる表示変更ではなく、削除計画になることがあります。
操作履歴と解説を振り返れます。
Terraform 1.17.0 / hashicorp/local 2.5.3 / local backend
cp modules-main.tf.sample main.tf
cat modules/service/main.tf
cat main.tfterraform {
required_providers {
local = { source = "hashicorp/local", version = "2.5.3" }
}
}
variable "name" { type = string }
variable "port" { type = number }
resource "local_file" "config" {
filename = "${path.root}/${var.name}.conf"
content = "name=${var.name}\nport=${var.port}\n"
file_permission = "0600"
}
output "path" { value = local_file.config.filename }
terraform {
required_providers {
local = { source = "hashicorp/local", version = "2.5.3" }
}
}
variable "services" {
type = map(number)
default = { front = 8080, admin = 9090 }
}
module "service" {
for_each = var.services
source = "./modules/service"
name = each.key
port = each.value
}
output "paths" { value = { for key, item in module.service : key => item.path } }terraform init -input=false -no-color > init.log
terraform plan -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py planmodule.service["admin"].local_file.config create module.service["front"].local_file.config create
terraform apply -input=false -no-color plan.bin > apply.log
terraform output -json paths
cat front.conf admin.conf{"admin":"./admin.conf","front":"./front.conf"}
name=front
port=8080
name=admin
port=9090python3 -c 'import json; json.dump({"services":{"front":8081,"admin":9090}},open("terraform.tfvars.json","w"))'
terraform plan -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py planmodule.service["admin"].local_file.config no-op module.service["front"].local_file.config delete,create
terraform apply -input=false -no-color plan.bin > apply.log
cat front.conf admin.confname=front port=8081 name=admin port=9090
python3 -c 'import json; json.dump({"services":{"front":8081}},open("terraform.tfvars.json","w"))'
terraform plan -input=false -no-color -out=plan.bin > plan.log
python3 inspect.py planmodule.service["admin"].local_file.config delete module.service["front"].local_file.config no-op
terraform apply -input=false -no-color plan.bin > apply.log
terraform state list
python3 -c 'from pathlib import Path; print("front="+str(Path("front.conf").exists())+" admin="+str(Path("admin.conf").exists()))'module.service["front"].local_file.config front=True admin=False
演習完了