ทำไมต้อง Infrastructure as Code
ผมเคยสร้าง servers ด้วยมือทุกครั้งที่ต้อง provision server ใหม่ก็ต้อง SSH เข้าไปติดตั้ง packages configure services ทำซ้ำเหมือนเดิมทุกครั้งถ้ามี 5 servers ก็ทำ 5 รอบถ้าทำผิดขั้นตอนก็ไม่มีทาง replicate ได้ IaC แก้ปัญหานี้ทั้งหมด
Terraform เป็น IaC tool ที่ได้รับความนิยมมากที่สุดพัฒนาโดย HashiCorp ใช้ภาษา HCL (HashiCorp Configuration Language) ที่อ่านง่ายรองรับ providers มากกว่า 3,000 ตัวตั้งแต่ AWS, Azure, GCP ไปจนถึง Proxmox VE, Cloudflare, GitHub และอีกมากมาย
Terraform vs Ansible vs Pulumi
Terraform เน้น provisioning infrastructure (สร้าง VMs, networks, storage) ใช้ declarative approach คุณบอกว่าต้องการอะไร Terraform จัดการให้ Ansible เน้น configuration management (ติดตั้ง packages, configure services) ใช้ imperative approach Pulumi เหมือน Terraform แต่ใช้ภาษา programming จริง (Python, TypeScript, Go) แทน HCL ผมใช้ Terraform สำหรับ provisioning และ Ansible สำหรับ configuration
ติดตั้ง Terraform
# Ubuntu
wget -O - https://apt.releases.hashicorp.com/gpg | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/hashicorp.list
apt update && apt install terraform
terraform version
# Terraform v1.9.x
OpenTofu — Open Source Fork
# OpenTofu เป็น fork ของ Terraform หลัง HashiCorp เปลี่ยน license เป็น BSL
# Compatible กับ Terraform 100%
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh -o install-opentofu.sh
chmod +x install-opentofu.sh
./install-opentofu.sh --install-method deb
tofu version
# OpenTofu v1.8.x
# ใช้ tofu แทน terraform ได้เลย ทุก command เหมือนกัน
โครงสร้างไฟล์พื้นฐาน
# providers.tf — กำหนด providers
terraform {
required_version = ">= 1.9.0"
required_providers {
proxmox = {
source = "telmate/proxmox"
version = "~> 3.0"
}
}
}
provider "proxmox" {
pm_api_url = "https://pve1.example.com:8006/api2/json"
pm_user = "terraform@pam"
pm_password = var.proxmox_password
pm_tls_insecure = true
}
# variables.tf — กำหนดตัวแปร
variable "proxmox_password" {
type = string
sensitive = true
}
variable "vm_count" {
type = number
default = 3
}
variable "vm_memory" {
type = number
default = 4096
}
# main.tf — สร้าง resources
resource "proxmox_vm_qemu" "web_server" {
count = var.vm_count
name = "web-"
target_node = "pve1"
clone = "ubuntu-cloud-template"
cores = 4
memory = var.vm_memory
scsihw = "virtio-scsi-single"
os_type = "cloud-init"
disk {
storage = "local-zfs"
size = "32G"
type = "scsi"
}
network {
model = "virtio"
bridge = "vmbr0"
}
ipconfig0 = "ip=10.10.10./24, gw=10.10.10.1"
ciuser = "admin"
sshkeys = file("~/.ssh/id_ed25519.pub")
lifecycle {
ignore_changes = [network]
}
}
# outputs.tf — แสดงผลลัพธ์
output "vm_ips" {
value = [for vm in proxmox_vm_qemu.web_server : vm.default_ipv4_address]
}
Terraform Workflow
# 1. Initialize — ดาวน์โหลด providers
terraform init
# 2. Plan — ดูว่าจะสร้าง/แก้ไขอะไร
terraform plan -out=tfplan
# + proxmox_vm_qemu.web_server[0] will be created
# + proxmox_vm_qemu.web_server[1] will be created
# + proxmox_vm_qemu.web_server[2] will be created
# Plan: 3 to add, 0 to change, 0 to destroy.
# 3. Apply — สร้าง infrastructure จริง
terraform apply tfplan
# 4. ดู state
terraform state list
terraform state show proxmox_vm_qemu.web_server[0]
# 5. Destroy — ลบทั้งหมด (ระวัง!)
terraform destroy
State Management
Terraform state เป็นไฟล์ที่เก็บ mapping ระหว่าง configuration กับ real infrastructure สำคัญมากถ้า state หาย Terraform จะไม่รู้ว่ามี resources อะไรอยู่
Remote State Backend
# ใช้ S3 backend สำหรับ shared state
terraform {
backend "s3" {
bucket = "terraform-state-prod"
key = "infrastructure/terraform.tfstate"
region = "ap-southeast-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# หรือใช้ MinIO สำหรับ on-premise
terraform {
backend "s3" {
bucket = "terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
endpoint = "https://minio.example.com"
skip_credentials_validation = true
skip_metadata_api_check = true
force_path_style = true
}
}
State Commands
# ดู resources ใน state
terraform state list
# ย้าย resource (เช่น rename)
terraform state mv proxmox_vm_qemu.web proxmox_vm_qemu.web_server
# Import existing resource เข้า state
terraform import proxmox_vm_qemu.existing_vm pve1/qemu/100
# ลบ resource จาก state (ไม่ลบจริง)
terraform state rm proxmox_vm_qemu.web_server[2]
สร้าง Module
# modules/proxmox-vm/main.tf
variable "name" { type = string }
variable "node" { type = string; default = "pve1" }
variable "template" { type = string; default = "ubuntu-cloud-template" }
variable "cores" { type = number; default = 2 }
variable "memory" { type = number; default = 2048 }
variable "disk_size" { type = string; default = "20G" }
variable "ip" { type = string }
variable "gateway" { type = string; default = "10.10.10.1" }
variable "ssh_key" { type = string }
resource "proxmox_vm_qemu" "vm" {
name = var.name
target_node = var.node
clone = var.template
cores = var.cores
memory = var.memory
os_type = "cloud-init"
disk {
storage = "local-zfs"
size = var.disk_size
type = "scsi"
}
network {
model = "virtio"
bridge = "vmbr0"
}
ipconfig0 = "ip=/24, gw="
sshkeys = var.ssh_key
}
output "ip" { value = var.ip }
output "name" { value = var.name }
# ใช้ Module
module "web_servers" {
source = "./modules/proxmox-vm"
for_each = {
"web-1" = "10.10.10.101"
"web-2" = "10.10.10.102"
"web-3" = "10.10.10.103"
}
name = each.key
ip = each.value
cores = 4
memory = 4096
ssh_key = file("~/.ssh/id_ed25519.pub")
}
module "db_server" {
source = "./modules/proxmox-vm"
name = "db-1"
ip = "10.10.10.201"
cores = 8
memory = 16384
disk_size = "100G"
ssh_key = file("~/.ssh/id_ed25519.pub")
}
Provision VMs แบบ Production
# terraform.tfvars — ค่าตัวแปร
proxmox_password = "SecurePassword123!"
environment = "production"
domain = "example.com"
ssh_public_key = <<-EOT
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBxxxxxxxxxxxxxxxxxxxxxxxx admin@workstation
EOT
servers = {
"web-1" = { ip = "10.10.10.101", cores = 4, memory = 4096, disk = "32G", role = "web" }
"web-2" = { ip = "10.10.10.102", cores = 4, memory = 4096, disk = "32G", role = "web" }
"api-1" = { ip = "10.10.10.111", cores = 4, memory = 8192, disk = "32G", role = "api" }
"db-1" = { ip = "10.10.10.201", cores = 8, memory = 16384, disk = "100G", role = "db" }
"redis-1" = { ip = "10.10.10.211", cores = 2, memory = 8192, disk = "20G", role = "cache" }
"monitor" = { ip = "10.10.10.251", cores = 4, memory = 8192, disk = "50G", role = "monitor" }
}
Directory Structure
infrastructure/
├── environments/
│ ├── production/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── terraform.tfvars
│ │ └── backend.tf
│ └── staging/
│ ├── main.tf
│ ├── variables.tf
│ └── terraform.tfvars
├── modules/
│ ├── proxmox-vm/
│ ├── networking/
│ └── monitoring/
└── README.md
Security Best Practices
# 1. ใช้ .gitignore สำหรับ sensitive files
*.tfvars
*.tfstate
*.tfstate.backup
.terraform/
# 2. ใช้ Vault สำหรับ secrets
data "vault_generic_secret" "db_password" {
path = "secret/database/production"
}
# 3. ใช้ sensitive = true
variable "db_password" {
type = string
sensitive = true
}
# 4. Plan ก่อน Apply เสมอ
terraform plan -out=tfplan
terraform apply tfplan
Best Practices สำหรับนักพัฒนา
การเขียนโค้ดที่ดีไม่ใช่แค่ทำให้โปรแกรมทำงานได้ แต่ต้องเขียนให้อ่านง่าย ดูแลรักษาง่าย และ Scale ได้ หลัก SOLID Principles เป็นพื้นฐานสำคัญที่นักพัฒนาทุกู้คืนควรเข้าใจ ได้แก่ Single Responsibility ที่แต่ละ Class ทำหน้าที่เดียว Open-Closed ที่เปิดให้ขยายแต่ปิดการแก้ไข Liskov Substitution ที่ Subclass ต้องใช้แทน Parent ได้ Interface Segregation ที่แยก Interface ให้เล็ก และ Dependency Inversion ที่พึ่งพา Abstraction ไม่ใช่ Implementation
เรื่อง Testing ก็ขาดไม่ได้ ควรเขียน Unit Test ครอบคลุมอย่างน้อย 80% ของ Code Base ใช้ Integration Test ทดสอบการทำงานร่วมกันของ Module ต่างๆ และ E2E Test สำหรับ Critical User Flow เครื่องมือยอดนิยมเช่น Jest, Pytest, JUnit ช่วยให้การเขียน Test เป็นเรื่องง่าย
เรื่อง Version Control ด้วย Git ใช้ Branch Strategy ที่เหมาะกับทีม เช่น Git Flow สำหรับโปรเจคใหญ่ หรือ Trunk-Based Development สำหรับทีมที่ Deploy บ่อย ทำ Code Review ทุก Pull Request และใช้ CI/CD Pipeline ทำ Automated Testing และ Deployment
Terraform กับ OpenTofu ใช้ตัวไหนดี?
OpenTofu เป็น fully compatible fork ของ Terraform ที่เป็น open-source จริงๆ (MPL license) หลังจาก HashiCorp เปลี่ยนเป็น BSL ในปี 2023 สำหรับ projects ใหม่ผมแนะนำ OpenTofu เพราะไม่มีความเสี่ยงเรื่อง license changes ในอนาคตทุก Terraform config ใช้กับ OpenTofu ได้เลยไม่ต้องแก้อะไร
State file สำคัญแค่ไหน?
สำคัญมากครับถ้า state file หาย Terraform จะไม่รู้ว่ามี resources อะไรอยู่ต้อง import ทุก resource กลับมาเองซึ่งเจ็บปวดมากใช้ remote backend เสมอ (S3, MinIO, Consul) พร้อม locking เพื่อป้องกัน concurrent modifications และ backup state file สม่ำเสมอ
Terraform ใช้กับ on-premise ได้ไหมไม่ใช้ cloud?
ได้ครับผมใช้ Terraform กับ Proxmox VE เป็นหลักสร้าง VMs, LXC containers, จัดการ networks ทั้งหมดบน on-premise servers ไม่ต้องใช้ public cloud เลยนอกจากนี้ยังใช้กับ DNS (Cloudflare, PowerDNS), monitoring (Grafana), secrets (Vault) ได้ด้วย
เรียน Terraform ยากไหม?
HCL เป็นภาษาที่เรียนง่ายมากง่ายกว่า programming language ทั่วไปถ้าเข้าใจ concept ของ resources, variables, outputs, modules ก็ใช้ได้แล้วสิ่งที่ต้องเข้าใจดีคือ state management และ plan/apply workflow ใช้เวลา 1-2 สัปดาห์ก็เริ่มใช้ production ได้
สรุป
Terraform/OpenTofu เป็นเครื่องมือ IaC ที่ทุก DevOps และ SysAdmin ควรรู้มันทำให้ infrastructure เป็น reproducible, version controlled และ auditable ไม่ว่าจะเป็น cloud หรือ on-premise ร่วมกับ Git สำหรับ version control ทำให้ทุกการเปลี่ยนแปลง infrastructure ผ่าน review process ได้
ผมแนะนำให้เริ่มจาก project เล็กๆก่อนเช่น provision 3-5 VMs บน Proxmox แล้วค่อยขยายไปจนครอบคลุม infrastructure ทั้งหมดครับ
