Resource Lifecycle
lifecycleblock — fine-tune ว่า Terraform จะ create/destroy/update resource ยังไง — กันลบเผลอ, zero-downtime replace, ฯลฯ
Lifecycle Block
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t2.micro"
lifecycle {
create_before_destroy = true
prevent_destroy = false
ignore_changes = [tags]
replace_triggered_by = [aws_security_group.web.id]
}
}
มี 4 options หลัก:
1. create_before_destroy
Default: Terraform จะ destroy → create (อาจ downtime)
ถ้าตั้ง true: create ใหม่ก่อน → destroy ของเก่า (zero downtime)
resource "aws_launch_template" "web" {
name_prefix = "web-"
image_id = "ami-12345"
instance_type = "t2.micro"
lifecycle {
create_before_destroy = true
}
}
ใช้ตอน:
- Auto Scaling Group / Launch Template
- ASG ที่ replace ทุกครั้งที่ launch template เปลี่ยน
- Resource ที่ "name" unique (ใช้
name_prefixร่วมด้วย)
- ถ้า resource มี unique constraint (เช่น name ซ้ำไม่ได้) → ต้องใช้
name_prefixแทนname - ไม่ work ถ้า resource มี dependency ที่ไม่ replace ตามไปด้วย
2. prevent_destroy
ป้องกัน destroy แบบ accident — ใช้กับ resource สำคัญ เช่น database, S3 bucket ที่มีข้อมูลจริง
resource "aws_db_instance" "prod" {
identifier = "prod-db"
engine = "postgres"
instance_class = "db.t3.medium"
allocated_storage = 100
lifecycle {
prevent_destroy = true
}
}
ถ้ามีคนพยายามลบ → Terraform fail ทันที:
Error: Instance cannot be destroyed
Resource aws_db_instance.prod has lifecycle.prevent_destroy set...
ถ้าจำเป็นต้องลบจริงๆ — ลบ prevent_destroy = true ออกจาก code → commit → apply
ขั้นตอนนี้ทำให้มี audit trail ว่าใครเป็นคนลบ
3. ignore_changes
บอก Terraform ว่า "ไม่ต้องสนใจ argument นี้แม้จะต่างจาก config"
resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = "t2.micro"
tags = {
Name = "web"
}
lifecycle {
ignore_changes = [
tags, # เพิกเฉยทั้ง tags
ami, # ไม่ replace ตอน AMI ใหม่
]
}
}
Use Cases:
- Auto-managed tags — tools อื่น (เช่น AWS Backup) เพิ่ม tag เอง
- Auto-update — AMI updated โดย AWS auto patching
- Initial deploy only — ตั้งค่าเริ่มต้น แล้วปล่อยให้คนแก้ใน console (อาจไม่ดี!)
Ignore ทั้งหมด:
lifecycle {
ignore_changes = all
}
ใช้ ignore_changes = all แสดงว่า resource นั้น "ไม่ใช่ Terraform manage แล้ว" — น่าจะ remove ออกจาก state ไปเลยมากกว่า
4. replace_triggered_by
Force replace resource เมื่อ resource อื่นเปลี่ยน (Terraform 1.2+)
resource "aws_appautoscaling_policy" "web" {
# ... config ...
lifecycle {
replace_triggered_by = [
aws_appautoscaling_target.web.id
]
}
}
ใช้ตอน:
- ASG policy ที่ต้อง re-create ทุกครั้งที่ target เปลี่ยน
- Lambda function ต้อง re-deploy เมื่อ source code (S3 object) เปลี่ยน
รวม Lifecycle Options
resource "aws_db_instance" "prod" {
identifier = "prod-db"
engine = "postgres"
instance_class = "db.t3.medium"
lifecycle {
create_before_destroy = true # zero-downtime replace
prevent_destroy = true # ป้องกันลบ
ignore_changes = [ # ignore เปลี่ยนแปลงเหล่านี้
password, # password rotated by Vault
tags["LastBackup"], # backup tool เป็นคนอัปเดต
]
}
}
ตัวอย่าง Production Patterns
Pattern 1: ASG with Launch Template
resource "aws_launch_template" "web" {
name_prefix = "web-lt-"
image_id = data.aws_ami.amazon_linux.id
instance_type = var.instance_type
lifecycle {
create_before_destroy = true
}
}
resource "aws_autoscaling_group" "web" {
name_prefix = "web-asg-"
launch_template {
id = aws_launch_template.web.id
version = aws_launch_template.web.latest_version
}
min_size = 2
max_size = 10
lifecycle {
create_before_destroy = true
}
}
Pattern 2: Production Database
resource "aws_db_instance" "prod" {
identifier = "prod-db"
engine = "postgres"
engine_version = "15.4"
instance_class = "db.t3.medium"
allocated_storage = 100
backup_retention_period = 30
deletion_protection = true # double protection จาก AWS เอง
lifecycle {
prevent_destroy = true
ignore_changes = [
engine_version, # AWS auto minor version upgrade
latest_restorable_time,
]
}
}
Pattern 3: Lambda with Auto-Updated Source
resource "aws_lambda_function" "api" {
function_name = "my-api"
role = aws_iam_role.lambda.arn
handler = "index.handler"
runtime = "nodejs20.x"
s3_bucket = aws_s3_bucket.code.id
s3_key = "lambda/api.zip"
lifecycle {
replace_triggered_by = [
aws_s3_object.lambda_code.etag # ทุกครั้งที่ code zip เปลี่ยน
]
}
}
เมื่อไหร่ไม่ใช้ Lifecycle?
- อย่าใช้
prevent_destroyทุก resource — ทำให้ลบยาก ทดสอบ destroy ลำบาก - อย่าใช้
ignore_changes = all— แปลว่า "ไม่ใช่ Terraform แล้ว" - อย่าใช้
create_before_destroyกับ resource ที่ไม่ต้องการ zero-downtime
สรุป
| Option | หน้าที่ |
|---|---|
create_before_destroy | Zero-downtime replace |
prevent_destroy | กันลบ resource สำคัญ |
ignore_changes | Ignore argument บาง field |
replace_triggered_by | Force replace เมื่อ resource อื่นเปลี่ยน |
ใช้ lifecycle เท่าที่จำเป็น — มากเกินไป = code ที่อ่านยาก + behavior ที่ surprise
ต่อไป → Meta Arguments — count, for_each, depends_on, provider