Module คือกลไกหลักของ Terraform สำหรับรวบรวม resource หลายตัวที่ใช้งานร่วมกันให้กลายเป็นหน่วยเดียวที่สามารถเรียกใช้ซ้ำได้ทุก environment เปรียบได้กับฟังก์ชันใน programming หรือ package ที่ทีมอื่นสามารถ import ไปใช้ได้ การเขียน configuration แบบ module-based จะช่วยลดโค้ดซ้ำ เพิ่มความสม่ำเสมอของ infrastructure ทั่วองค์กร และทำให้การทดสอบเกิดขึ้นในระดับ component ได้
บทความนี้จะอธิบายแนวคิดของ module ประเภทต่าง ๆ, การเรียกใช้ module จาก local path, Git และ Terraform Registry, และข้อควรระวังเรื่อง version pinning
Module คืออะไร
Module คือชุดของไฟล์ .tf ที่อยู่ใน directory เดียวกัน ทุก configuration ของ Terraform ที่เขียนใน directory ปัจจุบันเองก็ถือเป็น “root module” อยู่แล้ว แต่เมื่อพูดถึง module โดยทั่วไปมักหมายถึง “child module” ที่ถูก root module เรียกใช้
- Root module — directory ที่รัน
terraformคำสั่งอยู่ - Child module — module ที่ถูกเรียกผ่าน block
module - Published module — module ที่ publish ไปยัง Terraform Registry หรือ Git repo สาธารณะ
เรียกใช้ Module จาก Local Path
วิธีเริ่มต้นที่ง่ายที่สุดคือแยก module ออกเป็น subdirectory ภายในโปรเจกต์ แล้วเรียกผ่าน relative path
# โครงสร้างโปรเจกต์
my-project/
├── main.tf # root module
├── variables.tf
└── modules/
└── vpc/
├── main.tf
├── variables.tf
└── outputs.tf
# main.tf (root)
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
az_count = 3
tags = {
Environment = "production"
}
}
resource "aws_instance" "web" {
subnet_id = module.vpc.public_subnet_ids[0]
}
เรียก Module จาก Git หรือ GitHub
Terraform รองรับ source ที่เป็น Git repository โดยตรง เหมาะเมื่อ module ถูกใช้ร่วมกันหลายโปรเจกต์ในทีมเดียว การ pin ด้วย tag หรือ commit hash เป็นสิ่งที่ควรทำเสมอ เพื่อให้ผลของ apply คงที่
module "database" {
source = "git::https://github.com/mycompany/tf-modules.git//database?ref=v1.2.0"
engine = "postgres"
version = "15.4"
multi_az = true
}
module "network" {
source = "[email protected]:mycompany/tf-modules.git//network?ref=main"
}
Terraform Registry
Registry ของ HashiCorp เก็บ module สำเร็จรูปจากหลายบริษัทและ community โดยเฉพาะ provider ใหญ่ ๆ เช่น AWS, Azure, Google Cloud ก็มี module มาตรฐานให้เลือกใช้ วิธีอ้างอิงคือ NAMESPACE/NAME/PROVIDER
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-southeast-1a", "ap-southeast-1b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
}
Version Constraint
การล็อก version ของ module ป้องกันการเปลี่ยนแปลงที่ไม่คาดคิดเมื่อ module publish feature ใหม่ รูปแบบที่ใช้บ่อยคือ
version = "5.1.0"— ใช้เวอร์ชัน 5.1.0 เท่านั้นversion = "~> 5.0"— อนุญาต 5.x แต่ไม่ข้ามไป 6.xversion = ">= 4.0, < 6.0"— ระบุช่วง- Git source: pin ด้วย
?ref=v1.0.0หรือ commit hash
ข้อดีของการใช้ Module
- ลด copy-paste code ระหว่าง environment (dev/stage/prod)
- รวม best practice ของ resource หลายตัวไว้จุดเดียว
- คนในทีมไม่ต้องรู้ internal ของ module เพียง input/output เพียงพอ
- ทดสอบ component ได้โดยไม่ต้อง deploy stack ทั้งระบบ
- Upgrade ได้ทีเดียวทั้งโปรเจกต์ผ่านการเปลี่ยน version
สรุป
Module คือวิธีทำให้ Terraform scalable พอรองรับระบบขนาดใหญ่ การเริ่มต้นง่าย ๆ คือแยก logic ออกเป็น subdirectory ภายในโปรเจกต์ก่อน จากนั้นเมื่อ module มีค่าพอจะใช้ร่วมหลายโปรเจกต์ ค่อยย้ายไปยัง Git repository แยก พร้อม pin version ให้ชัดเจน Registry ของ HashiCorp เป็นแหล่งที่ดีสำหรับเริ่มต้นโดยไม่ต้องเขียนเอง บทความถัดไปจะลงลึกการสร้าง module จาก scratch ตั้งแต่ directory structure, input/output convention และ naming pattern

