tfvars และการแยก Environment

📖 text • 10 นาที

tfvars และการแยก Environment

ปัญหา: Code เหมือนกัน แต่ค่าต่างกัน

Production กับ Development ใช้ resource เหมือนกัน แต่:

Dev Production
Instance type t2.micro t3.large
Instance count 1 3
Monitoring off on
Domain dev.myapp.com myapp.com

ไม่ต้อง copy code — ใช้ tfvars file แยกค่าตาม environment

tfvars Files

terraform.tfvars — อ่านอัตโนมัติ

# terraform.tfvars
environment   = "dev"
instance_type = "t2.micro"
instance_count = 1

*.auto.tfvars — อ่านอัตโนมัติ

# common.auto.tfvars
project   = "myapp"
region    = "ap-southeast-1"

Custom tfvars — ต้องระบุ flag

# environments/dev.tfvars
environment    = "dev"
instance_type  = "t2.micro"
instance_count = 1
monitoring     = false
# environments/prod.tfvars
environment    = "prod"
instance_type  = "t3.large"
instance_count = 3
monitoring     = true
# Deploy dev
terraform apply -var-file="environments/dev.tfvars"

# Deploy prod
terraform apply -var-file="environments/prod.tfvars"

โครงสร้างโปรเจค

my-project/
├── main.tf
├── variables.tf
├── outputs.tf
├── locals.tf
├── providers.tf
└── environments/
    ├── dev.tfvars
    ├── staging.tfvars
    └── prod.tfvars

variables.tf

variable "environment" {
  description = "Deployment environment (dev, staging, prod)"
  type        = string

  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
  default     = "t2.micro"
}

variable "instance_count" {
  description = "Number of EC2 instances"
  type        = number
  default     = 1
}

variable "monitoring" {
  description = "Enable detailed monitoring"
  type        = bool
  default     = false
}

locals.tf

locals {
  name_prefix = "myapp-${var.environment}"

  common_tags = {
    Project     = "myapp"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

main.tf

resource "aws_instance" "web" {
  count         = var.instance_count
  ami           = data.aws_ami.amazon_linux.id
  instance_type = var.instance_type
  monitoring    = var.monitoring

  tags = merge(local.common_tags, {
    Name = "${local.name_prefix}-web-${count.index}"
  })
}

Workspace vs tfvars

Terraform มี workspace สำหรับแยก state:

# สร้าง workspace
terraform workspace new dev
terraform workspace new prod

# สลับ workspace
terraform workspace select dev

# ดู workspace ปัจจุบัน
terraform workspace show

ใช้ใน code:

locals {
  environment = terraform.workspace
}

เมื่อไรใช้อะไร?

Approach ข้อดี ข้อเสีย
tfvars ชัดเจน, explicit ต้องจำ flag
Workspace แยก state อัตโนมัติ ซ่อน context, ลืมว่าอยู่ workspace ไหน

แนะนำ: ใช้ tfvars + แยก state path สำหรับ production — ชัดเจนกว่า workspace

Priority Order

เมื่อค่าซ้ำกัน Terraform ใช้ค่าที่ priority สูงสุด:

1. default value             ← ต่ำสุด
2. terraform.tfvars
3. *.auto.tfvars (alphabetical)
4. -var-file flag
5. TF_VAR_xxx environment variable
6. -var flag                 ← สูงสุด

ตัวอย่าง:

# variables.tf
variable "region" {
  default = "ap-southeast-1"    # priority 1
}
# terraform.tfvars
region = "us-east-1"            # priority 2 — ชนะ default
terraform apply -var="region=eu-west-1"  # priority 6 — ชนะทุกอัน
# ผลลัพธ์: region = "eu-west-1"

Best Practices

  1. ค่าที่ทุก env เหมือนกัน → ใส่ใน default
  2. ค่าที่ต่างตาม env → ใส่ใน environments/*.tfvars
  3. ค่าที่เป็นความลับ → ใช้ environment variables (TF_VAR_xxx)
  4. ไม่ commit terraform.tfvars ที่มี secrets
  5. ทำ template terraform.tfvars.example ให้ทีม
# terraform.tfvars.example (commit ได้)
environment   = ""  # dev, staging, prod
instance_type = ""  # t2.micro, t3.large
db_password   = ""  # ใส่ค่าจริงตอน deploy

สรุป

Concept ตัวอย่าง
Auto-loaded terraform.tfvars, *.auto.tfvars
Manual load -var-file="prod.tfvars"
Env var TF_VAR_name=value
CLI flag -var="name=value"
Workspace terraform workspace select prod
Priority CLI flag > env var > var-file > auto.tfvars > tfvars > default

บทถัดไปเรามา Lab สร้างโปรเจคที่ deploy ได้หลาย environment