Terraform Variables
ตัวแปร(Variables)เป็นสิ่งที่ทำให้ Infrastructure as Code นั้นแตกต่างจากการใช้ shell script เพราะเราจะแยก code กับ data ออกจากกัน และเมื่อเราแยก data ออกมาแล้วเราจะสามารถปรับเปลี่ยนได้โดยที่ code ยังเหมือนเดิม

ประเภทของตัวแปร
terraform มีตัวแปรอยู่ 3 ประเภทด้วยกัน
Input Variables
input variables จะเป็นตัวแปรที่ใช้ในการกำหนดค่าการทำงานของ terraform สิ่งที่ต้องพิจารณาคือ เราจะใช้ input variables เมื่อต้องการ การเปลี่ยนแปลงในอนาคต เช่น เปลี่ยน region วันนี้ใช้ ap-southeast-1 อนาคตอาจย้ายไป deploy ใน ap-southeast-2 เราจะใช้การประกาศตัวแปรแบบนี้
การประกาศตัวแปร
variable "region" {}
ถ้าเราประกาศตัวแปรแบบนี้ เวลา run terraform apply จะมี prompt ขึ้นมาให้เรากรอกค่าของตัวแปร region ก่อนจะสร้าง resource ต่อไป
อีกสิ่งหนึ่งที่ขาดหายไปคือ data type terraform ซึ่งถ้าเราต้องการกำหนด data type และค่า default เราจะเขียนแบบนี้
variable "region" {
type = string
description = "AWS default region"
default = "ap-southeast-1"
}
ซึ่งถ้าตัวแปรของเราเป็นความลับ ไม่ต้องการให้แสดงค่าของตัวแปรนี้ออกไปที่ console และ log เช่น Token หรือ Access Key เราจะกำหนดให้ตัวแปรนี้เป็น sensitive แบบนี้
variable "aws_secret_key" {
type = string
description = "AWS secret key"
sensitive = true
}
ค่า default ของ sensitive จะเป็น false คือไม่เก็บความลับ
นอกจากนี้ใน variable block จะยังสามารถกำหนด property ได้อีก 2 อย่างคือ
- nullable ตัวแปรนี้สามารถกำหนดค่าเป็น null ได้หรือไม่
- validation จะระบุ function ที่จะตรวจสอบความถูกต้องของตัวแปรนั้นๆ เช่น
ในตัวอย่างนี้จะตรวจสอบว่า string ที่จะใส่เข้ามาในตัวแปร image_id ต้องนำหน้าด้วยคำว่า “ami-”
variable "image_id" { type = string description = "AMI image ID" validation = substr(var.image_id, 0, 4) == "ami-" }
การกำหนดค่าให้กับ input
ในตัวอย่างก่อนหน้าเป็นการกำหนดค่า default ให้กับตัวแปร ซึ่งการกำหนดค่าให้กับตัวแปรยังมีอีกหลายวิธี โดยที่ terraform จะอ่านค่าตัวแปรตามลำดับความสำคัญ ตามนี้
-
TF_VAR_ วิธีแรกเราจะสร้าง Environment Variables ที่นำหน้าด้วยคำว่า TF_VAR_ ซึ่งใน linux และ macos เราจะใช้การ export command แบบนี้
export TF_VAR_region=ap-southeast-1
บน windows เราสามารถกำหนด Environment Variables ด้วย Powershell ได้แบบนี้
$env:TF_VAR_region=ap-southeast-1
-
terraform.tfvars วิธีทีนี้เราจะกำหนดค่าของตัวแปรไว้ในไฟล์ terraform.tfvars หรือ terraform.tfvars.json เมื่อ terraform เห็นไฟล์ terraform.tfvars ก็จะ load ตัวแปรต่างๆที่อยู่ในไฟล์นี้จะถูกอ่านออกไปใช้งานโดยอัตโนมัติ
# ไฟล์ terraform.tfvars region=ap-southeast-1
terraform.tfvars.json จะถูกอ่านทีหลัง (มีความสำคัญมากกว่า terraform.tfvars)
-
.auto.tfvars วิธีนี้เราจะตั้งชื่อไฟล์แล้วลงท้ายด้วย .auto.tfvars หรือ .auto.tfvars. json เหมือนกับ terraform.tfvars เลยแต่จะมี piority มากกว่า เพราะ terraform จะเอาค่าของตัวแปรในไฟล์นี้ไปทับ terraform.tfvars ซึ่งเราอาจแยกออกเป็น environment ต่าง เช่น dev.auto.tfvars หรือ prod.auto.tfvars
.auto.tfvars และ .auto.tfvars.json จะเรียงลำดับการอ่านตามชื่อไฟล์
-
-var-file วิธีนี้เราจะ กำหนดชื่อไฟล์เข้าไปตอนที่สั่ง terraform apply แบบนี้
$ terraform apply -var-file=dev.tfvars
ส่วนใหญ่เราจะใช้นามสกุลเป็น tfvars เหมือนกัน แต่ไม่ได้ load เข้าไปใช้งานโดยอัตโนมัติ
-
-var วิธีนี้ไม่ได้ใช้ไฟล์เหมือนในวิธีที่ผ่านมา เราะกำหนดค่าให้กับตัวแปรทีละตัว
$ terraform apply -var="region=ap-southeast-1"
-
Command prompt ถ้าเราไม่ได้กำหดค่าของตัวแปรด้วยวิธีไหนเลย และใน variable block ก็ไม่ได้กำหนดค่า default ไว้ด้วย terraform จะ prompt ขึ้นมาให้ใส่ค่าของตัวแปรตอน apply

