วิธีอ่าน Terraform ที่ไม่ได้เขียนเอง
ทุกโมดูลก่อนหน้านี้สอนให้คุณ เขียน Terraform และ Terragrunt โมดูลนี้สอนอีกครึ่งหนึ่ง คือการ อ่าน configuration ที่คนอื่น — หรือ AI — เขียนไว้ แล้วตัดสินว่ามันถูกต้องจริงหรือไม่ ผู้ช่วย AI ส่ง module, terragrunt.hcl, CI pipeline ที่ดูเหมือนตัวอย่างที่คุณเรียนมาทุกอย่าง ใช้ resource type และ argument ที่อ่านแล้วลื่นไหลและดูทันสมัย และ — ส่วนใหญ่แล้ว — terraform validate กับ terraform plan ผ่านสะอาดทั้งคู่ นั่นคือกับดักที่โมดูลนี้มีไว้ปิด จาก 23 pattern ที่บทถัดไปรวบรวมไว้ มีเพียงส่วนน้อยเท่านั้นที่ validate/plan/terragrunt ปฏิเสธตรงๆ ที่เหลือคือ configuration ที่ schema ถูกต้อง plan สะอาด แต่พังทีหลัง — ตอน apply จริงกับ cloud account จริง ตอน plan ครั้งถัดไปหลังมีคนแก้ list ที่ไม่เกี่ยวข้อง หรือไม่พังเลยแต่ทำสิ่งผิดอย่างเงียบๆ (ป้องกัน resource ผิดตัว, deploy prod ทับ account ของ dev, ปล่อย secret ที่ไม่มีใคร review)
มีปัญหา training data สามอย่างที่ซ้อนกันจนเกิดเรื่องนี้ อย่างแรก provider ecosystem ของ Terraform เปลี่ยนรูปแบบทุก release จริงๆ — aws_s3_bucket.acl เคยเป็นวิธีตั้งค่า ACL มาหลายปีแล้วตอนนี้ deprecated ไปเป็น aws_s3_bucket_acl, terragrunt run-all/plan-all เคยเป็นคำสั่งเดียวที่มีก่อน Terragrunt 1.1 ปรับ CLI ใหม่ — และ training data สาธารณะจำนวนมากเกิดก่อนการเปลี่ยนแปลงแต่ละครั้งขณะที่ยังอ่านเป็น HCL ที่ลื่นไหลทันสมัยอยู่ อย่างที่สอง count เป็น construct การวนซ้ำตัวแรกที่ tutorial ส่วนใหญ่สอน ผู้ช่วย AI จึงหยิบมาใช้เป็นค่าเริ่มต้นแม้ในที่ที่ for_each เป็นทางเลือกเดียวที่ปลอดภัย — list สามารถถูกจัดลำดับใหม่ได้ แต่ count แยกไม่ออกระหว่าง “จัดลำดับใหม่” กับ “แทนที่” อย่างที่สาม ทางที่เร็วที่สุดในการผ่าน error เรื่อง permission หรือ destroy มักเป็นทางแก้ที่กว้างที่สุดเสมอ — -auto-approve ลดแรงเสียดทานได้จริง prevent_destroy บน resource บางตัว ทำให้ error message หายไปได้จริง — แลกมาด้วยการเอา safeguard ตัวเดียวที่สำคัญออกไป หกขั้นตอนด้านล่างคือลำดับที่เผยความผิดพลาดเหล่านี้ออกมาจริงๆ และทุกบทถัดไปในโมดูลนี้จะเจาะลึกส่วนหนึ่งของมัน
flowchart TD A["1. Providers & versions<br/>pin ด้วย ~>? commit lock file แล้วหรือยัง?"] --> B["2. Backend & state<br/>locking จริงหรือ? remote_state ชี้ไปที่ state ที่ apply แล้ว?"] B --> C["3. Variables & locals<br/>nullable, ephemeral, validation block"] C --> D["4. Resources & lifecycle<br/>count แทนที่จะเป็น for_each? prevent_destroy ป้องกันอะไรจริงๆ?"] D --> E["5. Modules<br/>มี provider block ข้างใน? pin source แล้ว? depends_on ซ่อน cycle อยู่หรือไม่?"] E --> F["6. Terragrunt live tree<br/>run --all ไม่ใช่ run-all/plan-all? dev กับ prod ต่างกันจริงหรือ?"] F --> G["7. CI & policy<br/>-auto-approve บน plan สดๆ? pin action แล้ว? syntax policy ทันสมัย?"]
1. Providers & versions
หัวข้อที่มีชื่อว่า “1. Providers & versions”ก่อนอื่นเลย ตรวจว่า provider constraint ป้องกันคุณได้จริงหรือไม่ และ lock file ที่ pin version ที่ resolve จริง commit ไว้แล้วหรือยัง — เพราะ constraint ที่ลอยตัวเปลี่ยนความหมายของ “configuration เดียวกัน” ในสองวันที่ต่างกัน บนเครื่องที่ต่างกัน โดยไม่มี diff ให้ review เลย
- สิ่งที่ต้องมองหา:
~>หรือ>=ในrequired_providers?.terraform.lock.hclcommit ไว้หรือ gitignore ไว้พร้อมกับ.terraform/? มี resource ไหนใช้ argument ที่ schema ของ provider ที่ติดตั้งไว้ทำเครื่องหมายdeprecated: trueหรือไม่? - คำถามที่ต้องถาม: ถ้าเพื่อนร่วมทีมรัน
terraform initวันนี้เทียบกับอีกหนึ่งเดือนข้างหน้า จะ resolve provider version เดียวกันหรือไม่ — และterraform validate -jsonจะกลับมาโดยไม่มี warning เลยหรือไม่ ไม่ใช่แค่ไม่มี error? - บทที่อธิบายเรื่องนี้: กลุ่ม Versions & providers ใน AI Bug Catalog (entry 1–3) สำหรับการ resolve
.terraform.lock.hclจริงและ warning เรื่อง deprecation ที่มาจาก schema จริง; Installing & Project Structure สำหรับพื้นฐานrequired_providers
2. Backend & state
หัวข้อที่มีชื่อว่า “2. Backend & state”เมื่อ provider ถูก pin แล้ว ตรวจว่าอะไรที่ล็อกและเก็บ state จริงๆ — เพราะ terraform_remote_state และ backend-locking argument ที่ลอยตัวทั้งคู่พังในแบบที่ validate มองไม่เห็นจาก configuration ฝั่งที่อ่านค่าเพียงอย่างเดียว
- สิ่งที่ต้องมองหา: กลไกล็อกของ backend ตรงกับสิ่งที่ Terraform/backend version นี้รองรับจริงหรือไม่ (
use_lockfileของ S3 เทียบกับdynamodb_tableที่ deprecated แล้ว)?terraform_remote_statedata source ทุกตัวชี้ไปที่key/pathที่ apply แล้วจริงหรือไม่? state เคยถูกใช้แยก environment ผ่านterraform workspaceในที่ที่ backend config แยกกันจริงๆ จะปลอดภัยกว่าหรือไม่? - คำถามที่ต้องถาม: ถ้า backend config นี้รัน
initกับ bucket ใหม่เอี่ยมตอนนี้เลย locking จะทำงานจริงหรือไม่ — และถ้า state ที่terraform_remote_stateนี้อ่านยังไม่มีอยู่ plan จะพังดังๆ หรือมีอะไรดำเนินต่อไปเงียบๆ ด้วยค่า default? - บทที่อธิบายเรื่องนี้: กลุ่ม State & backend ใน AI Bug Catalog (entry 4–6) สำหรับ lock file ที่ gitignore แล้วเกิด drift จริง และ “Unable to find remote state” ที่พังหนักจริง; The State File และ Why Terragrunt สำหรับกลไกทั้งสองแบบเจาะลึก
3. Variables & locals
หัวข้อที่มีชื่อว่า “3. Variables & locals”variable block ที่ดูเหมือนแค่ input validation ธรรมดาสามารถเปลี่ยนค่าที่ไปถึง resource จริงได้อย่างเงียบๆ — nullable และ ephemeral ทั้งคู่มีผลต่อพฤติกรรมในแบบที่ไม่มี error message ไหนบอก
- สิ่งที่ต้องมองหา: default ของ
nullable = falsevariable แทนที่ค่าnullที่ส่งมา override อย่างเงียบๆ หรือไม่ โดยไม่มีอะไรใน plan output บอกเลย? variable ที่เป็นephemeralเคยมีdefaultเป็น secret ตรงๆ หรือไม่ — ซึ่งยังรั่วเข้าไปในshow -jsonของ plan ที่ save ไว้ แม้จะไม่เข้า state ก็ตาม? - คำถามที่ต้องถาม: ถ้า variable ตัวนี้ถูกส่ง
nullมาจากผู้เรียกใช้ ค่าจริงจะกลายเป็นnullจริงหรือไม่ — หรือจะกลายเป็น default อย่างเงียบๆ โดย CLI output เหมือนกันทั้งสองแบบ? - บทที่อธิบายเรื่องนี้: กลุ่ม Variables ใน AI Bug Catalog (entry 7–8) สำหรับ output การ apply แบบ
nullableเทียบข้างกันจริง และการรั่วของ ephemeral default เข้าshow -jsonจริง
4. Resources & lifecycle
หัวข้อที่มีชื่อว่า “4. Resources & lifecycle”resource block อาจเป็น HCL ที่ valid สมบูรณ์แบบแต่ยังผิดในแบบที่ปรากฏเฉพาะตอน plan ครั้งถัดไป หรือวันที่ใครสักคนต้องการให้ lifecycle block ทำตามที่ชื่อมันบอกจริงๆ
- สิ่งที่ต้องมองหา: ใช้
countกับ list ที่อาจถูกจัดลำดับใหม่ได้หรือไม่ ในที่ที่for_eachเป็นทางเลือกปลอดภัยทางเดียว?lifecycle { prevent_destroy = true }อยู่บน resource ที่สำคัญจริงหรืออยู่บนอะไรที่ทิ้งได้ใกล้ๆ กัน?for_eachเคยดึง key มาจาก computed attribute ของ resource ที่ managed อีกตัวหรือไม่? มี argument ที่ดู hallucinate มา (copy จาก resource type ที่คล้ายกันแต่ไม่ใช่ตัวเดียวกัน) อยู่ที่ไหนหรือไม่? - คำถามที่ต้องถาม: ถ้าเอา item ตรงกลางออกจาก list นี้ตอนนี้เลย
terraform planจะแสดงการลบ item เดียวสะอาดๆ หรือจะแสดงการแทนที่ไล่ไปตามตำแหน่งที่เลื่อน? และถ้า resource นี้ถูก destroy ตอนนี้เลยprevent_destroyจะบล็อกจริงหรือแค่ดูเหมือนบล็อกจาก error message ของ resource อื่น? - บทที่อธิบายเรื่องนี้: กลุ่ม Resources & lifecycle ใน AI Bug Catalog (entry 9–13) สำหรับ
plan -destroyจริงที่พิสูจน์ว่าprevent_destroyป้องกันเฉพาะ resource ที่ประกาศไว้เท่านั้น และ plan การเลื่อน index ของcountจริง
5. Modules
หัวข้อที่มีชื่อว่า “5. Modules”module call สามารถซ่อน provider configuration หรือ source ที่ไม่ pin ซึ่งกลายเป็นปัญหาก็ต่อเมื่อผู้เรียกใช้ต้องการ count, for_each, หรือ environment ที่สอง
- สิ่งที่ต้องมองหา: module ที่ reusable ประกาศ
providerblock ของตัวเองหรือไม่ ทำให้เข้ากันไม่ได้กับcount/for_each/depends_onฝั่งที่เรียกใช้?sourceแบบgit::/registry ละ?ref=/version constraint หรือไม่ ลอยอยู่บน default branch?depends_onบน module call มีไว้เพื่อปิดบัง cycle ของ reference ที่มีอยู่จริงหรือไม่? - คำถามที่ต้องถาม: source ของ module นี้ resolve ไปที่ commit/version เดียวกันทุกครั้งหรือไม่ ไม่ว่าจะ init จากเครื่องไหน วันไหน — และถ้าผู้เรียกใช้ต้องการ loop module นี้ด้วย
countมันจะทำงานได้หรือไม่? - บทที่อธิบายเรื่องนี้: กลุ่ม Modules ใน AI Bug Catalog (entry 14–15) สำหรับ error “Module is incompatible with count, for_each, and depends_on” จริง และ error ของ reference cycle จริงที่ไม่มี
depends_onใดปิดบังได้; Writing a Reusable Module และ Module Composition & Sources สำหรับกลไกทั้งสองแบบเจาะลึก
6. Terragrunt live tree
หัวข้อที่มีชื่อว่า “6. Terragrunt live tree”ไฟล์ terragrunt.hcl ถูก copy-paste ข้าม environment กันตลอดเวลา — การตรวจว่า copy นั้นเปลี่ยนค่าที่สำคัญจริงหรือไม่เป็นการอ่านที่คุ้มค่าที่สุดในโมดูลนี้ทั้งหมด
- สิ่งที่ต้องมองหา: คำสั่งที่ AI เขียนใช้
run-all/plan-allหรือไม่ — ทั้งคู่ถูกเอาออกใน Terragrunt 1.1 CLI redesign แล้ว? ไฟล์terragrunt.hclของdevและprod(หรือ environment สองตัวไหนก็ตาม) มีค่าaccount_id/region/subscription/project เหมือนกันทุกตัวอักษร ในinputsหรือไม่ ในที่ที่ต้องต่างกันจริง? - คำถามที่ต้องถาม:
terragrunt hcl validateที่ผ่านทั้งสองไฟล์ environment พิสูจน์ได้จริงหรือไม่ว่า deploy ไป account ต่างกัน — หรือพิสูจน์แค่ว่าทั้งคู่เป็น HCL ที่ valid ทาง syntax? - บทที่อธิบายเรื่องนี้: กลุ่ม Terragrunt ใน AI Bug Catalog (entry 16–17) สำหรับการปฏิเสธ “unknown command” จริง และการ copy-paste
dev/prodที่เหมือนกันทุกตัวอักษรจริงซึ่งhcl validateจับไม่ได้; Terragrunt HCL & the Root Config และ The Multi-Environment Problem สำหรับกลไกที่พิสูจน์เต็มรูปแบบ
7. CI & policy
หัวข้อที่มีชื่อว่า “7. CI & policy”สุดท้าย ตรวจว่า pipeline ที่ apply configuration นี้จริงๆ มี approval gate จริง มี policy check จริง และมี dependency ที่เชื่อถือได้หรือไม่ — เพราะทุกขั้นตอนการอ่านก่อนหน้านี้อาจสมบูรณ์แบบแล้วยังหลุดผ่าน pipeline ที่เอา safeguard ตัวเดียวที่สำคัญออกไปได้
- สิ่งที่ต้องมองหา:
-auto-approveรันกับ plan ที่ สดใหม่ หรือกับ plan ที่ save แล้ว review แล้ว? GitHub Action จาก third-party ถูก pin ด้วย commit SHA หรือลอยอยู่บน@master/@main? Rego policy ใช้ syntax ก่อน v1 (deny[msg] { ... }) ที่ load ไม่ผ่านภายใต้ OPA/conftest ปัจจุบันหรือไม่?.tflint.hcl/checkov config อ้างอิง rule ID ที่ไม่มีอยู่จริงใน rule catalog ของ linter นั้นหรือไม่? - คำถามที่ต้องถาม: ถ้า pipeline นี้รันตอนนี้เลย มีจุดไหนระหว่าง “plan” กับ “การเปลี่ยนแปลง infrastructure จริง” ที่มนุษย์หรือ policy gate จะหยุดมันได้จริงหรือไม่ — และทุก check ใน pipeline นี้รันจริงพิสูจน์ได้หรือไม่ หรือมีตัวไหนเงียบๆ ไม่ทำอะไรเลย?
- บทที่อธิบายเรื่องนี้: กลุ่ม CI & policy ใน AI Bug Catalog (entry 18–21) สำหรับ proof การ
-auto-approveเทียบข้างกันจริง, error parse ของ Rego v1 จริง, และการรัน tflint จริงที่ rule ที่ hallucinate มาเช็คอะไรไม่ได้เลยอย่างเงียบๆ; Verification Tools สำหรับทุกเครื่องมือในรายการนี้ที่รันจริง
สิ่งที่โมดูลนี้ครอบคลุมต่อไป
หัวข้อที่มีชื่อว่า “สิ่งที่โมดูลนี้ครอบคลุมต่อไป”- AI Bug Catalog — 23 pattern เฉพาะเจาะจง แต่ละอันมี configuration ที่ AI มักเขียน, output จริงจาก
validate/plan/test/terragrunt/tflint/checkov/conftest, และวิธีแก้ - Review Checklist — 23 pattern เดียวกันในรูปแบบ checklist หน้าเดียว 8 กลุ่ม แต่ละบรรทัดลิงก์ไปยังบทที่พิสูจน์มัน
- Verification Tools —
terraform fmt -check,validate,plan -detailed-exitcode,show -json+jq,terraform testกับmock_provider, tflint, checkov, conftest,terragrunt hcl validate/render/run --all plan, และ harness ของคอร์สนี้เองแต่ละตัวพิสูจน์อะไรได้จริงบ้าง - Worked review สามบท — Worked Review 1, Worked Review 2, Worked Review 3 — นำลำดับการอ่านนี้ไปใช้กับชุด configuration ที่ AI สร้างเต็มรูปแบบ (module network+compute, Terragrunt live tree แบบ multi-environment, และ CI pipeline พร้อม policy check) ทั้งสามบทนี้เขียนและดูแลแยกจากบทนี้ — ถ้าลิงก์ด้านล่าง 404 ระหว่างที่งานนั้นยังไม่เสร็จ ลำดับการอ่านและ catalog ข้างบนยังยืนได้ด้วยตัวเอง
Mental Model
หัวข้อที่มีชื่อว่า “Mental Model”ลำดับการอ่าน Terraform/Terragrunt ที่ไม่ได้เขียนเอง:
1. Providers & versions → pin ด้วย ~> แล้วหรือยัง? commit lock file แล้วหรือยัง? มี deprecated arg ไหม?2. Backend & state → กลไกล็อกจริงหรือ? remote_state ชี้ไปที่ state ที่ apply แล้วหรือไม่?3. Variables & locals → nullable/ephemeral ทำงานตามชื่อจริงหรือไม่?4. Resources & lifecycle → count ในที่ที่ควรเป็น for_each หรือไม่? prevent_destroy ป้องกันอะไรจริงๆ?5. Modules → มี provider block ข้างในไหม? pin source แล้วหรือยัง? depends_on ซ่อน cycle อยู่ไหม?6. Terragrunt live tree → run --all ไม่ใช่ run-all/plan-all? dev กับ prod ต่างกันจริงหรือไม่?7. CI & policy → -auto-approve บน plan สดๆ? pin action แล้ว? syntax policy ทันสมัยหรือไม่?
"terraform validate และ plan ผ่านสะอาดทั้งคู่" ตอบคำถามเหล่านี้ได้แทบไม่ได้เลย — catalog 23 entryของโมดูลนี้ส่วนใหญ่คือ configuration ที่ schema valid, plan สะอาด แต่ผิดตรงๆ เฉยๆCommon Misconceptions
หัวข้อที่มีชื่อว่า “Common Misconceptions”- “ถ้า
validateกับplanผ่านทั้งคู่ แปลว่าถูกต้อง” พิสูจน์ตลอด catalog ของโมดูลนี้แล้วว่า จาก 23 pattern มีแค่ไม่กี่อันเท่านั้นที่validate/plan/terragruntปฏิเสธตรงๆ ที่เหลือเป็น HCL ที่ valid ทั้ง syntax และ semantic ซึ่ง Terraform ไม่มีทางตั้ง flag ได้ เพราะไม่มีอะไรในภาษาที่บอกความต่างระหว่าง “ป้องกัน resource ผิดตัว” กับ “resource ถูกป้องกันอยู่” - “Terraform ที่ AI สร้างแค่ต้องการ prompt ใหม่กว่านี้” ปัญหาไม่ใช่แค่ความล้าสมัย —
dynamodb_tableและterragrunt run-allคือ configuration ที่ valid ทาง syntax และดูลื่นไหลโดยเฉพาะ ซึ่งบังเอิญเล็งไปที่รูปแบบที่ provider/CLI version ปัจจุบันเลยผ่านไปแล้ว บางทีก็มี warning บางทีก็ไม่มีเลย - “ความล้มเหลวแบบเงียบๆ หายากกว่า
applyที่ถูกปฏิเสธ เลยสำคัญน้อยกว่า” ในทางตรงกันข้ามต่างหากที่ใกล้ความจริงกว่าใน catalog นี้ —prevent_destroyบน resource ผิดตัว, ชื่อ rule ใน.tflint.hclที่เช็คอะไรไม่ได้เลยอย่างเงียบๆ, หรือprodที่ deploy ทับaccount_idของdevทั้งหมดนี้ผ่านไปได้โดยไม่มี error ไม่มี warning ไม่มีสัญญาณอะไรผิดปกติเลย — จนถึงจุดที่มีบางอย่างขึ้นอยู่กับพฤติกรรมที่ผิดนั้นพอดี - “
-auto-approveเป็นแค่ความสะดวกของ CI สำหรับข้าม prompt” มันเอาจุดเดียวในทั้ง pipeline ที่ plan ที่ save และ review แล้วจะถูกตรวจกับความจริงก่อนมีอะไรเปลี่ยนแปลงจริงออกไป — ทางแก้คือแยกขั้นตอนplan -out+ policy gate +apply <planfile>ไม่ใช่แค่ยอมรับ flag นี้เพราะ CI พิมพ์yesไม่ได้