Module Composition and Sources
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”source argument บน module block บอก Terraform ว่าจะไปเอา code ของ module นั้นมาจากไหน และ infrastructure จริงที่ไม่เล็กเกิดจากการเอา module เล็ก ๆ หลายตัวมาประกอบกัน — output ของ module หนึ่งถูกส่งตรงเข้าไปเป็น input variable ของอีก module หนึ่ง
source มาจากไหนบ้าง
หัวข้อที่มีชื่อว่า “source มาจากไหนบ้าง”ทุก module block ต้องมี source และมีสามแบบหลักที่คุณจะเจอบ่อยมาก local relative path ชี้ไปที่ directory ภายใน repository ของคุณเอง public Terraform Registry resolve address สั้น ๆ แบบ <namespace>/<name>/<provider> ไปเป็น module ที่ publish ไว้และมี version Git URL ชี้ตรงไปที่ repository โดยจะ pin ไว้ที่ tag, branch หรือ commit ไหนก็ได้ผ่าน ?ref=
# local relative pathmodule "bucket" { source = "./modules/s3-bucket"}
# public Terraform Registrymodule "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0"}
# Git URL pinned to a specific tagmodule "vpc_from_git" { source = "git::https://github.com/acme/terraform-modules.git//vpc?ref=v1.4.0"}ทั้งสามแบบคือคำตอบที่ต่างกันของคำถามเดียวกัน คือ Terraform จะไปเอาไฟล์ .tf ของ child module นี้มาจากไหน ไม่มีอะไรในวิธีเขียน variables.tf, main.tf หรือ outputs.tf ข้างใน module ที่ต้องเปลี่ยนตาม source แบบไหนที่ caller เลือกใช้
ประกอบ module: output ของตัวหนึ่งกลายเป็น input ของอีกตัว
หัวข้อที่มีชื่อว่า “ประกอบ module: output ของตัวหนึ่งกลายเป็น input ของอีกตัว”configuration แบบแบนราบตัวเดียวที่มี resource เป็นร้อยตัวนั้นอ่านยากและ reuse ไม่ได้เลย infrastructure จริงถูกสร้างจาก module เล็ก ๆ ที่ focus งานเดียว แล้วต่อกันผ่าน output กับ input vpc module หนึ่งเปิด identifier ที่ module อื่นต้องการ
output "vpc_id" { description = "ID of the created VPC" value = aws_vpc.this.id}
output "private_subnet_ids" { description = "IDs of the private subnets" value = aws_subnet.private[*].id}ec2-instance module ประกาศ input ที่ต้องการเพื่อ launch เข้าไปใน network นั้น
variable "vpc_id" { description = "ID of the VPC to launch the instance into" type = string}
variable "subnet_id" { description = "ID of the subnet to launch the instance into" type = string}root configuration คือจุดที่ต่อทั้งสอง module เข้าด้วยกันจริง โดยส่ง output ของ module หนึ่งตรงเข้าไปเป็น input ของอีก module หนึ่ง
# root main.tfmodule "vpc" { source = "./modules/vpc" cidr_block = "10.0.0.0/16"}
module "web_server" { source = "./modules/ec2-instance"
vpc_id = module.vpc.vpc_id subnet_id = module.vpc.private_subnet_ids[0]}ทั้งสอง module ไม่จำเป็นต้องรู้จักกันเลย vpc module ไม่รู้ด้วยซ้ำว่าจะมี ec2-instance module มา consume output ของตัวเองในอนาคต และ ec2-instance module ก็ไม่รู้ว่า vpc_id ที่ได้รับมาจาก module หรือแค่ string ที่ hardcode ไว้ root configuration เป็นจุดเดียวที่รู้จักทั้งสอง module และเป็นคนเชื่อมทั้งสองเข้าด้วยกัน
public Terraform Registry คือตัวเร่ง productivity ตัวจริง
หัวข้อที่มีชื่อว่า “public Terraform Registry คือตัวเร่ง productivity ตัวจริง”pattern ทั่วไปอย่าง “VPC ที่มี public/private subnet” ถูกแก้ปัญหามาแล้วหลายรอบ public Terraform Registry มี community module ที่ดูแลดีและถูกใช้กันแพร่หลาย — terraform-aws-modules/vpc/aws เป็นหนึ่งในจุดเริ่มต้นที่พบบ่อยที่สุดสำหรับ AWS networking — และการหยิบตัวนี้มาใช้มักคุ้มค่ากับเวลาของคุณมากกว่าการเขียนสิ่งเดียวกันขึ้นมาเองตั้งแต่ศูนย์
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "~> 5.0"
name = "acme-app-vpc" cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-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"]}อย่างไรก็ตาม “ใช้กันแพร่หลาย” ไม่เหมือนกับ “เชื่อได้แบบไม่ต้องตรวจ” ก่อนสร้าง production infrastructure บน Registry module ตัวไหน ควรอ่านให้แน่ใจว่า module นั้น create อะไรจริง ๆ บ้าง — resource, ค่า default และ IAM permission ที่สร้างในนามคุณ Registry module ก็ยังเป็น code ของคนอื่นที่รันด้วย AWS credential ของคุณอยู่ดี
flowchart LR
subgraph root["Root configuration"]
vpcmod["module vpc"]
ec2mod["module web_server"]
end
subgraph vpc["Child module: vpc"]
vpcout1["output vpc_id"]
vpcout2["output private_subnet_ids"]
end
subgraph ec2["Child module: ec2-instance"]
ec2in1["var.vpc_id"]
ec2in2["var.subnet_id"]
end
vpcmod --> vpcout1
vpcmod --> vpcout2
vpcout1 -->|module.vpc.vpc_id| ec2in1
vpcout2 -->|module.vpc.private_subnet_ids[0]| ec2in2
ec2in1 --> ec2mod
ec2in2 --> ec2mod