Terraform Output: Export ค่า สำหรับใช้ใน Scripts หรือ Outputs

Output Value เป็นอีกหนึ่งกลไกหลักของ Terraform ที่ทำให้ค่าภายใน configuration ถูก “ส่งออก” ไปยังผู้ใช้งานหรือระบบภายนอก เช่น CI/CD pipeline, script ที่เรียก terraform output, หรือ module อื่นที่ consume module นี้ หากไม่มี output การสร้าง resource ก็เหมือนกล่องดำ — ผู้ใช้ไม่รู้ว่า IP, endpoint, หรือ ID ของ resource ที่เพิ่งสร้างคืออะไร

บทความนี้อธิบายวิธีประกาศ output, การใช้ sensitive, การ export ค่าให้ script ภายนอกอ่านผ่าน JSON, และวิธีที่ module หนึ่งส่งค่าให้อีก module หนึ่งผ่าน output+input

ประกาศ Output Value

Output ใช้ block output ตามด้วยชื่อที่จะใช้อ้างอิง และต้องมี argument value ซึ่งเป็นนิพจน์ที่ Terraform จะ evaluate หลัง apply

resource "aws_instance" "web" {
  ami           = "ami-0123456789"
  instance_type = "t3.micro"
}

output "instance_id" {
  description = "ID of the web EC2 instance"
  value       = aws_instance.web.id
}

output "instance_public_ip" {
  description = "Public IP address"
  value       = aws_instance.web.public_ip
}

หลังรัน terraform apply Terraform จะแสดงค่า output ทั้งหมดที่ console และเก็บไว้ใน state file พร้อมเรียกดูภายหลังได้ด้วย terraform output

เรียกใช้ Output จาก Command Line

# แสดง output ทั้งหมด
terraform output

# แสดงเฉพาะตัวเดียว (raw value, ไม่มี quote)
terraform output -raw instance_public_ip

# export เป็น JSON สำหรับ script/CI
terraform output -json > outputs.json

# ใช้ใน shell script
IP=$(terraform output -raw instance_public_ip)
ssh ubuntu@$IP

Sensitive Output

ค่าที่ไม่ต้องการให้โชว์บนหน้าจอ เช่น password, API key, หรือ endpoint ที่รวม credential ต้องประกาศด้วย sensitive = true Terraform จะซ่อนค่าในผลลัพธ์ของ plan/apply ทันที แต่ยังสามารถเรียกดูผ่าน terraform output -raw ได้

output "db_password" {
  description = "RDS master password"
  value       = random_password.db.result
  sensitive   = true
}

output "connection_string" {
  value = "postgres://${aws_db_instance.main.username}:${random_password.db.result}@${aws_db_instance.main.endpoint}/${var.db_name}"
  sensitive = true
}

ถ้า resource มี argument ที่ถูก mark เป็น sensitive (เช่น random_password.result) แต่ output ที่ใช้ค่านั้นไม่ได้ระบุ sensitive = true Terraform จะ error ทันที เป็นการบังคับให้ไม่เผลอโชว์ secret

Output ที่ขึ้นกับ Condition

ใช้ conditional expression ได้ตามปกติ ทำให้ output ปรับตาม input โดยไม่ต้องสร้าง output หลายตัว

output "endpoint_url" {
  value = var.enable_https ? "https://${aws_lb.main.dns_name}" : "http://${aws_lb.main.dns_name}"
}

output "worker_ips" {
  value = var.create_workers ? aws_instance.worker[*].private_ip : []
}

ส่งค่าระหว่าง Module ด้วย Output

Module ที่ใช้ใน root configuration สามารถ “export” ค่าผ่าน output ให้ module อื่นหรือ root module นำไปใช้ต่อได้ วิธีนี้คือกระดูกสันหลังของการประกอบ infrastructure จาก module ย่อย

# modules/network/outputs.tf
output "vpc_id" {
  value = aws_vpc.main.id
}

output "private_subnet_ids" {
  value = aws_subnet.private[*].id
}

# root main.tf
module "network" {
  source = "./modules/network"
}

module "compute" {
  source            = "./modules/compute"
  vpc_id            = module.network.vpc_id
  private_subnets   = module.network.private_subnet_ids
}

Terraform Remote State Output

เมื่อมีหลายโปรเจกต์ Terraform แยก state กัน แต่ต้อง reference ค่ากัน สามารถใช้ terraform_remote_state data source อ่าน output ของอีก state ได้ โดยไม่ต้อง duplicate code หรือ hardcode ค่าลง variable

data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "mycompany-tfstate"
    key    = "network/terraform.tfstate"
    region = "ap-southeast-1"
  }
}

resource "aws_instance" "app" {
  subnet_id = data.terraform_remote_state.network.outputs.private_subnet_ids[0]
}

สรุป

Output value ทำให้ configuration ของ Terraform สื่อสารกับภายนอกได้ ไม่ว่าจะเป็น operator ที่ต้องการทราบ IP ของ resource, script ที่อ่าน JSON เข้า pipeline, หรือ module ที่ต่อกันเป็นชั้น ๆ การใช้ sensitive จะช่วยป้องกัน secret หลุดออกหน้าจอ ส่วน terraform_remote_state ช่วยเชื่อม state ข้ามโปรเจกต์ได้โดยไม่ต้อง copy ค่า เมื่อออกแบบ module ใด ๆ ควรคิดก่อนว่า caller ต้องการอะไรแล้วเปิดเป็น output ให้ครบ จะทำให้ module ของคุณถูกนำไปใช้ต่อได้ง่ายขึ้น