DevOps
น้องๆ เคยเจอปัญหาเขียน Terraform ซ้ำๆ กันไหม? สมัยผมทำร้านเน็ต SiamCafe นะ เขียนสคริปต์ติดตั้งเกมส์ ติดตั้งโปรแกรมทีนึง โค้ดก็ยาวเหยียด แถมยังต้องมานั่งแก้ทีละจุดอีก ถ้ามีอะไรผิดพลาดขึ้นมา โอ้โห ปวดหัวเลย! Terraform Modules ก็เหมือนกัน ถ้าไม่จัดการให้ดี โค้ดจะรก แก้ไขยาก แถมยังเสี่ยงต่อความผิดพลาดด้วย
Best practices ก็คือแนวทางปฏิบัติที่ดีที่สุดที่เราควรรู้ เพื่อให้การจัดการ Terraform ของเราเป็นระเบียบ ใช้งานง่าย และลดความเสี่ยงในการเกิดข้อผิดพลาดนั่นเอง คิดง่ายๆ เหมือนเรามีสูตรทำอาหารที่อร่อยและทำซ้ำได้ทุกครั้งน่ะแหละ
Terraform เป็นเครื่องมือ Infrastructure as Code (IaC) ที่ช่วยให้เราจัดการ infrastructure ของเราได้ด้วยโค้ด ไม่ว่าจะเป็น cloud resources (AWS, Azure, GCP) หรือ on-premise resources เราสามารถ define infrastructure ของเราเป็นโค้ด แล้ว Terraform จะจัดการสร้าง, แก้ไข, และลบ resources เหล่านั้นให้เอง
สมัยก่อนตอนเปิดร้าน SiamCafe ใหม่ๆ นะ กว่าจะ setup Server แต่ละเครื่องนี่ลำบากมาก ต้องลง OS เอง, ติดตั้งโปรแกรมเอง, config เองทุกอย่าง แต่ถ้ามี Terraform นี่ชีวิตง่ายขึ้นเยอะ!
Module คือ container สำหรับหลายๆ Terraform resources ที่ถูกใช้ร่วมกัน พูดง่ายๆ ก็คือกลุ่มของโค้ด Terraform ที่เราเอามา repackage ใหม่ เพื่อให้ reuse ได้ง่ายขึ้น Module สามารถประกอบไปด้วย variables, resources, outputs และ modules อื่นๆ ได้อีกด้วย
คิดซะว่า Module คือ function ในภาษาโปรแกรมที่เราคุ้นเคยนั่นแหละ รับ input (variables), ทำงานบางอย่าง (resources), แล้ว return output ออกมา
# ตัวอย่าง module
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "3.0.0"
NAME = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
tags = {
Terraform = "true"
Environment = "dev"
}
}
การใช้งาน Module หลักๆ มี 2 แบบ คือ
สำหรับมือใหม่ ผมแนะนำให้เริ่มจาก Public Modules ก่อน เพราะใช้งานง่าย และมี documentation ให้ศึกษาเยอะแยะ SiamCafe Blog ก็มีบทความแนะนำเรื่องนี้อยู่เหมือนกัน ลองไปอ่านดูนะ
ก่อนอื่นเราต้องหา Module ที่ตอบโจทย์ความต้องการของเราก่อน เช่น ถ้าเราต้องการสร้าง VPC บน AWS เราก็สามารถค้นหา Module ที่ชื่อว่า "vpc" บน Terraform Registry ได้เลย
สิ่งที่ต้องพิจารณาคือ
หลังจากเลือก Module ได้แล้ว เราก็ต้อง config Module ให้ตรงกับความต้องการของเรา โดยการกำหนดค่า variables ต่างๆ ที่ Module นั้นๆ ต้องการ
# ตัวอย่างการ config module
module "my_instance" {
source = "hashicorp/aws/ec2"
version = "4.0.0"
ami = "ami-0c55b36c0269d454e"
instance_type = "t2.micro"
key_name = "my-keypair"
subnet_id = "subnet-0bb1c79de3EXAMPLE"
vpc_security_group_ids = ["sg-0e59c34b6eEXAMPLE"]
tags = {
Name = "My EC2 Instance"
}
}
ในตัวอย่างข้างบน เรากำลัง config Module ที่ชื่อ "hashicorp/aws/ec2" เพื่อสร้าง EC2 instance บน AWS โดยเรากำหนดค่า variables ต่างๆ เช่น AMI, instance type, key pair, subnet ID และ security group ID
Module สามารถ return output ได้ ซึ่ง output เหล่านี้เราสามารถนำไปใช้ต่อใน module อื่นๆ หรือใน Terraform configuration ของเราได้
# ตัวอย่างการ output จาก module
output "instance_id" {
description = "The ID of the EC2 instance"
value = module.my_instance.id
}
ในตัวอย่างข้างบน เรากำลัง output ค่า ID ของ EC2 instance ที่สร้างโดย module "my_instance" เราสามารถเข้าถึงค่านี้ได้โดยใช้ `module.my_instance.id`
ดูวิดีโอเพิ่มเติมเกี่ยวกับTerraform Modules Best Practic:
นอกจาก Terraform Modules แล้ว ยังมีทางเลือกอื่นๆ ในการจัดการ Infrastructure as Code เช่น:
ลองมาดูตารางเปรียบเทียบข้อดีข้อเสียของแต่ละทางเลือกกัน
| ทางเลือก | ข้อดี | ข้อเสีย |
|---|---|---|
| Terraform Modules | Reuse code, maintainability, consistency, collaboration | ต้องเรียนรู้ concept ใหม่ |
| Writing from scratch | ควบคุมได้ทุกอย่าง | เสียเวลาเยอะ, โอกาสเกิดข้อผิดพลาดสูง |
| Copy-pasting | รวดเร็ว | Code รก, แก้ไขยาก, เสี่ยงต่อความผิดพลาด |
| Shell scripts | ยืดหยุ่น | จัดการยาก, ไม่ scalable, security concerns |
จากตารางจะเห็นว่า Terraform Modules เป็นทางเลือกที่ดีที่สุดในแง่ของ reuse code, maintainability, consistency, และ collaboration ถึงแม้ว่าต้องใช้เวลาเรียนรู้ concept ใหม่ แต่คุ้มค่าในระยะยาวแน่นอน
ยังไงลองเข้าไปอ่านบทความเพิ่มเติมที่ SiamCafe Blog ได้นะ มีเรื่อง DevOps อีกเยอะเลย
เอาล่ะน้องๆ มาถึงส่วนที่สำคัญที่สุดแล้ว นั่นคือ best practices หรือเคล็ดลับที่พี่บอมสั่งสมมาตลอด 28+ ปีในวงการ IT โดยเฉพาะเรื่อง Terraform Modules เนี่ย บอกเลยว่าลองผิดลองถูกมาเยอะ เจ็บมาเยอะ กว่าจะตกผลึกเป็นวิธีที่ใช้ได้จริง
สมัยผมทำร้านเน็ต SiamCafe เนี่ย (ตั้งแต่ปี 1997 นู่น) เรื่อง automation ยังไม่บูมเท่าสมัยนี้หรอก แต่เราก็พยายามหาทางทำให้ชีวิตมันง่ายขึ้นอยู่เสมอ หลักการเดียวกันเลย คือทำยังไงให้ deploy ระบบใหม่ๆ ได้เร็ว ลดความผิดพลาด และ maintain ง่าย
เรื่อง versioning นี่สำคัญสุดๆ เหมือนเราเขียนโปรแกรมแล้วต้องเก็บ version control นั่นแหละ Terraform Modules ก็เหมือนกัน ต้องมี version ชัดเจน จะใช้ Git tags ก็ได้ หรือจะใช้เลข version แบบ semantic versioning (v1.0.0, v1.1.0, v2.0.0) ก็ได้ แล้วแต่ความถนัด
เคยเจอเคสที่ลูกค้าเรียกใช้ module แล้วดันไปแก้ module กลาง (โดยไม่รู้ตัว) พอ deploy ครั้งต่อไประบบรวนไปหมด เพราะ code เปลี่ยน version เปลี่ยน วิธีแก้คือบังคับให้เรียกใช้ module ผ่าน version ที่ระบุเท่านั้น
module "my_module" {
source = "github.com/my-org/my-module"
version = "v1.2.3" # ระบุ version ให้ชัดเจน!
...
}
Module ที่ดีต้องมีการตรวจสอบ input ที่ส่งเข้ามา ว่ามันถูกต้องตามที่เราต้องการหรือไม่ เช่น ถ้าเราต้องการให้รับค่าเป็นตัวเลข ก็ต้องเช็คว่าเป็นตัวเลขจริงๆ ไม่ใช่ตัวหนังสือ หรือถ้าต้องการให้รับค่าเป็น enum ก็ต้องเช็คว่าค่าที่ส่งมาอยู่ใน enum นั้นจริงๆ
สมัยก่อนผมเคยเจอเคสที่ลูกค้าส่งค่าผิดประเภทมาให้ module แล้วระบบ error แบบงงๆ กว่าจะแก้ได้เสียเวลาไปเยอะมาก ตั้งแต่นั้นมาเลยเน้นเรื่อง input validation เป็นพิเศษ
variable "instance_type" {
type = string
description = "The type of EC2 instance to create."
validation {
condition = contains(["t2.micro", "t2.small", "t2.medium"], var.instance_type)
error_message = "Invalid instance type. Must be one of t2.micro, t2.small, or t2.medium."
}
}
Module ที่ดีต้อง output ค่าที่จำเป็นออกมาให้หมด เพื่อให้ module อื่นๆ หรือ application อื่นๆ สามารถนำค่าเหล่านี้ไปใช้ต่อได้ เช่น instance ID, public IP address, DNS name อะไรพวกนี้
บางทีเราขี้เกียจ output ทุกอย่าง แต่สุดท้ายต้องกลับมาแก้ module เพิ่มเติม เพราะขาดข้อมูลที่จำเป็นไป เสียเวลาเปล่าๆ output ไปเลยดีกว่า
output "instance_id" {
value = aws_instance.example.id
description = "The ID of the EC2 instance."
}
output "public_ip" {
value = aws_instance.example.public_ip
description = "The public IP address of the EC2 instance."
}
พยายามทำให้ module มัน simple ที่สุด เท่าที่จะทำได้ อย่าใส่ logic ที่ซับซ้อนมากเกินไป ถ้า module มันซับซ้อนมากเกินไป จะทำให้ maintain ยาก และ debug ยาก
เคยเห็น module ที่มันทำทุกอย่างตั้งแต่ต้นจนจบ สุดท้ายแก้ทีนึงกระทบไปหมดทั้งระบบ module ที่ดีควรจะ focus แค่เรื่องเดียวเท่านั้น
เพราะมันช่วยให้เรา reuse code ได้ ลดความซ้ำซ้อน ลดความผิดพลาด และทำให้ infrastructure as code ของเราเป็นระเบียบมากขึ้น เหมือนเราสร้างบ้าน ถ้าเรามี template ของห้องแต่ละแบบ เราก็ไม่ต้องมานั่งออกแบบห้องใหม่ทุกครั้ง
Module ที่ดีควรจะเล็กพอที่จะ manage ได้ง่าย แต่ก็ไม่เล็กจนเกินไปจนต้องสร้าง module จำนวนมาก Module ควรจะ focus แค่เรื่องเดียวเท่านั้น
ใช้ได้ แต่ต้องระวัง เลือกใช้ module ที่มีคนใช้เยอะๆ และมีการ maintain อย่างสม่ำเสมอ อย่าใช้ module ที่ไม่มีคนดูแล เพราะอาจจะมีปัญหา security หรือปัญหาอื่นๆ ตามมาได้
เริ่มจากสิ่งที่เราทำซ้ำๆ บ่อยๆ ก่อน เช่น สร้าง EC2 instance, สร้าง S3 bucket, สร้าง VPC แล้วค่อยๆ extract code ที่เราเขียนซ้ำๆ เหล่านั้นออกมาเป็น module
Terraform Modules เป็นเครื่องมือที่มีประโยชน์มากๆ ในการจัดการ infrastructure as code แต่ต้องใช้ให้ถูกวิธี หวังว่า best practices และเคล็ดลับที่พี่บอมเล่าให้ฟังในวันนี้ จะเป็นประโยชน์กับน้องๆ นะครับ ลองเอาไปปรับใช้กันดู แล้วชีวิตจะง่ายขึ้นเยอะเลย
อย่าลืมแวะไปอ่านบทความอื่นๆ ใน SiamCafe Blog นะครับ มีเรื่อง IT ดีๆ อีกเยอะเลย แล้วก็ถ้าสนใจเรื่อง Forex ลองดู iCafeForex ด้วยนะจ๊ะ