Module Versioning and Registries
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”module source ที่ไม่ pin version สามารถ resolve ไปเป็น version ใหม่กว่าเดิมแบบเงียบ ๆ ในครั้งถัดไปที่มีคนรัน init ดังนั้นการ pin version constraint คือวินัยเดียวกับที่คุณใช้กับ provider lock file อยู่แล้ว เพียงแต่เล็งไปที่ module code แทนที่จะเป็น provider code
ทำไม module version ที่ไม่ pin ถึงเป็นความเสี่ยงแบบเงียบ ๆ
หัวข้อที่มีชื่อว่า “ทำไม module version ที่ไม่ pin ถึงเป็นความเสี่ยงแบบเงียบ ๆ”module ที่มาจาก Registry หรือ Git tag ไม่ได้ถูก freeze ไว้กับที่เหมือน local relative path ถ้า module block ไม่มี version constraint การรัน terraform init -upgrade — หรือแม้แต่ init ใหม่ใน CI pipeline ที่ไม่เคยรันมาก่อน — สามารถดึง release ใหม่กว่าของ module นั้นเข้ามาโดยไม่มีใคร review changelog ก่อน upgrade ที่ดูเหมือนเล็กน้อยสามารถเปลี่ยนชื่อ variable เปลี่ยน default หรือปรับโครงสร้าง resource ที่สร้างขึ้นใหม่ทั้งหมด และไม่มีอะไรแสดงให้เห็นจนกว่า plan หรือ apply จะเริ่มทำงานต่างจากเมื่อวาน
# unpinned - always resolves to the latest version on init -upgrademodule "vnet" { source = "Azure/vnet/azurerm"}นี่คือ failure mode เดียวกันเป๊ะกับที่ provider lock file มีไว้เพื่อป้องกัน แค่ขยับขึ้นไปอีกระดับหนึ่ง: แทนที่จะเป็น provider plugin ที่เปลี่ยนไปโดยที่คุณไม่รู้ตัว กลายเป็น implementation ภายในของ module เองที่เปลี่ยนไปโดยที่คุณไม่รู้ตัวแทน
pessimistic constraint operator: version = ”~> 5.0”
หัวข้อที่มีชื่อว่า “pessimistic constraint operator: version = ”~> 5.0””การ pin module จาก Registry หรือ Git tag ด้วย version argument แก้ปัญหานี้ได้ pattern ที่ใช้กันทั่วไปคือ pessimistic constraint operator, ~>:
# pinned - allows 5.x patch and minor upgrades, blocks a 6.0 major bumpmodule "vnet" { source = "Azure/vnet/azurerm" version = "~> 5.0"}~> 5.0 แปลว่า “อนุญาต version ใด ๆ ที่มากกว่าหรือเท่ากับ 5.0 จนถึงแต่ไม่รวม 6.0” พูดอีกแบบคือ ยอมให้ Terraform รับ patch และ minor release ภายในสาย 5.x ได้ — bug fix กับของใหม่ที่ backward-compatible — แต่ปฏิเสธการกระโดดไป 6.0 แบบเงียบ ๆ เพราะ major version bump คือสัญญาณที่ผู้สร้าง module บอกคุณว่าให้เตรียมรับ breaking changes คุณยังเป็นคนเลือกเองว่าจะกระโดดตอนไหน และอ่าน changelog ของ module ก่อนได้
private module source และการ publish module ของตัวเอง
หัวข้อที่มีชื่อว่า “private module source และการ publish module ของตัวเอง”ไม่ใช่ทุก module ที่ควรอยู่บน public Registry module ที่ encode networking layout, naming convention หรือ compliance requirement เฉพาะขององค์กรหนึ่งไม่ควรถูก publish ให้คนทั้งโลกเห็น สำหรับกรณีแบบนี้ องค์กรมักใช้ private Git repository หรือ private module registry — private registry ของ HCP Terraform หรือของที่ self-hosted เอง — เพื่อให้ module ยังมี version และค้นหาได้ภายในองค์กร โดยไม่ต้องกลายเป็น public
# private Git repositorymodule "internal_networking" {}
# private module registry (e.g. HCP Terraform)module "internal_networking" { source = "app.terraform.io/acme-corp/networking/azurerm" version = "~> 2.1"}ถ้าคุณต้องการ publish module ออกสู่สาธารณะ public Terraform Registry ต้องการ repository naming convention เฉพาะแบบนี้: terraform-<PROVIDER>-<NAME> เช่น terraform-azurerm-vnet Registry parse ชื่อนี้เพื่อดูว่า module เล็งไปที่ provider ไหนและควรเรียกว่าอะไร ดังนั้น repository ที่ไม่ตาม pattern นี้จะ publish ไม่สำเร็จ
flowchart TB
subgraph pinned["Pinned version"]
p1["version = ~> 5.0"] --> p2["terraform init always resolves within 5.x"]
end
subgraph unpinned["Unpinned version"]
u1["no version constraint"] --> u2["terraform init -upgrade may resolve 6.0"]
u2 --> u3["breaking changes applied without changelog review"]
end