
ในโลกของการพัฒนาซอฟต์แวร์และการจัดการโครงสร้างพื้นฐานยุคใหม่ ความเร็ว ความแม่นยำ และความสามารถในการปรับขนาดคือหัวใจสำคัญของการดำเนินงาน ไม่ว่าคุณจะเป็นผู้ดูแลระบบ, DevOps Engineer หรือนักพัฒนาซอฟต์แวร์ การจัดการ Cloud Infrastructure แบบเดิมๆ ด้วยการคลิกผ่านหน้าเว็บคอนโซลอาจกลายเป็นอุปสรรคที่ทำให้กระบวนการช้าลง เกิดข้อผิดพลาดได้ง่าย และยากต่อการทำซ้ำหรือขยายขนาดครับ ลองจินตนาการถึงการตั้งค่า VPC, Subnets, EC2 Instances, Load Balancers, และฐานข้อมูล RDS จำนวนมากด้วยมือดูสิครับ แค่คิดก็เหนื่อยแล้วใช่ไหมครับ?
แต่ไม่ต้องกังวลไปครับ! บทความนี้จะพาคุณดำดิ่งสู่โลกของ Terraform Infrastructure as Code (IaC) ซึ่งเป็นเครื่องมือที่ทรงพลังและได้รับความนิยมอย่างสูง สำหรับการจัดการ Cloud Infrastructure บน AWS (Amazon Web Services) ได้อย่างมีประสิทธิภาพและเป็นระบบ เราจะมาดูกันว่า Terraform คืออะไร ทำไมมันถึงสำคัญ และจะนำไปใช้งานจริงบน AWS ได้อย่างไร ตั้งแต่พื้นฐานไปจนถึงตัวอย่างการใช้งานที่ซับซ้อนขึ้น เพื่อให้คุณสามารถนำความรู้เหล่านี้ไปปรับใช้กับการทำงานจริงได้อย่างมั่นใจครับ
สารบัญ
- ทำความรู้จัก Infrastructure as Code (IaC) และ Terraform
- แนวคิดหลักของ Terraform ที่ควรรู้
- เตรียมความพร้อม: ติดตั้ง Terraform และตั้งค่า AWS Environment
- Terraform สำหรับ AWS: ตัวอย่างการใช้งานจริง
- ตัวอย่างที่ 1: สร้าง VPC และ Subnets (Public & Private)
- ตัวอย่างที่ 2: สร้าง EC2 Instance และ Security Group
- ตัวอย่างที่ 3: สร้าง S3 Bucket สำหรับ Static Website Hosting
- ตัวอย่างที่ 4: สร้าง RDS Database Instance (PostgreSQL)
- ตัวอย่างที่ 5: สร้าง Application Load Balancer (ALB) และ Auto Scaling Group (ASG)
- แนวคิด Terraform ขั้นสูงสำหรับ AWS
- แนวปฏิบัติที่ดีที่สุดในการใช้ Terraform กับ AWS
- เปรียบเทียบ: Terraform vs. AWS CloudFormation
- ความท้าทายและข้อควรพิจารณา
- คำถามที่พบบ่อย (FAQ)
- สรุปและก้าวต่อไป
ทำความรู้จัก Infrastructure as Code (IaC) และ Terraform
Infrastructure as Code (IaC) คืออะไร?
Infrastructure as Code (IaC) คือแนวคิดในการจัดการและ Provision โครงสร้างพื้นฐานด้านไอที เช่น เซิร์ฟเวอร์ เครือข่าย ฐานข้อมูล และบริการต่างๆ ผ่านไฟล์โค้ดแทนการตั้งค่าด้วยมือครับ แทนที่จะคลิกสร้างทรัพยากรต่างๆ บน AWS Console เราจะเขียนโค้ดเพื่ออธิบายว่าโครงสร้างพื้นฐานที่เราต้องการมีลักษณะอย่างไร จากนั้นเครื่องมือ IaC จะอ่านโค้ดนั้นและสร้างหรือปรับปรุงทรัพยากรให้เป็นไปตามที่กำหนดครับ
ทำไมต้องใช้ IaC?
การนำ IaC มาใช้มีประโยชน์มากมายที่ช่วยยกระดับการจัดการโครงสร้างพื้นฐานให้ดีขึ้นอย่างเห็นได้ชัดครับ:
- ความสอดคล้อง (Consistency): โครงสร้างพื้นฐานที่สร้างขึ้นจะเหมือนกันทุกครั้ง ไม่ว่าจะสร้างกี่ครั้งก็ตาม ลดข้อผิดพลาดจากมนุษย์ (human error) ครับ
- ความรวดเร็ว (Speed): สามารถ Provision โครงสร้างพื้นฐานใหม่ๆ ได้อย่างรวดเร็วและเป็นอัตโนมัติ ช่วยให้ Deployment Cycle สั้นลง
- ความสามารถในการทำซ้ำ (Repeatability): สามารถสร้างสภาพแวดล้อมต่างๆ เช่น Development, Staging, Production ที่เหมือนกันได้อย่างง่ายดาย
- การควบคุมเวอร์ชัน (Version Control): โค้ด IaC สามารถเก็บไว้ใน Version Control System (เช่น Git) ทำให้สามารถติดตามการเปลี่ยนแปลง ย้อนกลับเวอร์ชัน และทำงานร่วมกันในทีมได้
- การทำเอกสาร (Documentation): โค้ดเองก็เป็นเหมือนเอกสารที่อธิบายโครงสร้างพื้นฐาน ทำให้เข้าใจได้ง่ายว่ามีอะไรอยู่บ้างและถูกตั้งค่าอย่างไร
- ลดต้นทุน (Cost Reduction): การลดข้อผิดพลาดและเพิ่มความรวดเร็วในการจัดการสามารถนำไปสู่การประหยัดเวลาและค่าใช้จ่ายในระยะยาวครับ
Terraform คืออะไร?
Terraform เป็นเครื่องมือ IaC แบบ Open-source ที่พัฒนาโดย HashiCorp ครับ มันเป็นเครื่องมือที่ใช้ในการสร้าง, เปลี่ยนแปลง, และปรับปรุงโครงสร้างพื้นฐานได้อย่างปลอดภัยและมีประสิทธิภาพ โดดเด่นด้วยการใช้ภาษา HashiCorp Configuration Language (HCL) ที่อ่านง่ายและเข้าใจง่ายในการกำหนดโครงสร้างพื้นฐานครับ
คุณสมบัติหลักของ Terraform:
- Declarative: คุณเพียงแค่อธิบาย “สถานะที่ต้องการ” (desired state) ของโครงสร้างพื้นฐาน โดยไม่ต้องระบุขั้นตอน “วิธีการ” ที่จะไปถึงสถานะนั้น Terraform จะจัดการส่วนที่เหลือเองครับ
- Provider-agnostic: Terraform ไม่ได้จำกัดอยู่แค่ AWS เท่านั้น แต่สามารถทำงานร่วมกับ Cloud Providers อื่นๆ (เช่น Azure, GCP, DigitalOcean) รวมถึง On-premise Infrastructure (เช่น VMware, OpenStack) และ SaaS providers (เช่น GitHub, DataDog) ผ่านระบบ Providers ที่หลากหลายครับ
- State Management: Terraform มีการเก็บสถานะของโครงสร้างพื้นฐานที่ถูกจัดการไว้ในไฟล์ที่เรียกว่า “State file” ซึ่งเป็นข้อมูลสำคัญที่ Terraform ใช้ในการเปรียบเทียบสถานะปัจจุบันกับสถานะที่กำหนดไว้ในโค้ด เพื่อตัดสินใจว่าจะต้องสร้าง, อัปเดต, หรือลบทรัพยากรใดบ้างครับ
- Execution Plans: ก่อนที่จะทำการเปลี่ยนแปลงใดๆ Terraform จะสร้าง “Execution Plan” ที่แสดงให้เห็นว่า Terraform จะทำอะไรบ้าง (สร้าง, อัปเดต, ลบ) ซึ่งช่วยให้ผู้ใช้สามารถตรวจสอบและยืนยันการเปลี่ยนแปลงก่อนที่จะ Apply จริงครับ
ทำไมต้องใช้ Terraform กับ AWS?
AWS เป็น Cloud Provider ที่ใหญ่ที่สุดและมีบริการที่หลากหลายที่สุดครับ การใช้ Terraform ร่วมกับ AWS มีข้อได้เปรียบที่สำคัญหลายประการ:
- การจัดการทรัพยากรที่ซับซ้อน: AWS มีบริการมากมาย การจัดการด้วยมืออาจซับซ้อนและผิดพลาดได้ง่าย Terraform ช่วยให้เราสามารถกำหนดค่าบริการ AWS ที่ซับซ้อน เช่น VPCs, EC2s, RDS, S3, Lambda, EKS ฯลฯ ได้อย่างเป็นระบบครับ
- Multi-Cloud Capabilities: แม้ว่าบทความนี้จะเน้น AWS แต่หากในอนาคตองค์กรของคุณมีความจำเป็นต้องใช้ Cloud หลายแห่ง (Multi-cloud) Terraform ก็สามารถจัดการได้โดยใช้เครื่องมือเดียว ทำให้ลด Learning Curve และเพิ่มความยืดหยุ่นครับ
- Community และ Ecosystem ที่แข็งแกร่ง: Terraform มีชุมชนผู้ใช้งานขนาดใหญ่และมี Modules ที่พัฒนาโดยชุมชนมากมาย ทำให้การเริ่มต้นและแก้ไขปัญหาเป็นไปได้ง่ายครับ
- Integration กับ CI/CD: Terraform สามารถรวมเข้ากับ Pipeline ของ CI/CD ได้อย่างราบรื่น ทำให้การ Provision และ Deployment Infrastructure เป็นส่วนหนึ่งของกระบวนการอัตโนมัติทั้งหมดครับ
แนวคิดหลักของ Terraform ที่ควรรู้
เพื่อให้ใช้งาน Terraform ได้อย่างมีประสิทธิภาพ เรามาทำความเข้าใจแนวคิดพื้นฐานที่สำคัญกันก่อนครับ
Providers
Providers คือ Plugins ที่ Terraform ใช้ในการโต้ตอบกับ API ของ Cloud Provider หรือบริการอื่นๆ ครับ สำหรับ AWS เราจะใช้ AWS Provider เพื่อให้ Terraform สามารถสร้าง, จัดการ, และลบทรัพยากรบน AWS ได้ครับ
# กำหนดเวอร์ชันของ Terraform และ Providers ที่ต้องการใช้
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # ระบุเวอร์ชันของ AWS Provider
}
}
required_version = ">= 1.0.0" # ระบุเวอร์ชันขั้นต่ำของ Terraform
}
# กำหนดค่า Provider สำหรับ AWS
provider "aws" {
region = "ap-southeast-1" # ระบุ AWS Region ที่ต้องการใช้งาน
# profile = "default" # หากมีการตั้งค่า AWS CLI profiles
}
Resources
Resources คือส่วนประกอบหลักของโครงสร้างพื้นฐานที่คุณต้องการสร้างครับ เช่น VPC, Subnet, EC2 Instance, S3 Bucket, หรือ RDS Database แต่ละ Resource จะมี Type (เช่น aws_vpc, aws_instance) และ Local Name (ชื่อที่คุณตั้งให้ภายในไฟล์ Terraform) ครับ
# ตัวอย่างการสร้าง EC2 Instance
resource "aws_instance" "web_server_instance" {
ami = "ami-0abcdef1234567890" # รหัส AMI ของ EC2 (ต้องหา AMI ที่ถูกต้องใน Region ที่ใช้)
instance_type = "t2.micro"
key_name = "my-ssh-key" # ชื่อ SSH Key Pair ที่มีอยู่แล้วใน AWS
vpc_security_group_ids = [aws_security_group.web_sg.id]
subnet_id = aws_subnet.public_subnet_1.id
tags = {
Name = "WebServerFromTerraform"
}
}
Data Sources
Data Sources ใช้สำหรับดึงข้อมูลเกี่ยวกับทรัพยากรที่มีอยู่แล้วบน AWS หรือจากแหล่งอื่นครับ โดยไม่ได้สร้างทรัพยากรใหม่ แต่ใช้เพื่ออ้างอิงข้อมูลเหล่านั้นในโค้ด Terraform ของเราครับ เช่น การดึง AMI ล่าสุด หรือ VPC ID ที่มีอยู่แล้ว
# ตัวอย่างการดึง AMI ล่าสุดสำหรับ Ubuntu Server 20.04 LTS
data "aws_ami" "ubuntu_latest" {
most_recent = true
owners = ["099720109477"] # Canonical's AWS account ID for Ubuntu AMIs
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# สามารถนำ ami.id ไปใช้ใน aws_instance ได้
# ami = data.aws_ami.ubuntu_latest.id
Variables (Input, Output, Local)
Variables ช่วยให้โค้ด Terraform ของคุณมีความยืดหยุ่นและนำกลับมาใช้ใหม่ได้ง่ายขึ้นครับ
- Input Variables (
variable): ใช้สำหรับรับค่าจากภายนอก เช่น Region, Environment, หรือจำนวน Instances ทำให้สามารถปรับแต่งการ Deploy ได้โดยไม่ต้องแก้ไขโค้ดโดยตรงครับ - Output Values (
output): ใช้สำหรับแสดงข้อมูลสำคัญเกี่ยวกับทรัพยากรที่สร้างขึ้นหลังจาก Terraform Apply เสร็จสิ้น เช่น Public IP ของ EC2 หรือ DNS ของ Load Balancer - Local Values (
locals): ใช้สำหรับกำหนดค่าตัวแปรภายในไฟล์ Terraform เพื่อให้โค้ดอ่านง่ายขึ้นและลดการทำซ้ำของค่าเดียวกัน
# Input Variable
variable "instance_type" {
description = "Type of EC2 instance to launch"
type = string
default = "t2.micro"
}
# Local Variable
locals {
app_name = "MyWebApp"
tags = {
Project = "SiamLancard"
Environment = "Development"
}
}
# Output Value
output "web_server_public_ip" {
description = "Public IP address of the web server"
value = aws_instance.web_server_instance.public_ip
}
Modules
Modules คือวิธีการจัดระเบียบโค้ด Terraform ให้เป็นส่วนย่อยๆ ที่สามารถนำกลับมาใช้ใหม่ได้ครับ คุณสามารถสร้าง Module สำหรับชุดทรัพยากรที่มักจะใช้ร่วมกัน เช่น Module สำหรับ VPC ทั้งชุด หรือ Module สำหรับ Application Server Stack ที่ประกอบด้วย EC2, Security Group, และ Load Balancer ครับ การใช้ Module ช่วยลดความซ้ำซ้อนและทำให้โค้ดเป็นระเบียบมากขึ้น
# ตัวอย่างการเรียกใช้ Module (สมมติว่ามี module ชื่อ 'vpc' อยู่แล้ว)
module "main_vpc" {
source = "./modules/vpc" # Path ไปยัง Module ของคุณ หรือจาก Registry
vpc_cidr_block = "10.0.0.0/16"
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnet_cidrs = ["10.0.101.0/24", "10.0.102.0/24"]
# ส่งค่า Tag ไปยัง Module
tags = {
Project = "MyProject"
Owner = "DevOpsTeam"
}
}
State File
Terraform State File (terraform.tfstate) เป็นไฟล์ JSON ที่เก็บข้อมูลสถานะของโครงสร้างพื้นฐานที่ Terraform ได้สร้างและกำลังจัดการอยู่ครับ เป็นข้อมูลสำคัญที่ Terraform ใช้ในการเปรียบเทียบสถานะปัจจุบันกับสถานะที่กำหนดในโค้ด HCL เพื่อสร้าง Execution Plan ครับ
ข้อควรระวัง: State file มีความสำคัญอย่างยิ่งและควรได้รับการจัดการอย่างระมัดระวัง ไม่ควรแก้ไขด้วยมือโดยตรง และควรเก็บไว้ในที่ปลอดภัยและมีการ Lock เพื่อป้องกันการแก้ไขพร้อมกันหลายคน ซึ่งจะกล่าวถึงในส่วน Remote State ต่อไปครับ
Terraform Workflow: init, plan, apply, destroy
การใช้งาน Terraform โดยทั่วไปจะประกอบด้วยขั้นตอนหลักๆ ดังนี้ครับ:
terraform init: เป็นคำสั่งแรกที่ต้องรันเมื่อเริ่มต้นโปรเจกต์ใหม่หรือหลังจากดึงโปรเจกต์จาก Version Control ครับ คำสั่งนี้จะดาวน์โหลด Providers ที่จำเป็น, ตั้งค่า Backend สำหรับ State Management และดาวน์โหลด Modules ที่ถูกอ้างอิงครับterraform plan: คำสั่งนี้จะสร้าง Execution Plan โดยเปรียบเทียบสถานะปัจจุบันของโครงสร้างพื้นฐาน (จาก State File) กับสถานะที่กำหนดในโค้ด HCL และแสดงให้เห็นว่า Terraform จะสร้าง, อัปเดต, หรือลบทรัพยากรใดบ้างครับ เป็นขั้นตอนสำคัญสำหรับการตรวจสอบก่อนที่จะ Apply จริงครับterraform apply: เมื่อคุณพอใจกับ Execution Plan ที่แสดงโดยterraform planแล้ว คำสั่งterraform applyจะดำเนินการสร้าง, อัปเดต, หรือลบทรัพยากรตามที่ระบุใน Plan ครับ หลังจาก Apply สำเร็จ Terraform จะอัปเดต State File ด้วยสถานะล่าสุดของโครงสร้างพื้นฐานครับterraform destroy: คำสั่งนี้จะลบทรัพยากรทั้งหมดที่ถูกสร้างโดย Terraform ตามที่ระบุใน State File ครับ ควรใช้ด้วยความระมัดระวังอย่างยิ่ง โดยเฉพาะในสภาพแวดล้อม Production ครับ
เตรียมความพร้อม: ติดตั้ง Terraform และตั้งค่า AWS Environment
ก่อนที่เราจะเริ่มเขียนโค้ด Terraform เราต้องเตรียมสภาพแวดล้อมให้พร้อมก่อนครับ
การติดตั้ง Terraform
Terraform เป็น Single Binary ที่ติดตั้งง่ายครับ คุณสามารถดาวน์โหลดได้จากเว็บไซต์ทางการของ HashiCorp หรือใช้ Package Manager ตามระบบปฏิบัติการของคุณครับ
- สำหรับ macOS (ด้วย Homebrew):
brew tap hashicorp/tap brew install hashicorp/tap/terraform - สำหรับ Linux (Ubuntu/Debian):
sudo apt update && sudo apt install -y gnupg software-properties-common wget -O- https://apt.releases.hashicorp.com/gpg | \ gpg --dearmor | \ sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg gpg --no-default-keyring \ --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \ --fingerprint echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \ sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt update sudo apt install terraform - สำหรับ Windows: ดาวน์โหลดไฟล์
.zipจาก เว็บไซต์ Terraform และแตกไฟล์ จากนั้นเพิ่ม Path ของไฟล์terraform.exeไปยัง Environment Variables ของระบบครับ
หลังจากติดตั้งแล้ว ให้ตรวจสอบเวอร์ชันด้วยคำสั่ง:
terraform --version
คุณควรจะเห็นผลลัพธ์ประมาณนี้ครับ:
Terraform v1.x.x
on linux_amd64
การตั้งค่า AWS Credentials
Terraform จำเป็นต้องมีสิทธิ์ในการเข้าถึงบัญชี AWS ของคุณเพื่อสร้างและจัดการทรัพยากรครับ วิธีที่แนะนำและปลอดภัยที่สุดคือการใช้ AWS CLI และกำหนดค่า Credentials:
- ติดตั้ง AWS CLI: ถ้ายังไม่มี ให้ติดตั้ง AWS Command Line Interface (CLI) ก่อนครับ อ่านเพิ่มเติมเกี่ยวกับ AWS CLI
- กำหนดค่า AWS CLI: รันคำสั่ง
aws configureและใส่ Access Key ID, Secret Access Key, Default Region, และ Output Format ครับaws configure AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY Default region name [None]: ap-southeast-1 Default output format [None]: jsonข้อมูลเหล่านี้จะถูกเก็บไว้ในไฟล์
~/.aws/credentialsและ~/.aws/configครับ Terraform จะใช้ข้อมูลนี้โดยอัตโนมัติหากคุณไม่ได้ระบุprofileใน Provider Block - การใช้ IAM Roles (สำหรับ EC2 หรือ CI/CD): สำหรับการใช้งานใน Production หรือในสภาพแวดล้อม CI/CD ควรใช้ IAM Roles เพื่อมอบสิทธิ์ให้กับ EC2 Instance หรือ Pipeline โดยตรง แทนการเก็บ Credentials แบบ Hardcode ครับ
โครงสร้างไฟล์หลัก (main.tf)
โดยทั่วไป ไฟล์ Terraform จะมีนามสกุล .tf ครับ คุณสามารถจัดระเบียบโค้ดได้หลายวิธี แต่สำหรับโปรเจกต์ขนาดเล็ก ไฟล์ main.tf หนึ่งไฟล์ก็เพียงพอแล้วครับ
สร้างโฟลเดอร์สำหรับโปรเจกต์ของคุณและสร้างไฟล์ main.tf:
mkdir my-terraform-project
cd my-terraform-project
touch main.tf
ภายในไฟล์ main.tf ให้เริ่มต้นด้วยการกำหนด Provider สำหรับ AWS ครับ:
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
required_version = ">= 1.0.0"
}
provider "aws" {
region = "ap-southeast-1" # เลือก Region ที่คุณต้องการ
}
เมื่อคุณมีไฟล์นี้แล้ว ให้รัน terraform init ใน Terminal ที่อยู่ในโฟลเดอร์โปรเจกต์ เพื่อเริ่มต้นใช้งาน Terraform ครับ
terraform init
หากสำเร็จ คุณจะเห็นข้อความว่า “Terraform has been successfully initialized!” ครับ
Terraform สำหรับ AWS: ตัวอย่างการใช้งานจริง
ถึงเวลาลงมือปฏิบัติจริงกันแล้วครับ! เราจะมาดูตัวอย่างการสร้างทรัพยากร AWS ยอดนิยมด้วย Terraform กันครับ
ตัวอย่างที่ 1: สร้าง VPC และ Subnets (Public & Private)
Virtual Private Cloud (VPC) คือเครือข่ายเสมือนส่วนตัวของคุณใน AWS ครับ เป็นสิ่งแรกที่คุณควรสร้างเพื่อแยกโครงสร้างพื้นฐานของคุณออกจากผู้อื่น เราจะสร้าง VPC หนึ่งอัน พร้อม Public Subnet และ Private Subnet อย่างละสองอัน เพื่อรองรับ High Availability ครับ
# vpc.tf (หรือจะรวมใน main.tf ก็ได้)
# 1. สร้าง VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "SiamLancard-VPC"
}
}
# 2. สร้าง Internet Gateway สำหรับ Public Subnet
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "SiamLancard-IGW"
}
}
# 3. สร้าง Public Subnets (2 zones เพื่อ High Availability)
resource "aws_subnet" "public_subnet_1" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
availability_zone = "ap-southeast-1a" # เปลี่ยนเป็น AZ ที่คุณต้องการใน Region นั้นๆ
map_public_ip_on_launch = true # EC2 ใน Subnet นี้จะได้รับ Public IP โดยอัตโนมัติ
tags = {
Name = "SiamLancard-Public-Subnet-1a"
}
}
resource "aws_subnet" "public_subnet_2" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.2.0/24"
availability_zone = "ap-southeast-1b" # เปลี่ยนเป็น AZ ที่คุณต้องการใน Region นั้นๆ
map_public_ip_on_launch = true
tags = {
Name = "SiamLancard-Public-Subnet-1b"
}
}
# 4. สร้าง Private Subnets (2 zones เพื่อ High Availability)
resource "aws_subnet" "private_subnet_1" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.101.0/24"
availability_zone = "ap-southeast-1a" # ควรอยู่ใน AZ เดียวกับ Public Subnet ที่เกี่ยวข้อง
tags = {
Name = "SiamLancard-Private-Subnet-1a"
}
}
resource "aws_subnet" "private_subnet_2" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.102.0/24"
availability_zone = "ap-southeast-1b" # ควรอยู่ใน AZ เดียวกับ Public Subnet ที่เกี่ยวข้อง
tags = {
Name = "SiamLancard-Private-Subnet-1b"
}
}
# 5. สร้าง Route Table สำหรับ Public Subnet (เชื่อมต่อ Internet Gateway)
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0" # Traffic ทั้งหมด
gateway_id = aws_internet_gateway.main.id # ส่งไปที่ Internet Gateway
}
tags = {
Name = "SiamLancard-Public-Route-Table"
}
}
# 6. เชื่อม Public Subnets เข้ากับ Public Route Table
resource "aws_route_table_association" "public_1_association" {
subnet_id = aws_subnet.public_subnet_1.id
route_table_id = aws_route_table.public_rt.id
}
resource "aws_route_table_association" "public_2_association" {
subnet_id = aws_subnet.public_subnet_2.id
route_table_id = aws_route_table.public_rt.id
}
# 7. สร้าง NAT Gateway สำหรับ Private Subnet (เพื่อให้ Private Subnet ออกอินเทอร์เน็ตได้)
# ต้องมี Elastic IP ก่อน
resource "aws_eip" "nat_gateway_eip_1" {
vpc = true
depends_on = [aws_internet_gateway.main] # ให้ IGW สร้างเสร็จก่อน
tags = {
Name = "SiamLancard-NAT-EIP-1"
}
}
resource "aws_nat_gateway" "nat_gateway_1" {
allocation_id = aws_eip.nat_gateway_eip_1.id
subnet_id = aws_subnet.public_subnet_1.id # NAT Gateway ต้องอยู่ใน Public Subnet
tags = {
Name = "SiamLancard-NAT-GW-1"
}
}
# 8. สร้าง Route Table สำหรับ Private Subnet (เชื่อมต่อ NAT Gateway)
resource "aws_route_table" "private_rt_1" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat_gateway_1.id
}
tags = {
Name = "SiamLancard-Private-Route-Table-1"
}
}
# 9. เชื่อม Private Subnet 1 เข้ากับ Private Route Table 1
resource "aws_route_table_association" "private_1_association" {
subnet_id = aws_subnet.private_subnet_1.id
route_table_id = aws_route_table.private_rt_1.id
}
# Output VPC ID
output "vpc_id" {
description = "The ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs of the public subnets"
value = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id]
}
output "private_subnet_ids" {
description = "IDs of the private subnets"
value = [aws_subnet.private_subnet_1.id, aws_subnet.private_subnet_2.id]
}
ขั้นตอนการ Deploy:
- บันทึกโค้ดข้างต้นในไฟล์
vpc.tf(หรือmain.tf) - รัน
terraform init(ถ้ายังไม่ได้ทำ) - รัน
terraform planเพื่อตรวจสอบการเปลี่ยนแปลง - รัน
terraform applyเพื่อสร้างทรัพยากร พิมพ์yesเพื่อยืนยัน
หลังจากนี้คุณก็จะได้ VPC ที่มีโครงสร้างเครือข่ายพื้นฐานที่พร้อมใช้งานแล้วครับ
ตัวอย่างที่ 2: สร้าง EC2 Instance และ Security Group
ต่อไป เราจะสร้าง EC2 Instance ซึ่งเป็น Virtual Server บน AWS และ Security Group เพื่อควบคุมการเข้าถึงเครือข่ายครับ
# ec2.tf (หรือรวมกับไฟล์อื่น)
# ดึง AMI ID ล่าสุดของ Ubuntu Server 20.04 LTS
data "aws_ami" "ubuntu_latest" {
most_recent = true
owners = ["099720109477"] # Canonical's AWS account ID for Ubuntu AMIs
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# 1. สร้าง Security Group สำหรับ Web Server (เปิด Port 22 สำหรับ SSH และ Port 80 สำหรับ HTTP)
resource "aws_security_group" "web_sg" {
name = "siamlancard-web-sg"
description = "Allow HTTP and SSH inbound traffic"
vpc_id = aws_vpc.main.id # อ้างอิง VPC ที่สร้างไว้ในตัวอย่างก่อนหน้า
ingress {
description = "Allow HTTP from anywhere"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "Allow SSH from anywhere (ควรจำกัด IP จริงใน Production)"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # ควรปรับเป็น IP ของคุณเองเพื่อความปลอดภัย
}
egress {
from_port = 0
to_port = 0
protocol = "-1" # All protocols
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "SiamLancard-Web-Security-Group"
}
}
# 2. สร้าง EC2 Instance
resource "aws_instance" "web_server_instance" {
ami = data.aws_ami.ubuntu_latest.id # ใช้ AMI ID ที่ดึงมา
instance_type = "t2.micro"
key_name = "my-ssh-key" # ต้องมี SSH Key Pair ชื่อนี้ใน AWS ของคุณ
vpc_security_group_ids = [aws_security_group.web_sg.id]
subnet_id = aws_subnet.public_subnet_1.id # วางใน Public Subnet
user_data = <<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install -y apache2
sudo systemctl start apache2
sudo systemctl enable apache2
echo "<h1>Hello from Terraform on EC2!</h1>" | sudo tee /var/www/html/index.html
EOF
tags = {
Name = "SiamLancard-WebServer"
}
}
# Output Public IP ของ EC2 Instance
output "web_server_public_ip" {
description = "Public IP address of the web server"
value = aws_instance.web_server_instance.public_ip
}
# Output Public DNS ของ EC2 Instance
output "web_server_public_dns" {
description = "Public DNS of the web server"
value = aws_instance.web_server_instance.public_dns
}
ข้อควรทราบ:
- คุณต้องมี SSH Key Pair ที่ชื่อ
my-ssh-keyใน AWS Region ที่คุณใช้งานอยู่ก่อนที่จะรันโค้ดนี้ครับ user_dataเป็นสคริปต์ที่จะรันเมื่อ EC2 Instance เริ่มต้นทำงานครั้งแรก ในตัวอย่างนี้จะติดตั้ง Apache Web Server และสร้างไฟล์index.htmlง่ายๆ ครับ- ใน Production ควรจำกัด
cidr_blocksสำหรับ SSH ให้เหลือเพียง IP Address ที่จำเป็นเท่านั้นครับ
หลังจาก terraform apply คุณสามารถเข้าถึง Public IP หรือ Public DNS ที่เป็น Output เพื่อดูหน้าเว็บ Apache ที่ถูก Deploy ได้เลยครับ
ตัวอย่างที่ 3: สร้าง S3 Bucket สำหรับ Static Website Hosting
Amazon S3 (Simple Storage Service) เป็นบริการจัดเก็บ Object Storage ที่สามารถใช้สำหรับโฮสต์เว็บไซต์แบบ Static ได้อย่างง่ายดายและคุ้มค่าครับ
# s3.tf
# 1. สร้าง S3 Bucket
resource "aws_s3_bucket" "static_website_bucket" {
bucket = "siamlancard-my-unique-static-website-bucket-12345" # ต้องเป็นชื่อ Bucket ที่ไม่ซ้ำกันทั่วโลก
tags = {
Name = "SiamLancard-StaticWebsite"
Environment = "Development"
}
}
# 2. กำหนดให้ S3 Bucket รองรับ Static Website Hosting
resource "aws_s3_bucket_website_configuration" "static_website_config" {
bucket = aws_s3_bucket.static_website_bucket.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
# 3. กำหนด Public Access Block เพื่อให้ Bucket สามารถเข้าถึงได้จากภายนอก
resource "aws_s3_bucket_public_access_block" "block_public_access" {
bucket = aws_s3_bucket.static_website_bucket.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
# 4. กำหนด Bucket Policy เพื่ออนุญาตให้เข้าถึง Object ภายใน Bucket ได้
resource "aws_s3_bucket_policy" "bucket_policy" {
bucket = aws_s3_bucket.static_website_bucket.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "PublicReadGetObject"
Effect = "Allow"
Principal = "*"
Action = ["s3:GetObject"]
Resource = ["${aws_s3_bucket.static_website_bucket.arn}/*"]
},
]
})
}
# 5. อัปโหลดไฟล์ตัวอย่าง (index.html) ไปยัง S3 Bucket
resource "aws_s3_object" "index_html" {
bucket = aws_s3_bucket.static_website_bucket.id
key = "index.html"
content_type = "text/html"
source = "index.html" # ไฟล์ index.html ต้องอยู่ใน Path เดียวกันกับไฟล์ .tf
acl = "public-read" # ให้ไฟล์นี้สามารถอ่านได้โดยสาธารณะ
etag = filemd5("index.html") # ใช้สำหรับการตรวจสอบการเปลี่ยนแปลงของไฟล์
}
# สร้างไฟล์ index.html ชั่วคราว (คุณต้องสร้างไฟล์นี้ด้วยตนเอง)
/*
echo '<!DOCTYPE html>
<html>
<head><title>SiamLancard Static Website</title></head>
<body>
<h1>Hello from SiamLancard on S3!</h1>
<p>This is a static website hosted on AWS S3 using Terraform.</p>
</body>
</html>' > index.html
*/
# Output Website Endpoint
output "website_endpoint" {
description = "The S3 static website endpoint"
value = aws_s3_bucket_website_configuration.static_website_config.website_endpoint
}
ก่อนรัน: อย่าลืมสร้างไฟล์ index.html ในโฟลเดอร์เดียวกันกับไฟล์ Terraform ของคุณด้วยโค้ด HTML ง่ายๆ เช่นที่คอมเมนต์ไว้ในตัวอย่างนะครับ และเปลี่ยนชื่อ Bucket ให้เป็นชื่อที่ไม่ซ้ำกันทั่วโลกครับ
หลังจาก terraform apply คุณจะได้ URL สำหรับเว็บไซต์ Static ของคุณจาก Output ครับ
ตัวอย่างที่ 4: สร้าง RDS Database Instance (PostgreSQL)
Amazon RDS (Relational Database Service) ช่วยให้คุณสามารถสร้างและจัดการฐานข้อมูล Relational ได้ง่ายขึ้นครับ เราจะสร้าง PostgreSQL Instance ใน Private Subnet ครับ
# rds.tf
# 1. สร้าง Security Group สำหรับ RDS (เปิด Port 5432 สำหรับ PostgreSQL)
resource "aws_security_group" "rds_sg" {
name = "siamlancard-rds-sg"
description = "Allow inbound traffic to RDS from private subnets"
vpc_id = aws_vpc.main.id # อ้างอิง VPC ที่สร้างไว้
ingress {
description = "Allow PostgreSQL from private subnets"
from_port = 5432
to_port = 5432
protocol = "tcp"
# อนุญาตให้เข้าถึงจาก Private Subnet ของเราเท่านั้น
cidr_blocks = [
aws_subnet.private_subnet_1.cidr_block,
aws_subnet.private_subnet_2.cidr_block
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "SiamLancard-RDS-Security-Group"
}
}
# 2. สร้าง DB Subnet Group (สำหรับวาง RDS Instance ใน Subnets ที่กำหนด)
resource "aws_db_subnet_group" "main" {
name = "siamlancard-rds-subnet-group"
subnet_ids = [
aws_subnet.private_subnet_1.id,
aws_subnet.private_subnet_2.id
]
tags = {
Name = "SiamLancard-RDS-Subnet-Group"
}
}
# 3. สร้าง RDS PostgreSQL Instance
resource "aws_db_instance" "postgresql_db" {
allocated_storage = 20
storage_type = "gp2"
engine = "postgres"
engine_version = "13.7"
instance_class = "db.t3.micro"
name = "siamlancarddb" # ชื่อฐานข้อมูล
username = "siamlancardadmin"
password = "MyStrongPassword123!" # ควรใช้ Secrets Manager ใน Production
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.rds_sg.id]
skip_final_snapshot = true # สำหรับ Dev/Test เท่านั้น! ใน Production ควรเป็น false
multi_az = false # สำหรับ Dev/Test เท่านั้น! ใน Production ควรเป็น true เพื่อ HA
tags = {
Name = "SiamLancard-PostgreSQL-DB"
Environment = "Development"
}
}
# Output RDS Endpoint
output "rds_endpoint" {
description = "The endpoint of the RDS PostgreSQL instance"
value = aws_db_instance.postgresql_db.address
}
output "rds_port" {
description = "The port of the RDS PostgreSQL instance"
value = aws_db_instance.postgresql_db.port
}
output "rds_username" {
description = "The master username for the RDS PostgreSQL instance"
value = aws_db_instance.postgresql_db.username
}
ข้อควรทราบ:
- รหัสผ่าน (
password) ในตัวอย่างนี้เป็นแบบ Hardcode ซึ่งไม่แนะนำสำหรับ Production ครับ ควรใช้ AWS Secrets Manager หรือ HashiCorp Vault เพื่อจัดการ Credentials ที่ละเอียดอ่อนครับ - สำหรับ Production Environment ควรตั้งค่า
skip_final_snapshot = falseและmulti_az = trueเพื่อความทนทานและความพร้อมใช้งานสูงครับ aws_db_subnet_groupเป็นสิ่งจำเป็นสำหรับ RDS ที่จะถูก Deploy ใน VPC และ Subnets ที่คุณกำหนดครับ
หลังจาก terraform apply คุณจะได้ Endpoint ของฐานข้อมูล RDS ที่สามารถเชื่อมต่อได้จาก EC2 Instance ที่อยู่ใน Private Subnet ของคุณครับ
ตัวอย่างที่ 5: สร้าง Application Load Balancer (ALB) และ Auto Scaling Group (ASG)
Application Load Balancer (ALB) ช่วยกระจาย Traffic ไปยัง EC2 Instances หลายตัว และ Auto Scaling Group (ASG) ช่วยให้คุณปรับขนาด EC2 Instances ได้โดยอัตโนมัติตามความต้องการครับ
# alb_asg.tf
# 1. สร้าง Security Group สำหรับ ALB (เปิด Port 80 สำหรับ HTTP)
resource "aws_security_group" "alb_sg" {
name = "siamlancard-alb-sg"
description = "Allow HTTP inbound traffic to ALB"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"] # เปิดให้เข้าถึงจากทุกที่
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "SiamLancard-ALB-Security-Group"
}
}
# 2. สร้าง Application Load Balancer (ALB)
resource "aws_lb" "main_alb" {
name = "siamlancard-main-alb"
internal = false # External facing
load_balancer_type = "application"
security_groups = [aws_security_group.alb_sg.id]
subnets = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id] # ALB ควรอยู่ใน Public Subnets
tags = {
Name = "SiamLancard-ALB"
}
}
# 3. สร้าง Target Group (กลุ่มของ EC2 Instances ที่ ALB จะส่ง Traffic ไปให้)
resource "aws_lb_target_group" "web_tg" {
name = "siamlancard-web-tg"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.main.id
health_check {
path = "/"
protocol = "HTTP"
matcher = "200"
interval = 30
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 2
}
tags = {
Name = "SiamLancard-Web-TargetGroup"
}
}
# 4. สร้าง Listener สำหรับ ALB (Port 80)
resource "aws_lb_listener" "http_listener" {
load_balancer_arn = aws_lb.main_alb.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.web_tg.arn
}
}
# 5. สร้าง Launch Template (สำหรับกำหนดค่า EC2 Instance ที่จะสร้างโดย ASG)
resource "aws_launch_template" "web_lt" {
name_prefix = "siamlancard-web-lt-"
image_id = data.aws_ami.ubuntu_latest.id # ใช้ AMI ที่ดึงมา
instance_type = "t2.micro"
key_name = "my-ssh-key" # ต้องมี SSH Key Pair
vpc_security_group_ids = [
aws_security_group.web_sg.id, # SG สำหรับ EC2 (Port 22, 80)
# อาจจะเพิ่ม SG ที่อนุญาตให้ ALB เข้าถึงได้ใน Production
]
user_data = base64encode(<<-EOF
#!/bin/bash
sudo apt update -y
sudo apt install -y apache2
sudo systemctl start apache2
sudo systemctl enable apache2
echo "<h1>Hello from Auto Scaled EC2!</h1>" | sudo tee /var/www/html/index.html
EOF
)
tag_specifications {
resource_type = "instance"
tags = {
Name = "SiamLancard-ASG-Instance"
}
}
tag_specifications {
resource_type = "volume"
tags = {
Name = "SiamLancard-ASG-Instance-Volume"
}
}
}
# 6. สร้าง Auto Scaling Group (ASG)
resource "aws_autoscaling_group" "web_asg" {
name = "siamlancard-web-asg"
vpc_zone_identifier = [aws_subnet.private_subnet_1.id, aws_subnet.private_subnet_2.id] # ASG ควรอยู่ใน Private Subnets
desired_capacity = 2
max_size = 4
min_size = 2
target_group_arns = [aws_lb_target_group.web_tg.arn]
health_check_type = "ELB" # ให้ ALB ตรวจสอบ Health Check
health_check_grace_period = 300 # 5 นาที
launch_template {
id = aws_launch_template.web_lt.id
version = "$Latest"
}
tag {
key = "Name"
value = "SiamLancard-ASG-Instance"
propagate_at_launch = true
}
}
# Output ALB DNS Name
output "alb_dns_name" {
description = "The DNS name of the Application Load Balancer"
value = aws_lb.main_alb.dns_name
}
ข้อควรทราบ:
- ในตัวอย่างนี้ EC2 Instances ที่สร้างโดย ASG จะอยู่ใน Private Subnets เพื่อเพิ่มความปลอดภัย และ Traffic จะถูกส่งผ่าน ALB ครับ
user_dataต้องถูกbase64encodeเมื่อใช้กับ Launch Template ครับ- สำหรับ
vpc_zone_identifierของ ASG เราใช้ Private Subnets เพื่อให้ Instances ไม่ได้รับ Public IP โดยตรงครับ - คุณสามารถเพิ่ม Auto Scaling Policies เพื่อปรับขนาด ASG ตาม Metrics เช่น CPU Utilization ได้อีกด้วยครับ
หลังจาก terraform apply คุณจะได้ DNS Name ของ ALB จาก Output ซึ่งเมื่อเข้าถึงแล้ว จะเห็นหน้าเว็บจาก EC2 Instances ที่อยู่เบื้องหลัง ALB ครับ
แนวคิด Terraform ขั้นสูงสำหรับ AWS
เมื่อคุณคุ้นเคยกับพื้นฐานแล้ว ลองมาดูแนวคิดขั้นสูงบางอย่างที่จะช่วยให้การจัดการโครงสร้างพื้นฐานมีประสิทธิภาพและปลอดภัยยิ่งขึ้นครับ
การจัดการ Remote State (S3 + DynamoDB)
ในตัวอย่างข้างต้น Terraform จะเก็บ State File (terraform.tfstate) ไว้ในเครื่องของคุณ (Local State) ซึ่งมีข้อจำกัดมากมายเมื่อทำงานเป็นทีม หรือเมื่อต้องการความทนทานของ State ครับ การใช้ Remote State เป็นสิ่งสำคัญอย่างยิ่งสำหรับ Production Environment ครับ
AWS S3 และ DynamoDB เป็น Combination ที่นิยมใช้ในการจัดการ Remote State:
- S3 Bucket: ใช้สำหรับเก็บ State File อย่างปลอดภัยและทนทาน
- DynamoDB Table: ใช้สำหรับ State Locking เพื่อป้องกันไม่ให้ผู้ใช้หลายคนพยายาม Apply การเปลี่ยนแปลงพร้อมกัน ซึ่งอาจทำให้ State File เสียหายได้ครับ
วิธีการตั้งค่า Remote State:
1. สร้าง S3 Bucket และ DynamoDB Table (ทำด้วยมือผ่าน AWS Console หรือด้วย Terraform อีกโปรเจกต์หนึ่ง)
# backend.tf (ไฟล์แยกสำหรับ Backend Configuration)
terraform {
backend "s3" {
bucket = "siamlancard-terraform-state-bucket-12345" # ต้องเป็นชื่อที่ไม่ซ้ำกัน
key = "dev/network/terraform.tfstate" # Path ภายใน Bucket
region = "ap-southeast-1"
encrypt = true # ควรเข้ารหัส State File
dynamodb_table = "siamlancard-terraform-state-lock" # ชื่อ DynamoDB table สำหรับ Lock
}
}
ขั้นตอน:
- สร้าง S3 Bucket (เช่น
siamlancard-terraform-state-bucket-12345) และ DynamoDB Table (เช่นsiamlancard-terraform-state-lock) ด้วย Partition Key ชื่อLockIDใน Region เดียวกันก่อนครับ - เพิ่ม Block
backend "s3"เข้าไปในไฟล์ Terraform ของคุณ (เช่นbackend.tf) - รัน
terraform init -reconfigureครับ Terraform จะตรวจพบการเปลี่ยนแปลงและย้าย State File จาก Local ไปยัง S3 Bucket ของคุณครับ
หลังจากนี้ ทุกๆ การรัน terraform plan หรือ terraform apply Terraform จะอ่านและเขียน State File จาก S3 และใช้ DynamoDB ในการ Lock/Unlock State ครับ
การสร้างและใช้งาน Modules
เราได้เห็นตัวอย่างการใช้ Modules ไปแล้วครับ แต่จะเจาะลึกเกี่ยวกับการสร้าง Module ของตัวเองครับ
สมมติว่าคุณต้องการสร้าง Module สำหรับ VPC ที่สามารถนำกลับมาใช้ใหม่ได้ในหลายโปรเจกต์:
1. สร้างโครงสร้างโฟลเดอร์สำหรับ Module:
mkdir -p modules/vpc
cd modules/vpc
touch main.tf variables.tf outputs.tf
2. โค้ดสำหรับ Module VPC (modules/vpc/main.tf):
# modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr_block
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(
var.tags,
{ Name = "${var.project_name}-VPC" }
)
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = merge(
var.tags,
{ Name = "${var.project_name}-IGW" }
)
}
# (เพิ่มโค้ดสำหรับ Subnets, Route Tables, NAT Gateway เหมือนตัวอย่าง VPC ก่อนหน้า แต่ใช้ var.public_subnet_cidrs, var.private_subnet_cidrs)
# เพื่อให้บทความไม่ยาวเกินไป ขอละโค้ดส่วนนี้ไว้ แต่แนวคิดคือการใช้ var.xx แทนค่า hardcode
3. กำหนด Input Variables สำหรับ Module (modules/vpc/variables.tf):
# modules/vpc/variables.tf
variable "vpc_cidr_block" {
description = "The CIDR block for the VPC"
type = string
}
variable "public_subnet_cidrs" {
description = "A list of CIDR blocks for the public subnets"
type = list(string)
}
variable "private_subnet_cidrs" {
description = "A list of CIDR blocks for the private subnets"
type = list(string)
}
variable "project_name" {
description = "Name of the project to tag resources"
type = string
}
variable "tags" {
description = "A map of tags to apply to all resources"
type = map(string)
default = {}
}
4. กำหนด Output Values สำหรับ Module (modules/vpc/outputs.tf):
# modules/vpc/outputs.tf
output "vpc_id" {
description = "The ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs of the public subnets"
value = [for s in aws_subnet.public : s.id] # สมมติว่าสร้าง public subnets แบบ loop
}
output "private_subnet_ids" {
description = "IDs of the private subnets"
value = [for s in aws_subnet.private : s.id]
}
5. ใช้งาน Module ใน Root Configuration (main.tf):
# main.tf
module "main_vpc" {
source = "./modules/vpc" # อ้างอิง Path ไปยัง Module ที่สร้าง
vpc_cidr_block = "10.0.0.0/16"
public_subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnet_cidrs = ["10.0.101.0/24", "10.0.102.0/24"]
project_name = "SiamLancardApp"
tags = {
Environment = "Development"
}
}
# สามารถอ้างอิง Output จาก Module ได้:
# resource "aws_instance" "app_server" {
# subnet_id = module.main_vpc.private_subnet_ids[0]
# # ...
# }
การใช้ Modules ช่วยให้โค้ดของคุณเป็นระเบียบ, สามารถนำกลับมาใช้ใหม่ได้ และง่ายต่อการบำรุงรักษาครับ
Terraform Workspaces สำหรับ Multiple Environments
Terraform Workspaces ช่วยให้คุณสามารถจัดการสถานะของโครงสร้างพื้นฐานหลายชุดได้จาก Configuration เดียวกัน เหมาะสำหรับการจัดการหลายสภาพแวดล้อม เช่น Development, Staging, และ Production ครับ
ขั้นตอนการใช้งาน Workspaces:
- สร้าง Workspace ใหม่:
terraform workspace new stagingคำสั่งนี้จะสร้าง Workspace ชื่อ
stagingและสลับไปใช้งาน Workspace นั้นทันทีครับ - สลับ Workspace:
terraform workspace select production - ใช้ Workspace ในโค้ด: คุณสามารถใช้
terraform.workspaceในโค้ดเพื่อปรับแต่งค่าตาม Workspace ที่ใช้งานอยู่ครับresource "aws_instance" "example" { # ... tags = { Name = "MyInstance-${terraform.workspace}" Environment = terraform.workspace } } variable "instance_count" { type = map(number) default = { "default" = 1 "staging" = 2 "production" = 5 } } resource "aws_instance" "app" { count = lookup(var.instance_count, terraform.workspace, 1) # ใช้ default ถ้าหาไม่เจอ # ... }
ข้อควรทราบ: Workspaces เหมาะสำหรับแยกสภาพแวดล้อมที่คล้ายกัน แต่ถ้า Configuration แตกต่างกันมาก การใช้โฟลเดอร์แยกสำหรับแต่ละ Environment อาจจะเหมาะสมกว่าครับ
แนวปฏิบัติที่ดีที่สุดในการใช้ Terraform กับ AWS
เพื่อให้การใช้งาน Terraform ของคุณมีประสิทธิภาพ ปลอดภัย และยั่งยืน ควรปฏิบัติตามแนวทางเหล่านี้ครับ
การใช้ Version Control (Git)
เก็บโค้ด Terraform ของคุณไว้ใน Git Repository เสมอครับ เพื่อ:
- ติดตามการเปลี่ยนแปลง (Change tracking)
- สามารถย้อนกลับเวอร์ชัน (Rollback) ได้ง่าย
- ทำงานร่วมกันในทีม (Collaboration)
- มีประวัติการเปลี่ยนแปลงที่ชัดเจน
อย่าลืมเพิ่ม .terraform/ และ .terraform.lock.hcl (สำหรับ Terraform v0.14+) ลงใน .gitignore ด้วยครับ เพราะเป็นไฟล์ที่ Terraform สร้างขึ้นและไม่ควรถูก Track ใน Git ครับ
การทำ Modularization
แบ่งโค้ดของคุณออกเป็น Modules ที่นำกลับมาใช้ใหม่ได้ครับ เช่น Module สำหรับ VPC, Module สำหรับ EC2 App Server, Module สำหรับ RDS ฯลฯ
- ช่วยลดความซ้ำซ้อนของโค้ด
- ทำให้โค้ดเป็นระเบียบและจัดการง่ายขึ้น
- ส่งเสริมการทำงานร่วมกันในทีม เพราะแต่ละทีมสามารถดูแล Module ของตนเองได้
- เพิ่มความสามารถในการทดสอบและบำรุงรักษา