ข้ามไปยังเนื้อหา

Outputs and Locals

output เปิดเผยค่าออกจาก Terraform configuration หลัง apply ส่วน local คำนวณ expression ที่มีชื่อไว้ครั้งเดียวเพื่อใช้ซ้ำภายใน configuration เดียวกัน ทั้งสองไม่ใช่ variable และแก้ปัญหาคนละแบบกัน

output block มีชื่อ, value expression, และเลือกใส่ description กับ sensitive ได้ หลัง terraform apply เสร็จ ทุก output ที่ประกาศไว้จะ print ออกมา และเรียกดูซ้ำได้ทีหลังโดยไม่ต้อง apply ใหม่

resource "google_compute_instance" "web" {
name = "web-server"
machine_type = "e2-medium"
zone = "us-central1-a"
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
network_interface {
network = "default"
access_config {}
}
}
output "instance_id" {
description = "The unique identifier Google Cloud assigned to the instance"
value = google_compute_instance.web.instance_id
}
output "instance_external_ip" {
description = "Public IP address of the web server"
value = google_compute_instance.web.network_interface[0].access_config[0].nat_ip
}
output "db_password" {
description = "Generated password for the application database user"
value = random_password.db.result
sensitive = true
}
Terminal window
# Print every output declared in the configuration
terraform output
# Print a single output by name, unquoted for use in scripts
terraform output instance_external_ip
# Print all outputs as JSON, for piping into another tool
terraform output -json

terraform output -json สำคัญกว่าที่ดูตอนแรก เพราะเปลี่ยน output ของเราให้เป็น structured data ที่ script อื่น, CI pipeline, หรือ wrapper tool อ่านต่อได้แน่นอน แทนที่จะไป parse ข้อความบน terminal ที่ format มาให้คนอ่าน sensitive = true บน db_password ทำงานเหมือนตอนอยู่บน variable เป๊ะ Terraform ซ่อนค่าใน terraform output และใน output ของ apply แต่ค่ายังถูกเขียนลง state file เป็น plain text อยู่ดี นี่คือการป้องกันตอนแสดงผล ไม่ใช่ access control

Terraform มี named value ที่ต่างกันสามแบบ และควรพูดให้ชัดว่าต่างกันตรงไหน variable ถูกตั้งค่าจากภายนอกโดยคนเรียก output ถูกเปิดเผยออกไปข้างนอกหลัง apply ส่วน local ไม่ใช่ทั้งสองแบบ แต่คือ expression ที่มีชื่อ ถูกคำนวณครั้งเดียวภายใน configuration เพื่อไม่ต้องเขียน expression เดิมซ้ำใน resource block ห้าที่

variable "environment" {
type = string
description = "Deployment environment name"
default = "dev"
}
variable "project_id" {
type = string
description = "GCP project ID"
}
locals {
name_prefix = "${var.project_id}-${var.environment}"
common_labels = {
environment = var.environment
managed_by = "terraform"
}
}
resource "google_compute_instance" "web" {
name = "${local.name_prefix}-web"
machine_type = "e2-medium"
zone = "us-central1-a"
labels = local.common_labels
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
}
}
network_interface {
network = "default"
access_config {}
}
}
resource "google_storage_bucket" "assets" {
name = "${local.name_prefix}-assets"
location = "US"
labels = local.common_labels
}

ถ้าไม่มี local.name_prefix กับ local.common_labels string interpolation "${var.project_id}-${var.environment}" เดิม กับ labels map เดิม ต้องพิมพ์ซ้ำในทุก resource ที่ต้องใช้ และถ้าต้องแก้ naming scheme ทีหลังก็ต้องไล่หาทุกจุดที่ copy ไว้ locals block ไม่ได้ให้ caller ตั้งค่าได้แบบ variable และไม่ได้มองเห็นจากภายนอก configuration แบบ output แต่มีไว้แค่เก็บ expression ที่คำนวณแล้วให้อยู่จุดเดียว

ภายใน root configuration เดียว output ส่วนใหญ่เป็นแค่ข้อมูลไว้ดู เป็นวิธี print ค่าตอนจบของ apply หรือป้อนเข้า script ผ่าน terraform output -json ความสำคัญจริง ๆ จะเห็นชัดตอนเริ่มแยก infrastructure ออกเป็นชิ้นเล็ก ๆ ที่ manage แยกกัน

เวลา Terraform module หนึ่งเรียกอีก module หนึ่ง module ที่เรียกจะอ่าน output ของ child module เพื่อส่งค่าเชื่อมกัน — output "subnet_self_link" ของ networking module กลายเป็น input ของ variable "subnet" ใน compute module บทเรื่อง Modules ในคอร์สนี้จะพูดถึงการประกอบกันแบบนี้ลึกกว่านี้ แนวคิดเดียวกันนี้เกิดขึ้นอีกทีในสเกลที่ใหญ่กว่าใน Terragrunt เช่นกัน Terragrunt unit ที่ apply แยกกันจะอ่าน output ของอีก unit หนึ่งผ่าน dependency block ทำให้ VPC ที่ deploy อยู่ใน directory หนึ่งส่งชื่อ network ให้ database ที่ deploy อยู่คนละ directory ได้ โดยไม่ต้องมี Terraform state ร่วมกันเลย output คือสิ่งที่ทำให้การประกอบทั้งสองแบบนี้เป็นไปได้ — ถ้าไม่มี output ที่ประกาศไว้ชัดเจนและ stable ก็ไม่มีอะไรให้ module หรือ unit ที่ consume อ่านได้

flowchart LR
  v1["var.project_id"] --> l["local.name_prefix"]
  v2["var.environment"] --> l
  l --> r1["google_compute_instance.web"]
  l --> r2["google_storage_bucket.assets"]
  r1 --> o["output ip_address"]
  o --> ext["Consumed by another module or a Terragrunt dependency block"]
A local computes a shared value once; an output exposes the final result after apply
จุดประสงค์หลักของ locals block เทียบกับ variable และ output คืออะไร
ทำไม output ถึงสำคัญแม้ใน root configuration เดียวที่ยังไม่มี module เลย
terraform output -json มีประโยชน์อะไรมากที่สุด
output ป้อนเข้า Terragrunt dependency block ได้อย่างไรในภาพรวม