Skip to main content

Meta Arguments

Meta arguments เป็น argument พิเศษที่ทำงานกับ resource block ทุกชนิด — depends_on, count, for_each, provider, lifecycle

ทำไม "Meta"?

เพราะมันไม่ใช่ argument ของ resource เอง — เป็น argument ที่ Terraform engine ใช้ตัดสินใจ:

  • จำนวน instance
  • Order
  • Provider ตัวไหน
  • Behavior ของ create/destroy

1. depends_on

บอก Terraform ว่า "resource นี้ต้องรอ resource อื่นเสร็จก่อน" (แม้ไม่มี reference โดยตรง)

resource "aws_iam_role_policy" "lambda_logs" {
# ...
}

resource "aws_lambda_function" "api" {
function_name = "api"
role = aws_iam_role.lambda.arn

depends_on = [
aws_iam_role_policy.lambda_logs # ← รอ policy attach เสร็จก่อน
]
}

ส่วนใหญ่ Terraform คำนวณ dependency อัตโนมัติจาก reference — ใช้ depends_on เฉพาะตอน:

  • Implicit dependency ที่ Terraform มองไม่เห็น (เช่น IAM permission ต้อง attach ก่อน Lambda รัน)
  • Side effect ที่ไม่ผ่าน attribute reference
ใช้เท่าที่จำเป็น

depends_on เยอะเกิน = code ที่ดูแลยาก ส่วนใหญ่ปัญหา dependency มักแก้ด้วย reference attribute ตรงๆ ดีกว่า

2. count

สร้าง resource หลายตัวด้วย numeric loop

resource "aws_instance" "web" {
count = 3
ami = "ami-12345"
instance_type = "t2.micro"

tags = {
Name = "web-${count.index}" # web-0, web-1, web-2
}
}

Reference

# ตัวเดียว
output "first_ip" {
value = aws_instance.web[0].public_ip
}

# ทั้งหมด (splat)
output "all_ips" {
value = aws_instance.web[*].public_ip
}

Conditional Resource

resource "aws_instance" "bastion" {
count = var.create_bastion ? 1 : 0
ami = "ami-12345"
instance_type = "t2.micro"
}

→ ถ้า var.create_bastion = false → ไม่สร้าง bastion เลย

ข้อจำกัดของ count

resource "aws_instance" "web" {
count = 3
# ...
}

ถ้าลบ web[1] ออก → web[2] เลื่อนเป็น web[1] → state จะคิดว่าต้อง recreate web[2]!

→ ใช้ for_each แทนเมื่อต้องการ stable identity

3. for_each

สร้าง resource หลายตัวด้วย map / set

Map

resource "aws_instance" "servers" {
for_each = {
web = "t2.micro"
api = "t2.small"
db = "t2.medium"
}

ami = "ami-12345"
instance_type = each.value

tags = {
Name = each.key # web, api, db
}
}

Set

resource "aws_iam_user" "admin" {
for_each = toset(["alice", "bob", "charlie"])

name = each.key
}

Reference

# ตัวเดียว
output "web_ip" {
value = aws_instance.servers["web"].public_ip
}

# ทั้งหมด
output "all_ips" {
value = { for k, v in aws_instance.servers : k => v.public_ip }
}

count vs for_each

Aspectcountfor_each
Identityindex (0, 1, 2) — เปลี่ยนได้key (string) — stable
เพิ่ม/ลบกลางshifts other items✅ no shift
Conditionalcount = var.x ? 1 : 0for_each = var.x ? toset(["x"]) : []
เหมาะกับidentical resourcesdistinct resources by key
ใช้ตัวไหน?
  • for_each ถ้ามี natural key (env name, region name, user name)
  • count ถ้าเป็น replica เหมือนๆ กัน หรือ conditional 0/1
  • count อย่าใช้ถ้าจำนวนจะเปลี่ยนแปลงตอนแก้ config (insertion in middle)

ตัวอย่าง: Conditional + for_each

resource "aws_security_group_rule" "ingress" {
for_each = var.enable_ssh ? toset(["ssh"]) : toset([])

type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.web.id
}

4. provider

ระบุ provider alias สำหรับ resource ที่ใช้ alias

provider "aws" {
region = "ap-southeast-1"
}

provider "aws" {
alias = "tokyo"
region = "ap-northeast-1"
}

# Default provider
resource "aws_s3_bucket" "sg" {
bucket = "data-sg"
}

# Alias provider
resource "aws_s3_bucket" "tokyo" {
provider = aws.tokyo # ← meta argument
bucket = "data-tokyo"
}

5. lifecycle

ดูใน Resource Lifecycle — กำหนด create/destroy/update behavior

รวมตัวอย่าง: Multi-Region Multi-Env

locals {
environments = {
dev = {
instance_type = "t2.micro"
region = "tokyo"
}
staging = {
instance_type = "t2.small"
region = "tokyo"
}
prod = {
instance_type = "t2.large"
region = "us"
}
}
}

# Dev + staging in Tokyo
resource "aws_instance" "asia" {
for_each = {
for k, v in local.environments : k => v
if v.region == "tokyo"
}

provider = aws.tokyo
ami = "ami-tokyo"
instance_type = each.value.instance_type

tags = { Name = each.key }
}

# Prod in US
resource "aws_instance" "us" {
for_each = {
for k, v in local.environments : k => v
if v.region == "us"
}

provider = aws.us
ami = "ami-us"
instance_type = each.value.instance_type

tags = { Name = each.key }
}

สรุป

Meta Argumentหน้าที่
depends_onForce ordering (ใช้เท่าที่จำเป็น)
countReplicate ตามตัวเลข — index-based
for_eachReplicate ตาม map/set — key-based ⭐
providerเลือก provider alias
lifecycleFine-tune create/destroy behavior

Best Practice:

  • ใช้ for_each แทน count ถ้ามี natural key
  • หลีกเลี่ยง depends_on — ใช้ reference แทน
  • ใช้ lifecycle เท่าที่จำเป็น

ต่อไป → Section 5: Variables