ข้ามไปยังเนื้อหา

The State File

state ของ Terraform คือไฟล์ JSON ที่แมป resource แต่ละตัวใน configuration ของคุณเข้ากับ object จริงที่สร้างขึ้น และเป็นสิ่งเดียวที่ทำให้ Terraform รู้ว่าตัวเองจัดการอะไรอยู่

ตอนคุณรัน terraform apply Terraform สร้าง resource ผ่าน API ของ Google Cloud — Compute Engine instance, Cloud Storage bucket, IAM binding สักตัว API ของ GCP ไม่มีแนวคิดเรื่อง “Terraform” เลย ถ้า project หนึ่งมี Compute Engine instance 500 ตัว Compute Engine API ก็บอกไม่ได้ว่าตัวไหนคือตัวที่ Terraform สร้างให้กับ resource "google_compute_instance" "web" block นี้ ตัวไหนที่เพื่อนร่วมทีมสร้างมือใน Console และตัวไหนเป็นของ Terraform configuration อื่นไปเลย

Terraform แก้ปัญหานี้ด้วยการเก็บ record ของตัวเอง ทุกครั้งที่ apply Terraform จะเขียน mapping ระหว่าง resource address ใน configuration กับ ID จริงของ infrastructure ลงไฟล์ state ที่ชื่อ default คือ terraform.tfstate

resource "google_compute_instance" "web" {
name = "web-vm"
machine_type = "e2-medium"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
network_interface {
network = "default"
}
}

หลัง apply ไฟล์ state จะบันทึกประมาณว่า google_compute_instance.web -> projects/my-project-id/zones/us-central1-a/instances/web-vm พร้อม attribute ทุกตัวที่ Compute Engine API ส่งกลับมาสำหรับ instance นั้น — internal IP, self link, network interface และอื่น ๆ ข้อมูลที่ cache ไว้นี้ทำให้ Terraform ไม่ต้องเรียก GCP API แล้ว describe resource ทุกตัวใหม่แค่เพื่อคำนวณ plan เพราะเทียบ configuration กับ state ล่าสุดก่อนได้เลย นี่คือทั้งวิธีตรวจจับว่าอะไรเปลี่ยน และเป็นข้อดีด้าน performance จริง ๆ กับ configuration ขนาดใหญ่ state ยังเป็นที่เก็บ dependency metadata ด้วย ทำให้ Terraform รู้ลำดับที่ต้องสร้าง แก้ไข หรือลบ resource

state file ไม่ได้ผ่านการ sanitize attribute value ใด ๆ ที่ Terraform ได้รับจาก provider — หรือที่คุณตั้งตรงใน configuration — จะไปอยู่ใน terraform.tfstate แบบ plaintext รวมถึงค่าที่เป็น secret ด้วย ตัวอย่างที่เจอบ่อย

resource "google_sql_user" "app" {
name = "app_admin"
instance = google_sql_database_instance.main.name
password = "S3cretPassword!"
}

คุณไม่เคยรัน terraform output กับ password ตัวนั้น และไม่เคย print ใน log แต่ค่านั้นก็ยังไปอยู่ใน terraform.tfstate แบบ plaintext อยู่ดี เพราะ Terraform ต้องจำ attribute ทุกตัวที่ตั้งไว้ เพื่อตรวจ drift ตอน plan ครั้งถัดไป ใครก็ตามที่อ่านไฟล์นั้นได้ก็อ่าน password ได้ด้วย

นี่คือเหตุผลที่ terraform.tfstate ห้าม commit เข้า version control เด็ดขาด ใส่ลง .gitignore ตั้งแต่ commit แรกของโปรเจกต์ใหม่

.gitignore
terraform.tfstate
terraform.tfstate.backup
*.tfstate
*.tfstate.*

บทถัดไปจะพูดถึงการย้าย state ออกจาก laptop ไปไว้บน remote backend ที่ควบคุม access ได้จริง นั่นคือวิธีแก้ความเสี่ยงนี้ที่แท้จริง — .gitignore แค่กันอุบัติเหตุที่เห็นชัดที่สุดเท่านั้น

Terraform มีคำสั่งสามตัวสำหรับดูข้างใน state โดยไม่ต้องเปิดไฟล์ JSON เอง

Terminal window
# Human-readable dump of the entire current state
terraform show
# List every resource address currently tracked in state
terraform state list
# Show full attribute detail for one specific resource
terraform state show google_compute_instance.web

terraform state list คือวิธีเร็วที่สุดในการตอบคำถามว่า “configuration นี้จัดการอะไรอยู่ตอนนี้” คำสั่งนี้ print address อย่าง google_compute_instance.web หรือ module.network.google_compute_network.main โดยไม่มีรายละเอียดอื่น terraform state show <address> จะลงลึกไป address ใดตัวหนึ่ง แล้ว print attribute ทุกตัวที่ Terraform บันทึกไว้ ซึ่งบ่อยครั้งเร็วกว่าการไปเปิด Google Cloud Console เวลาต้องเช็คค่าที่ Terraform track อยู่

flowchart LR
  cfg["Terraform config (.tf files)"] --> apply["terraform apply"]
  apply --> gcp["Real GCP resources"]
  gcp -->|attributes written back| state["terraform.tfstate"]
  cfg -->|next run| plan["terraform plan"]
  state -->|read for comparison| plan
Config and real GCP resources both feed the state file that the next plan reads
ทำไม Terraform ถึงต้องมี state file แทนที่จะ query cloud provider API ทุกครั้ง
database password ถูกตั้งเป็น resource attribute แต่ไม่เคย print ด้วย terraform output ค่านั้นยังไปอยู่แบบ plaintext ที่ไหนได้ไหม
terraform state list กับ terraform state show ต่างกันยังไง
.gitignore ของโปรเจกต์ Terraform ใหม่ ควรมีอะไรตั้งแต่ commit แรก