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
| Aspect | count | for_each |
|---|---|---|
| Identity | index (0, 1, 2) — เปลี่ยนได้ | key (string) — stable |
| เพิ่ม/ลบกลาง | shifts other items | ✅ no shift |
| Conditional | count = var.x ? 1 : 0 | for_each = var.x ? toset(["x"]) : [] |
| เหมาะกับ | identical resources | distinct 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_on | Force ordering (ใช้เท่าที่จำเป็น) |
count | Replicate ตามตัวเลข — index-based |
for_each | Replicate ตาม map/set — key-based ⭐ |
provider | เลือก provider alias |
lifecycle | Fine-tune create/destroy behavior |
Best Practice:
- ใช้
for_eachแทนcountถ้ามี natural key - หลีกเลี่ยง
depends_on— ใช้ reference แทน - ใช้
lifecycleเท่าที่จำเป็น
ต่อไป → Section 5: Variables