Lab: Deploy หลาย Environment

📖 text • 25 นาที

Lab: Deploy หลาย Environment

สิ่งที่ต้องมี: Terraform + AWS Credentials ตั้งค่าแล้ว

เป้าหมาย

สร้างโปรเจคที่ deploy ได้ทั้ง dev และ prod ด้วย code ชุดเดียว — แค่เปลี่ยน tfvars file

Step 1: สร้างโปรเจค

mkdir terraform-multi-env-lab && cd terraform-multi-env-lab
mkdir environments

Step 2: เขียน variables.tf

variable "environment" {
  description = "Deployment environment"
  type        = string

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

variable "project" {
  description = "Project name"
  type        = string
  default     = "myapp"
}

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

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

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

variable "allowed_ssh_cidrs" {
  description = "CIDRs allowed for SSH access"
  type        = list(string)
  default     = ["0.0.0.0/0"]
}

Step 3: เขียน locals.tf

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

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

Step 4: เขียน main.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  required_version = ">= 1.0"
}

provider "aws" {
  region = "ap-southeast-1"
}

# หา AMI ล่าสุด
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-2023.*-x86_64"]
  }
}

# Default VPC
data "aws_vpc" "default" {
  default = true
}

# Security Group
resource "aws_security_group" "web" {
  name        = "${local.name_prefix}-web-sg"
  description = "Security group for ${local.name_prefix}"
  vpc_id      = data.aws_vpc.default.id

  ingress {
    description = "HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = var.allowed_ssh_cidrs
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

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

# EC2 Instances
resource "aws_instance" "web" {
  count                  = var.instance_count
  ami                    = data.aws_ami.amazon_linux.id
  instance_type          = var.instance_type
  monitoring             = var.enable_monitoring
  vpc_security_group_ids = [aws_security_group.web.id]

  user_data = <<-EOF
    #!/bin/bash
    yum update -y
    yum install -y httpd
    systemctl start httpd
    systemctl enable httpd
    cat > /var/www/html/index.html <<HTML
    <h1>${local.name_prefix} - Server ${count.index}</h1>
    <p>Environment: ${var.environment}</p>
    <p>Instance Type: ${var.instance_type}</p>
    HTML
  EOF

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

Step 5: เขียน outputs.tf

output "instance_ids" {
  description = "IDs ของ EC2 instances ทั้งหมด"
  value       = aws_instance.web[*].id
}

output "public_ips" {
  description = "Public IPs ทั้งหมด"
  value       = aws_instance.web[*].public_ip
}

output "web_urls" {
  description = "URLs ของเว็บทั้งหมด"
  value       = [for ip in aws_instance.web[*].public_ip : "http://${ip}"]
}

output "security_group_id" {
  description = "Security Group ID"
  value       = aws_security_group.web.id
}

output "summary" {
  description = "สรุปการ deploy"
  value       = <<-EOT
    Environment:    ${var.environment}
    Instance Count: ${var.instance_count}
    Instance Type:  ${var.instance_type}
    Monitoring:     ${var.enable_monitoring}
  EOT
}

Step 6: สร้าง tfvars files

environments/dev.tfvars

environment       = "dev"
instance_type     = "t2.micro"
instance_count    = 1
enable_monitoring = false
allowed_ssh_cidrs = ["0.0.0.0/0"]  # lab เท่านั้น

environments/prod.tfvars

environment       = "prod"
instance_type     = "t3.small"
instance_count    = 2
enable_monitoring = true
allowed_ssh_cidrs = ["203.0.113.0/24"]  # จำกัดเฉพาะ office IP

Step 7: Deploy Dev

terraform init
terraform plan -var-file="environments/dev.tfvars"

ดู plan — ควรเห็น:

  • 1 Security Group
  • 1 EC2 Instance (instance_count = 1)
  • Instance type = t2.micro
terraform apply -var-file="environments/dev.tfvars"

พิมพ์ yes

ดู output:

summary = <<-EOT
  Environment:    dev
  Instance Count: 1
  Instance Type:  t2.micro
  Monitoring:     false
EOT

web_urls = [
  "http://54.xx.xx.xx",
]

Step 8: ทดสอบ Dev

curl http://<DEV_PUBLIC_IP>
<h1>myapp-dev - Server 0</h1>
<p>Environment: dev</p>
<p>Instance Type: t2.micro</p>

Step 9: Destroy Dev

terraform destroy -var-file="environments/dev.tfvars"

พิมพ์ yes

หมายเหตุ: ใน lab นี้เราใช้ state เดียวกัน เพราะฉะนั้น ต้อง destroy ก่อนเปลี่ยน environment

ในงานจริง ควรใช้ remote state แยกตาม environment (backend key ต่างกัน)

Step 10: Deploy Prod (optional)

terraform plan -var-file="environments/prod.tfvars"

ดูความแตกต่าง:

  • 2 EC2 Instances (instance_count = 2)
  • Instance type = t3.small
  • Monitoring = true
  • SSH จำกัดเฉพาะ IP ที่กำหนด
terraform apply -var-file="environments/prod.tfvars" -auto-approve

ดู output:

web_urls = [
  "http://54.xx.xx.xx",
  "http://54.yy.yy.yy",
]

Step 11: Cleanup

# ลบ resource (ใช้ tfvars ที่ตรงกับ environment ปัจจุบัน)
terraform destroy -var-file="environments/prod.tfvars" -auto-approve

# ลบ lab directory
cd .. && rm -rf terraform-multi-env-lab

สิ่งที่ได้เรียนรู้

Concept สิ่งที่ฝึก
Variables ประกาศ input variables พร้อม type + validation
Locals สร้าง name prefix + common tags
tfvars แยกค่าตาม environment
Outputs แสดง summary และ URLs หลัง deploy
-var-file เลือก environment ตอน plan/apply
count สร้าง instance ตามจำนวนที่กำหนด
[*] Splat expression ดึงค่าจาก list ของ resource

สรุป

คุณเพิ่งสร้างโปรเจคที่ code ชุดเดียว deploy ได้หลาย environment — pattern นี้ใช้ในทุกโปรเจค Terraform จริง

Key takeaway:

  • Code = เหมือนกันทุก environment
  • tfvars = ค่าที่ต่างกันตาม environment
  • State = แยกกันตาม environment (ในงานจริง)

บทถัดไปเราจะเรียนรู้เรื่อง Terraform Modules