การนำตัวแปรไปใช้งาน
เมื่อต้องการนำตัวแปรนี้ไปใช้งาน เราจะใช้ var.ชื่อตัวแปร แบบนี้
var.region
หรือถ้าต้องการเอาไปแทรกไว้เป็นส่วนหนึ่งของข้อความ เราจะใช้ interpolation แบบนี้
instance_name = "${var.project}-Web-Server"
Local Variables
local variables เป็นตัวแปรที่เราใช้คำนวนภายใน เหมือนกับที่เรากำหนด constant ขึ้นมาใช้งานใน programming language อื่นๆ ในตัวอย่างนี้จะเป็นการกำหนด path ของไฟล์ที่จะนำไปใส่ไว้ใน s3 bucket
locals {
website_content = {
website = "/website/index.html"
logo = "/website/Globo_logo_Vert.png"
}
}
แต่โดยส่วนใหญ่แล้วเราจะรับค่าจาก input variables มาคำนวนต่ออีกทีแบบนี้ สังเกตุว่าเรา input เข้ามาแค่ var.company,var.project และ var.environment แต่นำมาสร้าง local variables ได้อีกหลายตัวเลยทีเดียว
locals {
common_tags = {
company = var.company
project = "${var.company}-${var.project}"
environment = var.environment
}
naming_prefix = "${var.project}-${var.environment}"
s3_bucket_name = "${lower(local.naming_prefix)}-${random_integer.s3.result}"
}
# ตัวอย่างใช้ random module สำหรับการ random ตัวเลขขึ้นมา 5 หลักต่อท้าย s3_bucket_name
resource "random_integer" "s3" {
min = 10000
max = 99999
}
Output Variables
output เป็นตัวแปรที่เราจะประกาศไว้ใช้งานใน 2 กรณีคือ
- ใช้แสดง output ออกหน้าจอ ตอนที่ run คำสั่ง terraform apply
- เมื่อเราสร้าง module ขึ้นมาใน terraform เราจะต้อง output ตัวแปรต่างๆออกไปใช้งานใน module อื่นๆต่อไป เหมือนกับการ return ผลลัพธ์ออกจาก function
รูปแบบของ output จะเป็นแบบนี้
output "aws_alb_public_dns" {
value = "http://${aws_lb.nginx.dns_name}"
description = "Public DNS for the application load balancer"
}
Data type
การใช้งานตัวแปรใน terraform เราจำเป็นต้องเลือกใช้ data type ให้เหมาะกับการใช้งาน โดยที่ terraform จะมี data type ในกลุ่มต่างๆ ดังนี้
-
primitive เป็น data type พื้นฐานที่จำเป็นเป็นต้องใช้ในการเขียนโปรแกรม เช่น string, number และ boolean
variable "enable_dns_hostnames" { type = bool description = "Enable DNS hostnames in VPC" default = true }
-
Collections เป็น data type ที่มีสมาชิกมากกว่า 1 ค่า โดยที่สมาชิกแต่ละตัวต้องมี data type แบบเดียวกัน ซึ่ง terraform จะมี collections อยู่ 3 ประเภทคือ list, set และ map
variable "vpc_public_subnets_cidr_block" { type = list(string) description = "CIDR Block for Public Subnets in VPC" default = ["10.0.0.0/24", "10.0.1.0/24"] }
เราอาจใช้ list และ map พร้อมๆกันได้ แบบนี้
variable "ingress_with_cidr_blocks" { description = "List of ingress rules to create where 'cidr_blocks' is used" type = list(map(string)) default = [{ cidr_block = ["0.0.0.0/0"], description = "", from_port = 22 }, { cidr_block = ["0.0.0.0/0"], description = "", from_port = 443 }] }
-
Structure เป็นตัวแปรที่มีสมาชิกหลายประเภทมารวมกัน มี 2 ประเภท คือ tuple และ object
ตัวอย่าง การประกาศตัวแปร object
variable "object_example" { type = object({ name=string, age=number }) } # การกำหนดค่าให้กับตัวแปรประเภท object object_example = { name = "John" age = 52 }
ตัวอย่าง การประกาศตัวแปร tuple
variable "tuple_example" { type = tuple([string, number, bool]) } # การกำหนดค่าให้กับตัวแปรประเภท tuple ["a", 15, true]
-
Any จะใช้กับตัวแปรที่สามารถเป็น data type อะไรก็ได้ เช่น list(any)
-
null จะเหมือนกับการใช้งาน programming language ภาษาอื่นๆ null จะเป็นค่าเริ่มต้น จะหมายความว่า ยังไม่แน่ใจว่า มี หรือ ไม่มีค่า
variable "security_group_id" { description = "ID of existing security group whose rules we will manage" type = string default = null }
