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 ไม่ได้ตายตัวเหมือน local relative path ถ้า module block ไม่มี version constraint การรัน terraform init -upgrade — หรือแม้แต่ init ครั้งแรกใน CI pipeline ที่ยังไม่เคยรันมาก่อน — ก็สามารถดึง version ใหม่กว่าของ module นั้นเข้ามาได้ โดยไม่มีใครได้อ่าน changelog ก่อนเลย การ upgrade ที่ดูเหมือนเล็กน้อยอาจ rename variable, เปลี่ยนค่า default หรือปรับโครงสร้าง resource ที่สร้างขึ้น และทั้งหมดนี้จะไม่โผล่ให้เห็นจนกว่า plan หรือ apply จะเริ่มทำงานต่างจากเมื่อวาน
# unpinned - always resolves to the latest version on init -upgrademodule "vpc" { source = "terraform-aws-modules/vpc/aws"}นี่คือ 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 "vpc" { source = "terraform-aws-modules/vpc/aws" 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 change คุณยังเป็นคนเลือกเองว่าจะกระโดดตอนไหน และอ่าน changelog ของ module ก่อนได้เสมอ
private module source กับการ publish module ของตัวเอง
หัวข้อที่มีชื่อว่า “private module source กับการ publish module ของตัวเอง”ไม่ใช่ทุก module ที่ควรอยู่บน public Registry module ที่เข้ารหัส networking layout, naming convention หรือ compliance requirement เฉพาะของบริษัทหนึ่ง ไม่ควรถูก publish ให้คนทั้งโลกเห็น สำหรับกรณีนี้ องค์กรมักใช้ private Git repository หรือ private module registry — private registry ของ HCP Terraform หรือตัวที่ self-host เอง — เพื่อให้ 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/aws" version = "~> 2.1"}ถ้าคุณต้องการ publish module ของตัวเองแบบ public จริง ๆ public Terraform Registry คาดหวัง naming convention ของ repository แบบเฉพาะ คือ terraform-<PROVIDER>-<NAME> เช่น terraform-aws-vpc Registry ใช้ชื่อนี้ในการแยกว่า 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