
ในโลกของการพัฒนาและบริหารจัดการระบบคลาวด์ที่เปลี่ยนแปลงอย่างรวดเร็ว การสร้างและจัดการโครงสร้างพื้นฐาน (Infrastructure) แบบดั้งเดิมที่ต้องอาศัยการคลิกผ่านหน้าคอนโซลหรือการรันสคริปต์ด้วยมือ อาจกลายเป็นคอขวดที่ทำให้กระบวนการช้าลง เกิดข้อผิดพลาดได้ง่าย และยากต่อการปรับขนาด แต่ไม่ต้องกังวลครับ เพราะในวันนี้ เรามีแนวทางปฏิวัติวงการที่เรียกว่า Infrastructure as Code (IaC) ซึ่งเข้ามาช่วยให้เราสามารถกำหนด ตรวจสอบ และจัดการโครงสร้างพื้นฐานของระบบคลาวด์ได้อย่างอัตโนมัติ มีประสิทธิภาพ และสามารถทำซ้ำได้ และเมื่อพูดถึง IaC เครื่องมือที่โดดเด่นและเป็นที่นิยมอย่างกว้างขวางในหมู่ผู้ใช้งาน AWS ก็คือ Terraform นั่นเองครับ บทความนี้จะพาทุกท่านดำดิ่งสู่โลกของ Terraform และ AWS เพื่อทำความเข้าใจว่าทำไมเครื่องมือนี้จึงเป็นกุญแจสำคัญในการปลดล็อกศักยภาพสูงสุดของ Cloud infrastructure ของคุณได้อย่างแท้จริง
- บทนำ: การปฏิวัติวงการ Cloud ด้วย Infrastructure as Code (IaC) และ Terraform
- Terraform คืออะไร? ทำไมต้อง Terraform สำหรับ AWS?
- Core Concepts ของ Terraform ที่ควรรู้
- เริ่มต้นใช้งาน Terraform สำหรับ AWS: Step-by-Step Guide
- Best Practices ในการใช้ Terraform กับ AWS
- ข้อดีและข้อจำกัดของ Terraform บน AWS
- Use Cases จริงสำหรับ Terraform บน AWS
- FAQ (คำถามที่พบบ่อย)
- สรุปและอนาคตของ IaC กับ Terraform บน AWS
บทนำ: การปฏิวัติวงการ Cloud ด้วย Infrastructure as Code (IaC) และ Terraform
ในยุคที่องค์กรต่าง ๆ หันมาใช้บริการ Cloud Computing อย่าง AWS มากขึ้น การจัดการโครงสร้างพื้นฐานไม่ว่าจะเป็นเซิร์ฟเวอร์, ฐานข้อมูล, เครือข่าย หรือบริการอื่น ๆ นับเป็นความท้าทายที่สำคัญครับ การสร้างและปรับแต่งทรัพยากรเหล่านี้ด้วยมือผ่าน AWS Management Console อาจเพียงพอสำหรับโปรเจกต์ขนาดเล็ก แต่เมื่อระบบเติบโตขึ้น มีความซับซ้อนมากขึ้น หรือต้องรองรับสภาพแวดล้อมที่หลากหลาย (เช่น Development, Staging, Production) ปัญหาต่าง ๆ ก็จะเริ่มปรากฏขึ้นมาอย่างชัดเจนครับ
ปัญหาเหล่านี้ได้แก่:
- ความไม่สอดคล้องกัน (Inconsistency): การตั้งค่าด้วยมืออาจทำให้เกิดความผิดพลาดและความแตกต่างระหว่างสภาพแวดล้อมต่าง ๆ ได้ง่าย
- ใช้เวลามาก (Time-consuming): การสร้างหรือแก้ไขโครงสร้างพื้นฐานด้วยมือแต่ละครั้งต้องใช้เวลาและแรงงานมาก
- ยากต่อการทำซ้ำ (Hard to reproduce): การสร้างสภาพแวดล้อมใหม่ที่เหมือนเดิมเป๊ะ ๆ เป็นเรื่องยากและเสี่ยงต่อการเกิดข้อผิดพลาด
- ไม่มีการบันทึกประวัติ (Lack of Version Control): ไม่สามารถติดตามการเปลี่ยนแปลงของโครงสร้างพื้นฐานได้เหมือนโค้ดโปรแกรมทั่วไป
- ความเสี่ยงด้านความปลอดภัย (Security Risks): การตั้งค่าที่ผิดพลาดอาจเปิดช่องโหว่ด้านความปลอดภัย
นี่คือจุดที่ Infrastructure as Code (IaC) เข้ามามีบทบาทสำคัญครับ IaC คือแนวคิดที่ปฏิวัติการจัดการโครงสร้างพื้นฐาน โดยเปลี่ยนจากการจัดการด้วยมือไปเป็นการกำหนดโครงสร้างพื้นฐานทั้งหมดให้อยู่ในรูปแบบของโค้ดที่อ่านเข้าใจได้ (Human-readable configuration files) ซึ่งโค้ดเหล่านี้สามารถถูกจัดเก็บในระบบ Version Control เช่น Git ทำให้สามารถติดตามการเปลี่ยนแปลง, ทำ Rollback, และทำงานร่วมกันเป็นทีมได้อย่างมีประสิทธิภาพครับ
และเมื่อพูดถึง IaC บน AWS เครื่องมือที่ได้รับความนิยมอย่างแพร่หลายและมีประสิทธิภาพสูงคือ Terraform ครับ Terraform เป็น Open-source tool ที่พัฒนาโดย HashiCorp ช่วยให้เราสามารถกำหนด (provision) และจัดการโครงสร้างพื้นฐานของ Cloud ได้อย่างง่ายดายและเป็นระบบ ไม่ว่าจะเป็น AWS, Azure, Google Cloud หรือแม้กระทั่ง On-premises infrastructure ครับ ด้วย Terraform คุณสามารถเขียนโค้ดเพื่อบอกว่า “ฉันต้องการ VPC ที่มี Subnets แบบนี้, EC2 Instance ขนาดเท่านี้, และ S3 Bucket ที่มีการตั้งค่าแบบนั้น” และ Terraform จะจัดการส่วนที่เหลือให้คุณเองครับ นี่คือพลังของการจัดการ Cloud infrastructure ในรูปแบบของโค้ด ที่จะช่วยให้คุณปลดล็อกศักยภาพของ AWS ได้อย่างเต็มที่ครับ
Terraform คืออะไร? ทำไมต้อง Terraform สำหรับ AWS?
Terraform คือเครื่องมือ Infrastructure as Code (IaC) แบบ Open-source ที่ช่วยให้คุณสามารถกำหนดโครงสร้างพื้นฐานของระบบคลาวด์และ On-premises ได้ด้วยโค้ดแบบ Declarative ครับ พัฒนาโดย HashiCorp จุดเด่นของ Terraform คือความสามารถในการจัดการทรัพยากรจากหลาย ๆ Providers (เช่น AWS, Azure, Google Cloud Platform, VMware vSphere, Kubernetes) ด้วยภาษาเดียวกันที่เรียกว่า HashiCorp Configuration Language (HCL) หรือจะใช้ JSON ก็ได้เช่นกันครับ
แล้วทำไมเราถึงควรเลือกใช้ Terraform สำหรับ AWS?
- Multi-Cloud Compatibility: แม้ว่าบทความนี้จะเน้นที่ AWS แต่ Terraform มีจุดแข็งที่เหนือกว่าเครื่องมือ IaC เฉพาะแพลตฟอร์มตรงที่มันสามารถทำงานร่วมกับ Cloud Providers อื่น ๆ ได้อย่างราบรื่น หากคุณมีแผนที่จะใช้ Multi-Cloud Strategy ในอนาคต การเรียนรู้ Terraform เพียงครั้งเดียวจะช่วยให้คุณสามารถจัดการ Infrastructure ได้ในทุก ๆ Cloud ที่รองรับครับ
- Declarative Configuration: คุณเพียงแค่บอก Terraform ว่าคุณต้องการ “สถานะสุดท้าย” ของ Infrastructure เป็นอย่างไร (เช่น ฉันต้องการ S3 bucket ชื่อ ‘my-unique-bucket’ และ EC2 instance ชนิด ‘t2.micro’) Terraform จะเป็นผู้รับผิดชอบในการหาวิธีดำเนินการเพื่อให้ได้สถานะนั้น ไม่ว่าจะเป็นการสร้างใหม่, แก้ไข, หรือลบ เพื่อให้ตรงกับโค้ดที่คุณเขียนครับ
- Efficiency and Automation: Terraform ช่วยลดเวลาและข้อผิดพลาดในการสร้างหรือปรับปรุง Infrastructure ได้อย่างมาก การสร้างสภาพแวดล้อมใหม่ ๆ ที่เหมือนกันเป๊ะ ๆ สามารถทำได้ในไม่กี่นาทีด้วยการรันคำสั่งเพียงไม่กี่คำสั่งครับ
- Consistency and Standardization: ด้วย IaC โครงสร้างพื้นฐานของคุณจะถูกกำหนดด้วยโค้ดที่สามารถตรวจสอบได้ สิ่งนี้ช่วยให้มั่นใจได้ว่าทุกสภาพแวดล้อม (Development, Staging, Production) มีการตั้งค่าที่สอดคล้องกัน ลดปัญหา “It works on my machine” ลงได้มากครับ
- Version Control: โค้ด Terraform ของคุณสามารถจัดเก็บในระบบ Version Control (เช่น Git) ทำให้คุณสามารถติดตามทุกการเปลี่ยนแปลง, ตรวจสอบโค้ด, ทำ Rollback ไปยังเวอร์ชันก่อนหน้าได้ง่าย ๆ และทำงานร่วมกันเป็นทีมได้อย่างมีประสิทธิภาพครับ
- Cost Optimization: การที่คุณสามารถเห็นภาพรวมของ Infrastructure ในรูปแบบโค้ด ทำให้คุณสามารถวางแผนและควบคุมการใช้ทรัพยากรได้อย่างรัดกุมมากขึ้น หลีกเลี่ยงการสร้างทรัพยากรที่ไม่จำเป็นหรือลืมลบทรัพยากรที่ไม่ได้ใช้แล้วครับ
- Disaster Recovery: ในกรณีที่เกิดเหตุไม่คาดฝัน การสร้าง Infrastructure ขึ้นมาใหม่จากโค้ด Terraform สามารถทำได้อย่างรวดเร็วและแม่นยำ ช่วยลด Downtime และเพิ่มความยืดหยุ่นให้กับระบบของคุณครับ
- Modularity and Reusability: Terraform สนับสนุนแนวคิด Modules ซึ่งช่วยให้คุณสามารถสร้างบล็อกโค้ดที่นำกลับมาใช้ใหม่ได้ ทำให้การจัดการ Infrastructure ที่ซับซ้อนเป็นเรื่องง่ายขึ้นและลดการเขียนโค้ดซ้ำซ้อนครับ
- Community and Ecosystem: Terraform มีชุมชนผู้ใช้งานขนาดใหญ่และเติบโตอย่างต่อเนื่อง ทำให้สามารถหาตัวอย่าง, Modules, และความช่วยเหลือได้ง่าย มี Providers จำนวนมากที่รองรับบริการและแพลตฟอร์มต่าง ๆ มากมายครับ
ด้วยเหตุผลเหล่านี้ Terraform จึงเป็นเครื่องมือที่ทรงพลังและจำเป็นอย่างยิ่งสำหรับองค์กรที่ต้องการบริหารจัดการ Cloud infrastructure บน AWS อย่างมีประสิทธิภาพ, ปลอดภัย, และสามารถปรับขนาดได้ครับ
Terraform เปรียบเทียบกับ AWS CloudFormation และเครื่องมืออื่นๆ
เมื่อพูดถึง IaC บน AWS หลายคนมักจะนึกถึง AWS CloudFormation ซึ่งเป็นบริการ IaC แบบ Native ของ AWS ด้วยครับ เพื่อให้เห็นภาพชัดเจนว่า Terraform มีจุดเด่นอย่างไร เรามาเปรียบเทียบ Terraform กับ CloudFormation และเครื่องมือ IaC อื่น ๆ กันครับ
| คุณสมบัติ | Terraform (HashiCorp) | AWS CloudFormation (AWS Native) | Ansible (Red Hat) | Chef/Puppet (Progress) |
|---|---|---|---|---|
| ประเภทเครื่องมือ | Infrastructure Provisioning (Declarative) | Infrastructure Provisioning (Declarative) | Configuration Management (Procedural/Declarative) | Configuration Management (Declarative) |
| ภาษาที่ใช้ | HCL (HashiCorp Configuration Language), JSON | YAML, JSON | YAML (Playbooks) | Ruby DSL (Chef), Puppet DSL (Puppet) |
| Cloud Provider | Multi-Cloud (AWS, Azure, GCP, VMware, Kubernetes ฯลฯ) | AWS-specific (แต่สามารถจัดการทรัพยากรนอก AWS ผ่าน Custom Resources ได้จำกัด) | Multi-Cloud (แต่เน้นจัดการ Configuration บน OS มากกว่า Provisioning Infrastructure) | Multi-Cloud (เน้นจัดการ Configuration บน OS) |
| การจัดการ State | ใช้ Terraform State File (.tfstate) เพื่อติดตามสถานะของ Infrastructure | จัดการ State ภายในบริการ CloudFormation Stack | ไม่มี State file โดยตรง มักจะรัน Idempotent Tasks | มี Node Catalog เพื่อติดตามสถานะของ Configuration |
| การจัดการ Dependencies | จัดการ Dependencies ระหว่างทรัพยากรโดยอัตโนมัติ | จัดการ Dependencies ระหว่างทรัพยากรโดยอัตโนมัติ | จัดการ Dependencies ผ่าน Playbook Order/Handlers | จัดการ Dependencies ผ่าน Resource Ordering |
| ความยืดหยุ่น/ขยายได้ | สูงมาก มี Providers และ Modules ให้เลือกใช้จำนวนมาก | สูง แต่จำกัดอยู่แค่บริการ AWS และ Custom Resources | สูง สามารถเขียน Modules/Roles ได้ | สูง สามารถเขียน Cookbooks/Modules ได้ |
| Learning Curve | ปานกลางถึงสูง (HCL ค่อนข้างเฉพาะ) | ปานกลาง (YAML/JSON ทั่วไป แต่มี AWS Concepts เฉพาะ) | ต่ำถึงปานกลาง (YAML ค่อนข้างง่าย) | สูง (Ruby DSL / Puppet DSL) |
| Use Cases หลัก | Provisioning Infrastructure ใหม่, Multi-Cloud Management, Disaster Recovery | Provisioning Infrastructure ใหม่บน AWS, จัดการ AWS Resources | Configuration Management, Software Deployment, Orchestration | Configuration Management, Policy Enforcement, Compliance |
| ราคา | Open-source (ฟรี), มี Terraform Cloud/Enterprise สำหรับฟีเจอร์เพิ่มเติม | ฟรี (คิดค่าบริการจากทรัพยากร AWS ที่สร้างขึ้น) | Open-source (ฟรี), มี Ansible Tower/Automation Platform สำหรับฟีเจอร์เพิ่มเติม | Open-source (ฟรี), มี Enterprise Editions |
โดยสรุปคือ:
- Terraform โดดเด่นในด้าน Multi-Cloud provisioning และเป็นตัวเลือกที่ดีที่สุดหากคุณต้องการความยืดหยุ่นในการจัดการโครงสร้างพื้นฐานข้าม Cloud providers หรือต้องการเครื่องมือ IaC ที่มีความเป็นกลาง
- AWS CloudFormation เป็นตัวเลือกที่ยอดเยี่ยมสำหรับผู้ที่เน้นการทำงานบน AWS เพียงอย่างเดียว และต้องการการผสานรวมกับบริการ AWS อื่นๆ ที่ราบรื่นที่สุด
- Ansible, Chef, Puppet เป็นเครื่องมือที่เน้นไปที่ Configuration Management (การตั้งค่าซอฟต์แวร์บนเซิร์ฟเวอร์) มากกว่าการสร้าง Infrastructure ใหม่ ๆ แม้ว่าบางเครื่องมือจะสามารถทำ Provisioning ได้บ้าง แต่ก็ไม่เป็นจุดแข็งหลักเหมือน Terraform หรือ CloudFormation ครับ
ดังนั้น หากเป้าหมายของคุณคือการจัดการ Cloud infrastructure บน AWS และอาจขยายไปสู่ Multi-Cloud ในอนาคต Terraform คือตัวเลือกที่คุ้มค่าแก่การลงทุนเรียนรู้เป็นอย่างยิ่งครับ
อ่านเพิ่มเติมเกี่ยวกับเครื่องมือ IaC ต่างๆ
Core Concepts ของ Terraform ที่ควรรู้
ก่อนที่เราจะลงมือเขียนโค้ด Terraform เพื่อจัดการ AWS Infrastructure เรามาทำความเข้าใจแนวคิดหลัก ๆ ที่เป็นหัวใจของ Terraform กันก่อนนะครับ การเข้าใจสิ่งเหล่านี้จะช่วยให้คุณสามารถเขียนโค้ดได้อย่างมีประสิทธิภาพและแก้ไขปัญหาได้เมื่อเจออุปสรรคครับ
Providers
Providers คือส่วนประกอบที่สำคัญที่สุดของ Terraform ครับ มันทำหน้าที่เป็นตัวเชื่อมระหว่าง Terraform กับ API ของ Cloud Provider หรือบริการอื่น ๆ ที่เราต้องการจัดการ Providers จะเป็นตัวกำหนดว่า Terraform สามารถสร้าง, อ่าน, อัปเดต, และลบทรัพยากรประเภทใดได้บ้าง และมี Attributes อะไรบ้างสำหรับแต่ละทรัพยากรนั้น ๆ ครับ
สำหรับ AWS เราจะใช้ aws provider ซึ่งเป็นที่นิยมและได้รับการพัฒนาอย่างต่อเนื่อง โดยเราจะต้องกำหนด Providers ในไฟล์ `.tf` ของเราเสมอครับ
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # กำหนดเวอร์ชันของ AWS Provider ที่ต้องการ
}
}
}
provider "aws" {
region = "ap-southeast-1" # กำหนด AWS Region ที่ต้องการใช้งาน
# profile = "default" # หากต้องการใช้ named profile จาก AWS CLI
}
ในตัวอย่างข้างต้น เรากำหนดให้ Terraform ใช้ AWS Provider เวอร์ชัน 5.0 ขึ้นไป และกำหนด Region เป็น ap-southeast-1 (สิงคโปร์) ครับ
Resources
Resources คือบล็อกโค้ดที่ใช้ในการกำหนดทรัพยากรต่าง ๆ ที่เราต้องการสร้างหรือจัดการบน Cloud Provider ครับ ไม่ว่าจะเป็น EC2 Instances, S3 Buckets, VPCs, Databases หรือ Security Groups ทุกสิ่งที่เราต้องการสร้างจะถูกประกาศเป็น Resource ใน Terraform ครับ
โครงสร้างของ Resource จะมีรูปแบบดังนี้:
resource "ประเภท_ของ_resource" "ชื่อ_เชิงตรรกะ_สำหรับ_resource" {
# Argument ต่าง ๆ สำหรับ resource นั้น ๆ
# เช่น name, instance_type, ami, tags
}
ตัวอย่างการสร้าง S3 Bucket:
resource "aws_s3_bucket" "my_bucket" {
bucket = "siamlancard-unique-bucket-12345" # ชื่อ S3 Bucket ต้องไม่ซ้ำกันทั่วโลก
tags = {
Name = "My Terraform Bucket"
Environment = "Dev"
}
}
ในตัวอย่างนี้ aws_s3_bucket คือประเภทของ Resource ที่มาจาก AWS Provider และ my_bucket คือชื่อเชิงตรรกะที่เรากำหนดขึ้นเองเพื่อใช้อ้างอิงถึง Resource นี้ภายในโค้ด Terraform ครับ
Data Sources
ในบางครั้ง เราอาจต้องการอ้างอิงถึงข้อมูลของทรัพยากรที่มีอยู่แล้วบน AWS (ที่ไม่ได้ถูกสร้างโดย Terraform ปัจจุบัน) เพื่อนำมาใช้ในการกำหนดทรัพยากรใหม่ หรือเพื่อดึงข้อมูลบางอย่างมาแสดงผล Data Sources เข้ามาช่วยในส่วนนี้ครับ มันช่วยให้ Terraform สามารถ “อ่าน” ข้อมูลจาก Infrastructure ที่มีอยู่ได้ครับ
ตัวอย่างการดึงข้อมูล AMI ID ล่าสุดของ Ubuntu:
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
resource "aws_instance" "web_server" {
ami = data.aws_ami.ubuntu.id # อ้างอิง ID ของ AMI ที่ดึงมาจาก Data Source
instance_type = "t2.micro"
tags = {
Name = "WebServer"
}
}
ในตัวอย่างนี้ data "aws_ami" "ubuntu" จะค้นหา AMI ล่าสุดของ Ubuntu 22.04 และเราสามารถอ้างอิง ID ของมันผ่าน data.aws_ami.ubuntu.id เพื่อนำไปใช้กับ EC2 Instance ได้ครับ
Variables และ Outputs
Variables (Input Variables) ช่วยให้โค้ด Terraform ของเรามีความยืดหยุ่นและนำกลับมาใช้ใหม่ได้ง่ายขึ้นครับ เราสามารถกำหนดค่าบางอย่างที่อาจเปลี่ยนแปลงได้บ่อยครั้ง (เช่น Region, ชื่อ Environment, ขนาด Instance) ให้เป็น Variable แทนที่จะ Hardcode ค่าเหล่านั้นลงไปในโค้ดโดยตรงครับ
การประกาศ Variable:
variable "aws_region" {
description = "The AWS region to deploy resources in"
type = string
default = "ap-southeast-1"
}
variable "instance_type" {
description = "The EC2 instance type"
type = string
default = "t2.micro"
}
การใช้งาน Variable:
provider "aws" {
region = var.aws_region
}
resource "aws_instance" "example" {
ami = "ami-0abcdef1234567890" # ตัวอย่าง AMI ID
instance_type = var.instance_type
tags = {
Name = "MyInstance-${var.aws_region}"
}
}
เราสามารถกำหนดค่าให้กับ Variables ได้หลายวิธี เช่น ผ่านไฟล์ terraform.tfvars, Environment variables, หรือผ่าน Command line arguments ครับ
Outputs (Output Values) เป็นวิธีในการแสดงผลข้อมูลสำคัญเกี่ยวกับ Infrastructure ที่เราสร้างขึ้น หรือข้อมูลที่เราดึงมาจาก Data Sources ครับ Output จะมีประโยชน์มากเมื่อเราต้องการส่งต่อข้อมูลจาก Root module ไปยัง Child module หรือเมื่อเราต้องการทราบข้อมูลบางอย่างหลังจากที่ Terraform ได้ทำการ Provision Infrastructure เสร็จสิ้นแล้วครับ
ตัวอย่าง Output:
output "s3_bucket_name" {
description = "The name of the created S3 bucket"
value = aws_s3_bucket.my_bucket.bucket
}
output "ec2_public_ip" {
description = "The public IP address of the EC2 instance"
value = aws_instance.web_server.public_ip
}
เมื่อรัน terraform apply เสร็จสิ้น Terraform จะแสดงค่า Output เหล่านี้ออกมาให้เราเห็นครับ
Modules
Modules คือแนวคิดที่สำคัญมากในการจัดการ Infrastructure ที่ซับซ้อนด้วย Terraform ครับ Module คือคอนเทนเนอร์สำหรับโค้ด Terraform ที่สามารถนำกลับมาใช้ใหม่ได้ (reusable) และสามารถเรียกใช้ได้จากที่อื่น ๆ ครับ Modules ช่วยให้เราสามารถจัดระเบียบโค้ด, ลดความซ้ำซ้อน, และสร้างบล็อกโครงสร้างพื้นฐานมาตรฐานที่สามารถใช้งานได้ในหลาย ๆ โปรเจกต์หรือหลาย ๆ สภาพแวดล้อมได้ครับ
Terraform Project ทุกอันถือเป็น Root module และเราสามารถสร้าง Child modules หรือใช้ Modules ที่มีอยู่แล้วจาก Terraform Registry ได้ครับ
ตัวอย่างการเรียกใช้ Module:
module "vpc" {
source = "./modules/vpc" # อ้างอิงไปยังโฟลเดอร์ Module ของเราเอง
vpc_cidr_block = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
tags = {
Project = "SiamLancardApp"
Environment = "Dev"
}
}
ในตัวอย่างนี้ เราเรียกใช้ Module ชื่อ vpc ซึ่งอยู่ในโฟลเดอร์ ./modules/vpc และส่งค่า Input variables เข้าไปให้ Module นั้น ๆ ครับ
เรียนรู้การสร้าง Terraform Modules เพิ่มเติม
Terraform State File
Terraform State File (terraform.tfstate) คือไฟล์ที่สำคัญที่สุดของ Terraform ครับ มันทำหน้าที่เป็น “ฐานข้อมูล” ที่ Terraform ใช้เพื่อติดตามสถานะปัจจุบันของ Infrastructure ที่ได้สร้างขึ้น Terraform ใช้ไฟล์นี้เพื่อ:
- Mapping Real-world Resources: เก็บ ID และ Attributes ของทรัพยากรจริงบน Cloud ที่ Terraform ได้สร้างไว้
- Tracking Metadata: เก็บข้อมูล Meta-data เกี่ยวกับทรัพยากร
- Performance Optimization: ลดการเรียก API ไปยัง Cloud Provider โดยไม่จำเป็น
- Plan and Apply Logic: ใช้เปรียบเทียบสถานะปัจจุบัน (ใน State file) กับสถานะที่ต้องการ (ในโค้ด Terraform) เพื่อสร้าง Execution Plan ที่ถูกต้อง
ไฟล์ .tfstate มีข้อมูลที่ละเอียดอ่อนเกี่ยวกับ Infrastructure ของคุณ ดังนั้นจึงต้องได้รับการดูแลรักษาอย่างดีครับ โดยปกติแล้ว ไม่ควรเก็บไฟล์ .tfstate ไว้ในระบบ Version Control โดยตรงครับ
Backend (Remote State)
เนื่องจาก terraform.tfstate มีความสำคัญและไม่ควรเก็บไว้ในเครื่องคอมพิวเตอร์ของเราโดยตรง หรือใน Git Repository Terraform จึงมีแนวคิดเรื่อง Backend หรือ Remote State ครับ Backend ช่วยให้เราสามารถเก็บ State File ไว้ในที่ที่ปลอดภัยและเข้าถึงได้จากหลาย ๆ คนในทีม ซึ่งเป็นสิ่งจำเป็นสำหรับการทำงานร่วมกัน
สำหรับ AWS Backend ที่นิยมใช้มากที่สุดคือ Amazon S3 ครับ โดยมักจะใช้ร่วมกับ Amazon DynamoDB เพื่อทำ State Locking (ป้องกันไม่ให้ผู้ใช้หลายคนพยายามแก้ไข Infrastructure เดียวกันพร้อมกัน ซึ่งอาจทำให้ State file เสียหายได้)
terraform {
backend "s3" {
bucket = "siamlancard-terraform-state-bucket-12345" # ชื่อ S3 bucket ที่ใช้เก็บ State
key = "dev/aws-vpc/terraform.tfstate" # Path ภายใน bucket
region = "ap-southeast-1"
encrypt = true # เข้ารหัสข้อมูลที่จัดเก็บใน S3
dynamodb_table = "siamlancard-terraform-lock" # DynamoDB table สำหรับ State Locking
}
}
การตั้งค่า Backend จะต้องทำก่อน terraform init ครับ เพราะ init จะเป็นตัวตั้งค่า Backend และดาวน์โหลด State file มายัง Local cache ของคุณครับ
การเข้าใจ Core Concepts เหล่านี้จะช่วยให้คุณมีพื้นฐานที่แข็งแกร่งในการเริ่มต้นใช้งาน Terraform กับ AWS ได้อย่างมั่นใจครับ
เริ่มต้นใช้งาน Terraform สำหรับ AWS: Step-by-Step Guide
มาถึงส่วนที่น่าตื่นเต้นที่สุดครับ เราจะมาลงมือทำจริงเพื่อสร้าง Infrastructure บน AWS ด้วย Terraform กันทีละขั้นตอนครับ
การติดตั้ง Terraform และการตั้งค่า AWS CLI
ก่อนอื่น คุณต้องติดตั้ง Terraform และตั้งค่า AWS CLI บนเครื่องของคุณเสียก่อนครับ
1. การติดตั้ง Terraform
Terraform สามารถติดตั้งได้ง่าย ๆ บนระบบปฏิบัติการส่วนใหญ่ครับ
-
สำหรับ macOS (ด้วย Homebrew):
brew tap hashicorp/tap brew install hashicorp/tap/terraform -
สำหรับ Windows (ด้วย Chocolatey):
choco install terraform -
สำหรับ Linux (Debian/Ubuntu):
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 > /dev/null 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
หลังจากติดตั้งแล้ว ให้ตรวจสอบว่า Terraform ถูกติดตั้งสำเร็จหรือไม่ด้วยคำสั่ง:
terraform -v
คุณควรจะเห็นเวอร์ชันของ Terraform ที่ติดตั้งไว้ครับ
2. การตั้งค่า AWS CLI และ Credentials
Terraform จำเป็นต้องมีสิทธิ์ในการเข้าถึง AWS Account ของคุณเพื่อสร้างทรัพยากรต่าง ๆ วิธีที่แนะนำคือการตั้งค่า AWS CLI ให้เรียบร้อยครับ
-
ติดตั้ง AWS CLI:
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip sudo ./aws/installหรือดูวิธีการติดตั้งสำหรับ OS อื่น ๆ ที่ AWS CLI Documentation ครับ
-
ตั้งค่า Credentials:
คุณสามารถสร้าง IAM User ที่มี Programmatic Access (Access Key ID และ Secret Access Key) ใน AWS Console หรือใช้ IAM Role สำหรับ EC2 Instances/Lambda Functions ก็ได้ครับ สำหรับการทดลองบนเครื่อง ให้ใช้ IAM User แล้วรันคำสั่ง:
aws configure AWS Access Key ID [None]: YOUR_ACCESS_KEY_ID AWS Secret Access Key [None]: YOUR_SECRET_ACCESS_KEY Default region name [None]: ap-southeast-1 Default output format [None]: jsonข้อมูลเหล่านี้จะถูกเก็บไว้ในไฟล์
~/.aws/credentialsและ~/.aws/configครับ Terraform จะใช้ข้อมูลนี้โดยอัตโนมัติหากคุณไม่ได้ระบุ Credentials อื่น ๆ ใน Provider block ครับ -
สิทธิ์ของ IAM User:
สำหรับบทความนี้ ให้สิทธิ์ IAM User ของคุณในการสร้าง S3 buckets, VPCs, Subnets, Internet Gateways, Route Tables, Security Groups, และ EC2 Instances ครับ หรือเพื่อความง่ายในการทดลอง คุณอาจจะให้สิทธิ์
AdministratorAccessชั่วคราว (แต่ไม่แนะนำสำหรับ Production environment ครับ)
โปรเจกต์แรก: สร้าง S3 Bucket ด้วย Terraform
มาเริ่มต้นด้วยการสร้าง S3 Bucket ซึ่งเป็นทรัพยากรที่ค่อนข้างเรียบง่ายกันครับ
1. สร้างไดเรกทอรีโปรเจกต์
mkdir terraform-s3-demo
cd terraform-s3-demo
2. สร้างไฟล์ main.tf
สร้างไฟล์ชื่อ main.tf ภายในไดเรกทอรี terraform-s3-demo และเพิ่มโค้ดต่อไปนี้:
# main.tf
# 1. กำหนด Terraform version และ AWS Provider
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "ap-southeast-1" # ตั้งค่า AWS Region เป็น Singapore
}
# 2. สร้าง S3 Bucket resource
resource "aws_s3_bucket" "my_first_bucket" {
# ชื่อ bucket ต้องไม่ซ้ำกันทั่วโลก แนะนำให้ใส่ prefix หรือ random string
bucket = "siamlancard-demo-bucket-20231027-unique"
tags = {
Name = "MyFirstTerraformBucket"
Environment = "Dev"
Project = "SiamLancard"
}
}
# 3. สร้าง Output เพื่อแสดงชื่อ Bucket หลังจากสร้างเสร็จ
output "bucket_name" {
description = "The name of the S3 bucket"
value = aws_s3_bucket.my_first_bucket.bucket
}
output "bucket_id" {
description = "The ID of the S3 bucket"
value = aws_s3_bucket.my_first_bucket.id
}
output "bucket_arn" {
description = "The ARN of the S3 bucket"
value = aws_s3_bucket.my_first_bucket.arn
}
**ข้อควรระวัง:** ชื่อ S3 Bucket (siamlancard-demo-bucket-20231027-unique) ต้องไม่ซ้ำกันทั่วโลกครับ คุณอาจจะต้องเปลี่ยนเป็นชื่ออื่นที่เฉพาะเจาะจงสำหรับคุณเองครับ
3. รันคำสั่ง Terraform
เปิด Terminal ในไดเรกทอรี terraform-s3-demo แล้วทำตามขั้นตอนเหล่านี้:
-
Initialize Terraform:
terraform initคำสั่งนี้จะดาวน์โหลด AWS Provider และตั้งค่า Backend (ในกรณีนี้คือ Local backend โดยปริยาย) คุณจะเห็นข้อความว่า
Terraform has been successfully initialized! -
Generate and Review an Execution Plan:
terraform planคำสั่ง
planจะวิเคราะห์โค้ด Terraform ของคุณ เปรียบเทียบกับสถานะปัจจุบันของ Infrastructure (ถ้ามี) และแสดงให้เห็นว่า Terraform จะทำอะไรบ้างเพื่อไปถึงสถานะที่คุณต้องการครับ คุณจะเห็นว่า Terraform จะ+ createS3 Bucket หนึ่งอันครับTerraform will perform the following actions:
# aws_s3_bucket.my_first_bucket will be created
+ resource “aws_s3_bucket” “my_first_bucket” {
… (รายละเอียดการสร้าง S3 bucket)
plan: 1 to add, 0 to change, 0 to destroy.
-
Apply the Changes:
terraform applyคำสั่ง
applyจะดำเนินการตาม Execution Plan ที่planสร้างไว้ มันจะถามให้คุณยืนยัน (พิมพ์yes) ก่อนที่จะเริ่มสร้างทรัพยากรจริง ๆ บน AWS ครับ หลังจากนั้น Terraform จะสร้าง S3 Bucket ของคุณบน AWS และแสดงค่า Output ที่เรากำหนดไว้ครับคุณสามารถเข้าไปตรวจสอบ S3 Bucket ที่สร้างขึ้นได้ใน AWS Management Console ได้เลยครับ
-
Destroy the Infrastructure (เมื่อเสร็จสิ้น):
terraform destroyเมื่อคุณไม่ต้องการใช้ S3 Bucket นี้แล้ว และต้องการลบทิ้งทั้งหมด คำสั่ง
destroyจะลบทรัพยากรทั้งหมดที่ถูกจัดการโดย Terraform ในโปรเจกต์นี้ออกไปครับ มันจะถามให้คุณยืนยันเช่นกัน (พิมพ์yes) เพื่อป้องกันการลบโดยไม่ตั้งใจครับ
ตัวอย่างที่ซับซ้อนขึ้น: สร้าง VPC, Subnets และ EC2 Instance
คราวนี้เรามาลองสร้าง Infrastructure ที่ซับซ้อนขึ้นอีกนิดครับ โดยจะสร้าง Virtual Private Cloud (VPC), Public and Private Subnets, Internet Gateway, Route Table, Security Group, และ EC2 Instance หนึ่งตัว
1. สร้างไดเรกทอรีโปรเจกต์ใหม่
mkdir terraform-vpc-ec2-demo
cd terraform-vpc-ec2-demo
2. สร้างไฟล์ Terraform
เราจะแยกโค้ดออกเป็นหลายไฟล์เพื่อความเป็นระเบียบครับ
main.tf
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
# เรียกใช้ VPC module
module "vpc" {
source = "./modules/vpc" # สมมติว่ามี module vpc อยู่ใน ./modules/vpc
project_name = var.project_name
env_name = var.environment_name
vpc_cidr = var.vpc_cidr_block
public_subnets_cidr = var.public_subnets_cidr
private_subnets_cidr = var.private_subnets_cidr
tags = {
Project = var.project_name
Environment = var.environment_name
}
}
# สร้าง EC2 Instance โดยใช้ VPC และ Subnet ที่สร้างจาก module
resource "aws_instance" "web_server" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
subnet_id = module.vpc.public_subnets[0] # วาง EC2 ใน Public Subnet แรก
vpc_security_group_ids = [aws_security_group.web_sg.id]
key_name = var.key_pair_name # ต้องมี Key Pair ใน AWS ก่อน
tags = {
Name = "${var.project_name}-${var.environment_name}-WebServer"
Environment = var.environment_name
}
}
# Data Source สำหรับดึง AMI ID ของ Ubuntu
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
# Security Group สำหรับ Web Server (เปิด Port 22 และ 80)
resource "aws_security_group" "web_sg" {
name = "${var.project_name}-${var.environment_name}-Web-SG"
description = "Allow HTTP and SSH inbound traffic"
vpc_id = module.vpc.vpc_id # อ้างอิง VPC ID จาก module vpc
ingress {
description = "SSH from anywhere"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTP from anywhere"
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 = "${var.project_name}-${var.environment_name}-Web-SG"
}
}
variables.tf
# variables.tf
variable "aws_region" {
description = "The AWS region to deploy resources in"
type = string
default = "ap-southeast-1"
}
variable "project_name" {
description = "Name of the project"
type = string
default = "SiamLancardApp"
}
variable "environment_name" {
description = "Name of the environment (e.g., dev, staging, prod)"
type = string
default = "dev"
}
variable "vpc_cidr_block" {
description = "CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
variable "public_subnets_cidr" {
description = "List of CIDR blocks for public subnets"
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
variable "private_subnets_cidr" {
description = "List of CIDR blocks for private subnets"
type = list(string)
default = ["10.0.101.0/24", "10.0.102.0/24"]
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t2.micro"
}
variable "key_pair_name" {
description = "Name of an existing EC2 Key Pair to use"
type = string
# คุณต้องเปลี่ยนค่า default เป็นชื่อ Key Pair ที่คุณมีใน AWS
default = "your-ec2-key-pair"
}
**สำคัญ:** คุณต้องมี EC2 Key Pair ที่สร้างไว้แล้วใน AWS Region ที่เลือก และเปลี่ยนค่า default ของ key_pair_name ให้เป็นชื่อ Key Pair ของคุณครับ
outputs.tf
# outputs.tf
output "vpc_id" {
description = "The ID of the VPC"
value = module.vpc.vpc_id
}
output "public_subnet_ids" {
description = "IDs of the public subnets"
value = module.vpc.public_subnets
}
output "web_server_public_ip" {
description = "Public IP address of the web server"
value = aws_instance.web_server.public_ip
}
output "web_server_private_ip" {
description = "Private IP address of the web server"
value = aws_instance.web_server.private_ip
}
สร้าง Module สำหรับ VPC
สร้างโฟลเดอร์ modules/vpc ภายในไดเรกทอรี terraform-vpc-ec2-demo
mkdir -p modules/vpc
จากนั้นสร้างไฟล์ main.tf ภายใน modules/vpc:
modules/vpc/main.tf
# modules/vpc/main.tf
# VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(var.tags, {
Name = "${var.project_name}-${var.env_name}-VPC"
})
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = merge(var.tags, {
Name = "${var.project_name}-${var.env_name}-IGW"
})
}
# Public Subnets
resource "aws_subnet" "public" {
count = length(var.public_subnets_cidr)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets_cidr[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index] # ใช้ AZs ที่มีอยู่
map_public_ip_on_launch = true # ทำให้ EC2 ใน Public Subnet ได้รับ Public IP
tags = merge(var.tags, {
Name = "${var.project_name}-${var.env_name}-PublicSubnet-${count.index + 1}"
})
}
# Private Subnets
resource "aws_subnet" "private" {
count = length(var.private_subnets_cidr)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnets_cidr[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = merge(var.tags, {
Name = "${var.project_name}-${var.env_name}-PrivateSubnet-${count.index + 1}"
})
}
# Route Table สำหรับ Public Subnets
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0" # Route traffic ออก Internet
gateway_id = aws_internet_gateway.main.id
}
tags = merge(var.tags, {
Name = "${var.project_name}-${var.env_name}-PublicRT"
})
}
# เชื่อม Public Route Table เข้ากับ Public Subnets
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
# Data Source สำหรับดึง Availability Zones ที่ใช้ได้ใน Region
data "aws_availability_zones" "available" {
state = "available"
}
modules/vpc/variables.tf
# modules/vpc/variables.tf
variable "project_name" {
description = "Name of the project"
type = string
}
variable "env_name" {
description = "Name of the environment"
type = string
}
variable "vpc_cidr" {
description = "CIDR block for the VPC"
type = string
}
variable "public_subnets_cidr" {
description = "List of CIDR blocks for public subnets"
type = list(string)
}
variable "private_subnets_cidr" {
description = "List of CIDR blocks for private subnets"
type = list(string)
}
variable "tags" {
description = "A map of tags to assign to the resources"
type = map(string)
default = {}
}
modules/vpc/outputs.tf
# modules/vpc/outputs.tf
output "vpc_id" {
description = "The ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnets" {
description = "List of public subnet IDs"
value = aws_subnet.public.*.id # ใช้ Splat expression เพื่อดึง ID ของทุก Public Subnet
}
output "private_subnets" {
description = "List of private subnet IDs"
value = aws_subnet.private.*.id
}
3. รันคำสั่ง Terraform
กลับมาที่ไดเรกทอรีหลัก terraform-vpc-ec2-demo แล้วรันคำสั่ง:
-
Initialize Terraform:
terraform initครั้งนี้ Terraform จะดาวน์โหลด AWS Provider และ Module ที่เราสร้างไว้ (
./modules/vpc) ครับ -
Generate and Review an Execution Plan:
terraform planคุณจะเห็นรายการทรัพยากรจำนวนมากที่ Terraform จะสร้างขึ้น (VPC, IGW, Subnets, Route Tables, EC2, SG) ตรวจสอบให้แน่ใจว่าทุกอย่างถูกต้องครับ
-
Apply the Changes:
terraform applyพิมพ์
yesเพื่อยืนยัน Terraform จะเริ่มสร้าง Infrastructure ของคุณบน AWS ครับ กระบวนการนี้อาจใช้เวลาสักครู่ เมื่อเสร็จสิ้น คุณจะเห็น Output ที่เป็น ID ของ VPC และ Public IP ของ EC2 Instance ครับคุณสามารถลอง SSH เข้าไปที่ EC2 Instance โดยใช้ Public IP ที่ได้จาก Output และ Key Pair ของคุณได้เลยครับ
-
Destroy the Infrastructure:
terraform destroyเมื่อทดสอบเสร็จแล้ว อย่าลืมลบทรัพยากรเหล่านี้ทิ้งเพื่อหลีกเลี่ยงค่าใช้จ่ายที่ไม่จำเป็นครับ พิมพ์
yesเพื่อยืนยันการลบครับ
นี่คือตัวอย่างพื้นฐานของการใช้ Terraform เพื่อสร้าง Infrastructure ที่ซับซ้อนขึ้นบน AWS ครับ การใช้ Modules ทำให้โค้ดของเราจัดระเบียบได้ดีขึ้นและนำกลับมาใช้ใหม่ได้ง่ายขึ้นครับ
Best Practices ในการใช้ Terraform กับ AWS
เพื่อให้การใช้ Terraform กับ AWS มีประสิทธิภาพ, ปลอดภัย, และยืดหยุ่นในระยะยาว การปฏิบัติตาม Best Practices จึงเป็นสิ่งสำคัญมากครับ
1. การจัดการ Remote State อย่างปลอดภัย (S3 + DynamoDB)
อย่างที่เราได้กล่าวไปแล้วว่า Terraform State file (.tfstate) มีข้อมูลที่สำคัญและละเอียดอ่อนมาก การเก็บไว้ในเครื่อง Local หรือใน Git Repository โดยตรงนั้นไม่ปลอดภัยและไม่เหมาะกับการทำงานเป็นทีมอย่างยิ่งครับ
Solution: ใช้ Remote State Backend
สำหรับ AWS ทางเลือกที่ดีที่สุดคือการใช้ Amazon S3 Bucket ในการจัดเก็บ State file และใช้ Amazon DynamoDB Table ในการจัดการ State Locking ครับ
- S3 Bucket: จัดเก็บ State file ไว้ใน S3 Bucket ที่มีการตั้งค่า Encryption (SSE-S3 หรือ KMS), Versioning (เพื่อย้อนกลับเวอร์ชัน State ได้), และ Block Public Access อย่างเข้มงวด
- DynamoDB Table: ใช้ DynamoDB Table เพื่อทำ State Locking ป้องกันไม่ให้ผู้ใช้หลายคนแก้ไข State file เดียวกันพร้อมกัน ซึ่งอาจทำให้ State file เสียหายได้
ตัวอย่างการตั้งค่า Backend ใน main.tf:
terraform {
backend "s3" {
bucket = "siamlancard-terraform-state-bucket-unique" # ต้องเป็นชื่อที่ไม่ซ้ำกันทั่วโลก
key = "environments/dev/my-app/terraform.tfstate" # กำหนด path สำหรับแต่ละ environment/project
region = "ap-southeast-1"
encrypt = true
dynamodb_table = "siamlancard-terraform-lock-table" # DynamoDB table สำหรับ State Locking
}
}
ก่อนจะรัน terraform init คุณต้องสร้าง S3 Bucket และ DynamoDB Table เหล่านี้ด้วยมือ (หรือใช้ Terraform สร้างในอีก Project หนึ่งก็ได้ครับ)
# สำหรับสร้าง S3 bucket และ DynamoDB table ด้วย Terraform (แยก project)
resource "aws_s3_bucket" "terraform_state_bucket" {
bucket = "siamlancard-terraform-state-bucket-unique"
lifecycle {
prevent_destroy = true # ป้องกันการลบ bucket โดยไม่ตั้งใจ
}
tags = {
Name = "Terraform State Bucket"
}
}
resource "aws_s3_bucket_versioning" "terraform_state_bucket_versioning" {
bucket = aws_s3_bucket.terraform_state_bucket.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state_bucket_encryption" {
bucket = aws_s3_bucket.terraform_state_bucket.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "siamlancard-terraform-lock-table"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform Lock Table"
}
}
รันโค้ดนี้ในโปรเจกต์แยกต่างหากครั้งเดียวเพื่อเตรียม Remote State Backend ให้พร้อมใช้งานครับ
2. การใช้ Modules เพื่อความยืดหยุ่นและการนำกลับมาใช้ใหม่
เมื่อ Infrastructure ของคุณเริ่มซับซ้อน การจัดระเบียบโค้ดด้วย Modules จะช่วยให้โปรเจกต์ของคุณจัดการได้ง่ายขึ้นมากครับ
- สร้าง Modules สำหรับ Components ทั่วไป: เช่น VPC, ECS Cluster, RDS Database, Lambda Function
- ทำให้ Modules สามารถตั้งค่าได้ (Configurable): ใช้ Input Variables และ Output Values เพื่อให้ Modules ยืดหยุ่นและนำไปใช้ในบริบทที่แตกต่างกันได้
- ใช้ Modules จาก Terraform Registry: สำหรับ Components มาตรฐานที่มีอยู่แล้ว (เช่น VPC module ของ AWS) การใช้ Modules จาก Registry ช่วยประหยัดเวลาและมั่นใจได้ว่าได้รับการดูแลจากชุมชน
# ตัวอย่างการใช้ Module จาก Terraform Registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.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"]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Environment = "dev"
}
}
3. การใช้ Workspaces สำหรับ Multiple Environments
Workspaces ช่วยให้คุณสามารถจัดการหลายสภาพแวดล้อม (เช่น dev, staging, prod) ได้โดยใช้ชุดโค้ด Terraform ชุดเดียวกัน แต่มี State file แยกกันครับ
# สร้าง workspace สำหรับ staging
terraform workspace new staging
# สลับไปใช้ workspace dev
terraform workspace select dev
# แสดง workspace ปัจจุบัน
terraform workspace show
คุณสามารถใช้ Workspaces ใน backend.s3.key เพื่อแยก State file ของแต่ละ Environment ได้:
terraform {
backend "s3" {
bucket = "siamlancard-terraform-state-bucket-unique"
key = "environments/${terraform.workspace}/my-app/terraform.tfstate" # ใช้ terraform.workspace
region = "ap-southeast-1"
encrypt = true
dynamodb_table = "siamlancard-terraform-lock-table"
}
}
และใช้ใน Variable เพื่อปรับค่าตาม Environment:
variable "instance_type" {
description = "EC2 instance type"
type = string
default = {
"dev" = "t2.micro"
"staging" = "t3.medium"
"prod" = "m5.large"
}[terraform.workspace]
}
4. การใช้ Version Control (Git)
โค้ด Terraform คือโค้ดโปรแกรมครับ ดังนั้นควรจัดเก็บไว้ในระบบ Version Control เช่น Git เสมอครับ
- Git Repository: เก็บโค้ด Terraform ทั้งหมดใน Git repository
- Branching Strategy: ใช้ Git Flow หรือ Trunk-based development เพื่อจัดการการเปลี่ยนแปลง
- Code Review: ทำ Code Review สำหรับทุกการเปลี่ยนแปลงในโค้ด Terraform เพื่อป้องกันข้อผิดพลาดและรักษาคุณภาพ
-
.gitignore: อย่าลืมเพิ่ม.terraform/และ.terraform.lock.hcl(และ*.tfvarsหากมี sensitive data) ลงใน.gitignore
5. การจัดการ Sensitive Data
ไม่ควรเก็บ Sensitive Data (เช่น Database Passwords, API Keys) ไว้ในโค้ด Terraform หรือ State file โดยตรงครับ
Solution: ใช้บริการจัดการ Secrets ของ AWS
- AWS Secrets Manager: สำหรับข้อมูลที่เป็น Secret จริง ๆ เช่น รหัสผ่านฐานข้อมูล, API keys
- AWS Systems Manager Parameter Store (Secure String): สำหรับข้อมูลที่ไม่ใช่ Secret แต่ไม่ควรเปิดเผย เช่น ชื่อผู้ใช้, หรือข้อมูลที่ต้องการเข้ารหัส
จากนั้นใช้ Terraform Data Sources เพื่อดึงค่าเหล่านี้มาใช้ครับ
data "aws_secretsmanager_secret" "db_password_secret" {
name = "my-app-db-password"
}
data "aws_secretsmanager_secret_version" "db_password_version" {
secret_id = data.aws_secretsmanager_secret.db_password_secret.id
}
resource "aws_rds_cluster" "my_db" {
# ...
master_password = jsondecode(data.aws_secretsmanager_secret_version.db_password_version.secret_string)["password"]
# ...
}
6. การทดสอบ Terraform Code
แม้ว่า Terraform จะมี terraform plan เพื่อแสดงการเปลี่ยนแปลง แต่ก็ยังไม่เพียงพอที่จะมั่นใจว่า Infrastructure จะทำงานได้ตามที่คาดหวังครับ
-
Static Analysis: ใช้เครื่องมือเช่น
terraform validateหรือtflintเพื่อตรวจสอบไวยากรณ์และ Best Practices - Integration Testing: สร้าง Infrastructure ในสภาพแวดล้อม Dev/Staging จริง ๆ แล้วรัน Automated Tests เพื่อตรวจสอบการทำงาน
- Policy as Code: ใช้ HashiCorp Sentinel หรือ Open Policy Agent (OPA) เพื่อบังคับใช้กฎด้านความปลอดภัยและ Compliance ก่อนที่จะทำการ Apply ครับ
7. การกำหนด Naming Convention
การมี Naming Convention ที่ชัดเจนสำหรับทรัพยากร AWS จะช่วยให้คุณและทีมสามารถระบุและจัดการทรัพยากรได้ง่ายขึ้นมากครับ
- ใช้ Tags: ใช้ AWS Tags อย่างสม่ำเสมอเพื่อระบุ Project, Environment, Owner, Cost Center ฯลฯ
-
ชื่อทรัพยากร: ใช้รูปแบบที่สอดคล้องกัน เช่น
<project>-<environment>-<resource-type>-<identifier>(เช่นsiamlancard-dev-ec2-webserver-01)
resource "aws_instance" "web_server" {
# ...
tags = {
Name = "${var.project_name}-${var.environment_name}-WebServer"
Project = var.project_name
Environment = var.environment_name
Owner = "devops-team"
}
}
การปฏิบัติตาม Best Practices เหล่านี้จะช่วยให้คุณใช้ Terraform กับ AWS ได้อย่างมีประสิทธิภาพ, ปลอดภัย, และยั่งยืนในระยะยาวครับ
ข้อดีและข้อจำกัดของ Terraform บน AWS
ทุกเครื่องมือย่อมมีทั้งข้อดีและข้อจำกัดครับ Terraform ก็เช่นกัน การเข้าใจข้อดีและข้อจำกัดจะช่วยให้คุณตัดสินใจได้ดีขึ้นว่าจะใช้ Terraform ในสถานการณ์ใด และควรจะระมัดระวังในเรื่องใดบ้าง