Drift Detection and Import
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”Configuration drift คือสิ่งที่เกิดขึ้นเมื่อของจริงเบี่ยงเบนไปจาก Terraform config โดยที่ Terraform ไม่รู้ตัว และ terraform import (หรือ declarative import block) คือวิธีที่คุณเอา resource ที่มีอยู่แล้วเข้ามาอยู่ภายใต้การจัดการของ Terraform ตั้งแต่แรก
Configuration drift
หัวข้อที่มีชื่อว่า “Configuration drift”Drift เกิดขึ้นทุกครั้งที่มีใครหรืออะไรก็ตามเปลี่ยน resource นอกเหนือจาก Terraform เคสที่เจอบ่อยบน Google Cloud วิศวกรเปิด Console ตอนรีบ ๆ แล้วแก้ label ของ Compute Engine instance ตรง ๆ หรือ resize machine type โดยไม่แตะ Terraform configuration ที่ควรจะจัดการ instance นั้นอยู่ state ที่ Terraform บันทึกไว้ตอนนี้ไม่ตรงกับ object จริงแล้ว
ไม่มีอะไรแจ้งเตือนคุณเรื่องนี้อัตโนมัติ ครั้งถัดไปที่มีคนรัน
terraform planTerraform จะ refresh มุมมองของ resource จริง เทียบกับทั้ง configuration และ state ล่าสุดที่บันทึกไว้ แล้วโชว์ความต่างออกมาเป็น plan — ปกติจะเป็น “in-place update” ที่จะ revert การเปลี่ยนแปลงที่ทำมือกลับไปเป็นแบบที่ configuration บอกไว้ เพราะ Terraform ถือว่า configuration คือ source of truth
บางครั้งคุณอยากได้ผลตรงข้าม คือยอมรับการเปลี่ยนแปลงที่ทำมือ แล้วแค่ทำให้ state ของ Terraform sync กลับมาตรงกับความเป็นจริง โดยไม่แตะ infrastructure จริงเลย นั่นคือหน้าที่ของ -refresh-only mode
terraform apply -refresh-onlyคำสั่งนี้ update แค่ attribute ที่บันทึกไว้ใน state file ให้ตรงกับสิ่งที่รันอยู่จริงบน GCP ตอนนี้ ไม่สร้าง update หรือ destroy resource จริงตัวไหนเลย — เป็นการ reconcile ความจำของ Terraform กับโลกจริงล้วน ๆ
เอา resource ที่มีอยู่แล้วเข้ามาอยู่ภายใต้การจัดการด้วย terraform import
หัวข้อที่มีชื่อว่า “เอา resource ที่มีอยู่แล้วเข้ามาอยู่ภายใต้การจัดการด้วย terraform import”GCP resource จำนวนมากถูกสร้างขึ้นก่อนที่ Terraform จะมีตัวตนใน project ด้วยซ้ำ — Compute Engine instance ที่ใครสักคนคลิกสร้างใน Console, Cloud Storage bucket ที่สร้างจาก script ยุคแรก คำสั่ง CLI terraform import เชื่อม resource ที่มีอยู่แล้วจริงตัวหนึ่งเข้ากับ resource address ที่เขียนไว้ใน configuration ของคุณแล้ว
terraform import google_compute_instance.web projects/my-project-id/zones/us-central1-a/instances/web-vmจุดที่พลาดง่ายคือเรื่องนี้ terraform import เติมแค่ state entry เท่านั้น ไม่เขียน HCL ให้คุณเลย คุณยังต้องเขียน resource "google_compute_instance" "web" { ... } block เองด้วยมือ ให้ attribute ใกล้เคียงกับ object จริงพอที่ plan ครั้งถัดไปจะไม่ขึ้น diff ใหญ่ ๆ ถ้า config ผิด apply ครั้งถัดไปของคุณอาจพยายาม “fix” resource ให้ตรงกับ config ที่ไม่เคยอธิบาย resource นั้นจริง ๆ
Declarative import block
หัวข้อที่มีชื่อว่า “Declarative import block”Terraform 1.5 เพิ่มวิธี import แบบที่สอง ซึ่งตอนนี้หลายทีมชอบมากกว่าสำหรับอะไรก็ตามที่ควรค่าแก่การ review นั่นคือ import block ที่เขียนตรงในไฟล์ .tf คู่กับ configuration ตัวอื่น ๆ
import { to = google_compute_instance.web id = "projects/my-project-id/zones/us-central1-a/instances/web-vm"}ข้อดีเทียบกับคำสั่ง CLI อยู่ที่เรื่อง review ล้วน ๆ การรัน terraform import ผ่าน CLI คือ side effect ทันที — เพราะเขียนลง state ทันทีที่คุณรัน โดยไม่มีขั้นตอน preview เลย ในทางกลับกัน import block ก็แค่ configuration อีกชิ้นหนึ่ง ที่ขึ้นในผลลัพธ์ของ terraform plan เป็น planned import เหมือนกับ planned create หรือ update ทำให้เพื่อนร่วมทีม review ได้ใน pull request ก่อนที่ใครจะรัน apply Terraform ยังสร้าง resource block เริ่มต้นให้คุณได้จาก attribute ของ object จริง โดยใช้ terraform plan -generate-config-out=generated.tf แล้วคุณค่อย review และจัดให้เรียบร้อยแทนที่จะเขียนจากศูนย์
จัดระเบียบ state โดยไม่แตะ infrastructure
หัวข้อที่มีชื่อว่า “จัดระเบียบ state โดยไม่แตะ infrastructure”terraform state subcommand อีกสองตัวปิดท้ายบทนี้ และทั้งคู่เป็นภาพสะท้อนกลับกัน
# Rename or move a resource's address in state, e.g. after refactoring into a moduleterraform state mv google_compute_instance.web module.app.google_compute_instance.web
# Stop tracking a resource in state, without destroying the real objectterraform state rm google_compute_instance.webterraform state mv เปลี่ยนแค่ address ที่ Terraform ใช้อ้างอิง resource ใน state — มีประโยชน์ตอน restructure configuration เข้า module แล้วไม่อยากให้ Terraform คิดว่าต้อง destroy address เก่าแล้วสร้างใหม่ terraform state rm ตรงข้ามกับ import เลย โดยลบ entry ของ resource ออกจาก state ทำให้ Terraform เลิกจัดการ แต่ไม่มีผลอะไรกับ GCP object จริงเลย object นั้นยังรันต่อไปเหมือนเดิมทุกอย่าง แค่ตอนนี้ไม่มีใครจัดการแล้ว
flowchart LR manual["Instance label edited in Console"] --> plan["terraform plan"] plan -->|"diff shown"| drift["Drift detected"] existing["Existing untracked GCP resource"] --> importBlock["import block or terraform import"] importBlock -->|"state entry created"| state["terraform.tfstate"]