Skip to main content

Workspaces

Workspace = แยก state file หลายชุดในโฟลเดอร์เดียว — เหมาะกับ multi-environment (dev/staging/prod)

Workspace คืออะไร?

ปกติ Terraform มี state file ตัวเดียว:

my-project/
└── terraform.tfstate

ใช้ workspace → มีหลาย state file:

my-project/
└── terraform.tfstate.d/
├── dev/ terraform.tfstate
├── staging/ terraform.tfstate
└── prod/ terraform.tfstate

ใช้ code เดียวกัน แต่ state ต่างกัน ตาม workspace

Default Workspace

ทุก project มี workspace default อัตโนมัติ:

$ terraform workspace show
default

Workspace Commands

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

# List
terraform workspace list

# Switch
terraform workspace select prod

# Show current
terraform workspace show

# Delete
terraform workspace delete dev

ใช้ใน Config

locals {
environment = terraform.workspace # ← ค่า workspace ปัจจุบัน
}

resource "aws_instance" "web" {
ami = "ami-12345"
instance_type = local.environment == "prod" ? "t3.large" : "t3.micro"

tags = {
Name = "web-${terraform.workspace}"
Environment = terraform.workspace
}
}

ตัวอย่าง: Multi-Environment Workflow

# 1. Setup
terraform init
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod

# 2. Deploy dev
terraform workspace select dev
terraform apply -var-file=dev.tfvars

# 3. Deploy staging
terraform workspace select staging
terraform apply -var-file=staging.tfvars

# 4. Deploy prod
terraform workspace select prod
terraform apply -var-file=prod.tfvars

ตัวอย่าง: Conditional by Workspace

locals {
is_prod = terraform.workspace == "prod"
}

resource "aws_db_instance" "main" {
identifier = "db-${terraform.workspace}"

engine = "postgres"
instance_class = local.is_prod ? "db.t3.large" : "db.t3.micro"
allocated_storage = local.is_prod ? 100 : 20

multi_az = local.is_prod
backup_retention_period = local.is_prod ? 30 : 7

deletion_protection = local.is_prod

tags = {
Environment = terraform.workspace
}
}

ตัวอย่าง: Per-Workspace Tfvars

# main.tf
locals {
config = {
dev = {
instance_type = "t3.micro"
replicas = 1
}
staging = {
instance_type = "t3.small"
replicas = 2
}
prod = {
instance_type = "t3.large"
replicas = 5
}
}

current = local.config[terraform.workspace]
}

resource "aws_instance" "web" {
count = local.current.replicas
ami = "ami-12345"
instance_type = local.current.instance_type
}

State Path

Local Backend

.
├── main.tf
└── terraform.tfstate.d/
├── dev/terraform.tfstate
└── prod/terraform.tfstate

Remote Backend (S3)

terraform {
backend "s3" {
bucket = "my-tfstate"
key = "infra/terraform.tfstate" # → env:/{workspace}/infra/terraform.tfstate
region = "ap-southeast-1"
}
}

ใน S3:

my-tfstate/
├── env:/dev/infra/terraform.tfstate
├── env:/staging/infra/terraform.tfstate
└── env:/prod/infra/terraform.tfstate

Workspace vs Multiple Directories

FeatureWorkspaceMultiple Dirs
CodeSharedSeparate
StateSeparateSeparate
ConfigSame .tfDifferent .tf
Different resources per env⚠️ Hard✅ Easy
Easy to switchworkspace selectcd

When to Use Workspace

  • ✅ Same architecture, different size (dev/staging/prod)
  • ✅ Quick experiments / feature branches
  • ✅ Tightly coupled environments

When to Use Multiple Dirs

  • ✅ Environments diverge significantly
  • ✅ Different teams own different envs
  • ✅ Different security boundaries

ตัวอย่าง: Feature Branch Pattern

# Developer creates ephemeral env per PR
git checkout -b feature/new-api

terraform workspace new pr-123
terraform apply -var-file=feature.tfvars

# After PR merged
terraform workspace select default
terraform workspace delete pr-123

→ Each PR has own infrastructure, easy cleanup

CI/CD Integration

.github/workflows/deploy.yml
on:
push:
branches: [main, develop]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3

- name: Init
run: terraform init

- name: Select Workspace
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
terraform workspace select prod
else
terraform workspace select dev
fi

- name: Apply
run: terraform apply -auto-approve
env:
TF_VAR_environment: ${{ github.ref == 'refs/heads/main' && 'prod' || 'dev' }}

TF_WORKSPACE Environment Variable

export TF_WORKSPACE=prod
terraform apply
# ← เท่ากับ workspace select prod + apply

ใช้ใน CI:

- name: Apply
env:
TF_WORKSPACE: ${{ github.ref_name }}
run: terraform apply -auto-approve

Limitations & Pitfalls

1. Same Backend

ทุก workspace ใช้ backend เดียวกัน — ถ้า bucket เสีย = ทุก env เสีย

→ Production ที่สำคัญ: ใช้ separate state files / accounts

2. Workspace ไม่ใช่ Security Boundary

ทุก workspace = same provider config → ถ้า dev ใช้ prod credentials → ทำลาย prod ได้

→ ใช้ separate AWS accounts สำหรับ env ต่างๆ

3. Missing Workspace = Default

ถ้าลืม workspace select → apply ที่ default — เผลอ deploy ผิด env

→ ตั้ง TF_WORKSPACE ใน CI หรือ check ใน script:

if [[ "$(terraform workspace show)" != "prod" ]]; then
echo "Error: must be in prod workspace"
exit 1
fi

4. ไม่เหมาะกับ Major Differences

ถ้า dev มี 3 instances, prod มี 30 + ELB + RDS Multi-AZ + ... → conditional logic ใน config ใหญ่

→ ใช้ separate dirs + module ดีกว่า

Best Practices

✅ DO:
- ใช้ workspace สำหรับ env ที่คล้ายกัน (size ต่าง)
- Document workspace usage ใน README
- Use TF_WORKSPACE ใน CI ป้องกันลืม
- ใช้ different AWS accounts ต่อ env (security)

❌ DON'T:
- ห้ามใช้ workspace เป็น security boundary
- ห้ามใช้ workspace ถ้า env ต่างกันมาก
- ห้าม share workspace ใน prod กับ dev
- ห้าม hard-code workspace name ใน config

Terraform Cloud Workspaces (ต่างกัน!)

⚠️ "Workspace" ใน Terraform Cloud / Enterprise = ความหมายต่างจาก CLI workspace

  • CLI Workspace = state file ใน 1 directory
  • TFC Workspace = ทั้ง project (state + variables + runs + history)

ใน TFC ไม่ใช้ CLI workspace — แต่ละ TFC workspace = 1 directory

ดูเพิ่มใน Section 19: HCP

สรุป

  • Workspace = หลาย state file ใน 1 directory
  • Commands: workspace new/select/list/delete
  • Reference: terraform.workspace
  • เหมาะกับ env ที่คล้ายกัน (dev/staging/prod with same arch)
  • ไม่เหมาะกับ major architecture differences → ใช้ separate dirs + modules
  • Terraform Cloud Workspace ≠ CLI Workspace

ต่อไป → GitHub Actions