The State File
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”state ของ Terraform คือไฟล์ JSON ที่แมป resource แต่ละตัวใน configuration ของคุณเข้ากับ object จริงที่สร้างขึ้น และเป็นสิ่งเดียวที่ทำให้ Terraform รู้ว่าตัวเองจัดการอะไรอยู่
ทำไม Terraform ถึงต้องมี state
หัวข้อที่มีชื่อว่า “ทำไม Terraform ถึงต้องมี state”ตอนคุณรัน 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
ความเสี่ยงของ plaintext ที่ซ่อนอยู่ใน state file
หัวข้อที่มีชื่อว่า “ความเสี่ยงของ plaintext ที่ซ่อนอยู่ใน state file”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 แรกของโปรเจกต์ใหม่
terraform.tfstateterraform.tfstate.backup*.tfstate*.tfstate.*บทถัดไปจะพูดถึงการย้าย state ออกจาก laptop ไปไว้บน remote backend ที่ควบคุม access ได้จริง นั่นคือวิธีแก้ความเสี่ยงนี้ที่แท้จริง — .gitignore แค่กันอุบัติเหตุที่เห็นชัดที่สุดเท่านั้น
การดู state
หัวข้อที่มีชื่อว่า “การดู state”Terraform มีคำสั่งสามตัวสำหรับดูข้างใน state โดยไม่ต้องเปิดไฟล์ JSON เอง
# Human-readable dump of the entire current stateterraform show
# List every resource address currently tracked in stateterraform state list
# Show full attribute detail for one specific resourceterraform state show google_compute_instance.webterraform 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