Skip to main content

Resource Behavior

Terraform คิดยังไงเวลา plan และ apply — ทำความเข้าใจว่ามันตัดสินใจ create / update / destroy / replace แบบไหน

4 Actions ของ Terraform

ทุกครั้งที่ terraform plan Terraform จะตัดสินว่าแต่ละ resource ต้องทำอะไร:

SymbolActionความหมาย
+Createสร้างใหม่ (ยังไม่มีใน state)
~Update in-placeแก้ไขแบบไม่สร้างใหม่
-/+Replaceลบของเก่า + สร้างใหม่
-Destroyลบทิ้ง (ไม่มีใน config แล้ว)
(ไม่แสดง)No-opไม่มีการเปลี่ยนแปลง

ตัวอย่าง Plan Output

Terraform will perform the following actions:

# aws_instance.web will be updated in-place
~ resource "aws_instance" "web" {
id = "i-1234567890abcdef0"
~ tags = {
~ "Name" = "web-old" -> "web-new"
}
}

# aws_s3_bucket.data will be created
+ resource "aws_s3_bucket" "data" {
+ bucket = "my-data"
+ id = (known after apply)
}

# aws_security_group.old will be destroyed
- resource "aws_security_group" "old" {
- id = "sg-12345" -> null
}

Plan: 1 to add, 1 to change, 1 to destroy.

Update vs Replace

ขึ้นอยู่กับ argument ที่แก้:

  • บาง argument = แก้ใน-place ได้ → update
  • บาง argument = ต้องสร้างใหม่ → replace

ตัวอย่าง: tags = update in-place

# ก่อน
tags = { Name = "web-v1" }

# หลัง
tags = { Name = "web-v2" }

→ AWS อนุญาตให้เปลี่ยน tag โดยไม่ต้องสร้างใหม่ → ~

ตัวอย่าง: instance_type = replace

# ก่อน
instance_type = "t2.micro"

# หลัง
instance_type = "t2.large"

→ AWS ไม่ให้เปลี่ยน instance type ของ instance ที่ running → ต้องสร้างใหม่ → -/+

Replace = Downtime!

ตอน plan ดูทุกครั้งว่ามี -/+ ไหม — ถ้ามีอาจหมายถึง downtime สำหรับ resource นั้น

ดูว่า argument ไหนทำให้ replace → ใน plan output จะมี # forces replacement กำกับ:

~ instance_type = "t2.micro" -> "t2.large" # forces replacement

Resource Lifecycle (CRUD)

State as Source of Truth

Terraform เปรียบเทียบ:

Config (.tf) ↔ State (.tfstate) ↔ Reality (cloud)
  • Config = State + State = Reality → ✅ no-op
  • Config ≠ State → plan แสดงการเปลี่ยนแปลง
  • State ≠ Reality (มีคนแก้ในcloud) → drift detected!

Drift Detection

terraform plan -refresh-only

→ ดูว่า reality เปลี่ยนไปจาก state มั้ย (มีคนแก้ใน console)

ตัวอย่าง: Common Behaviors

Argument ที่ "force new"

resource "aws_instance" "web" {
ami = "ami-12345" # ← เปลี่ยน = replace
instance_type = "t2.micro" # ← เปลี่ยน = replace
subnet_id = "subnet-abc" # ← เปลี่ยน = replace
key_name = "my-key" # ← เปลี่ยน = replace
}

Argument ที่ update in-place

resource "aws_instance" "web" {
tags = {...} # ← in-place
associate_public_ip = true # ← in-place (บางกรณี)
monitoring = true # ← in-place
root_block_device { ... } # ← in-place (บาง field)
}

ดูว่า argument ไหนทำอะไร → อ่าน documentation ของ resource ใน Terraform Registry

Manual Control: -replace

Force replace resource เฉพาะตัว:

terraform apply -replace="aws_instance.web"

ใช้เวลา:

  • Resource หาย state ไม่ตรงกับ reality
  • ต้องการ "re-create" เพื่อ apply config ใหม่ทั้งหมด

(เดิมเรียก terraform taint — deprecated ใน Terraform 0.15+)

Idempotency

Terraform เป็น idempotent:

  • Apply ครั้งแรก → สร้าง resource
  • Apply อีกครั้ง (ไม่แก้ config) → no-op
$ terraform apply
# (สร้าง resource)
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

$ terraform apply
# (ไม่มี diff)
No changes. Your infrastructure matches the configuration.

เช็คว่า Apply จะทำอะไร — ก่อน Apply!

# Plan → save ลงไฟล์
terraform plan -out=tfplan

# อ่าน plan ในรูปแบบ JSON
terraform show -json tfplan | jq '.resource_changes'

# Apply เฉพาะ plan ที่ save ไว้
terraform apply tfplan
Production Practice

ใน CI/CD ใช้ pattern:

  1. PR open → run plan -out=tfplan → comment ลง PR
  2. Reviewer ดู plan
  3. PR merge → apply tfplan ตัวเดิม → no surprise

สรุป

  • 4 actions: create (+), update (~), replace (-/+), destroy (-)
  • บาง argument force replacement → ดูใน plan output
  • State = source of truth → drift = state ≠ reality
  • ใช้ -refresh-only เช็ค drift, -replace force replace
  • Terraform เป็น idempotent — apply ซ้ำได้โดยไม่ทำอะไรเพิ่ม

ต่อไป → Resource Lifecycle