Terraform
← Tổng quan series

Lập trình trong Terraform: biến, output và vòng lặp

Dùng input variable, validation, output, count, for expression và function để tránh copy-paste cấu hình giữa các môi trường.

Instructor walkthrough

Bài giảng: hiểu luồng trước khi chạy lệnh

Bài toán: Dùng input variable, validation, output, count, for expression và function để tránh copy-paste cấu hình giữa các môi trường.

01Chuẩn bịkiểm tra account, region, provider và chi phí
02Đọc planđối chiếu resource address, diff và dependency
03Thực hànhapply mutation nhỏ trong sandbox, lưu evidence
04Khôi phụcre-run, failure drill, destroy hoặc rollback
Command reference · baseline
terraform fmt
terraform init
terraform validate
terraform plan
terraform apply
terraform plan -destroy
terraform destroy

Input variable: biến cấu hình, không phải secret store

Đặt phần thay đổi theo môi trường vào variables.tf:

variable "instance_count" {
  type        = number
  description = "Số EC2 cần chạy"
  default     = 1

  validation {
    condition     = var.instance_count >= 1 && var.instance_count <= 5
    error_message = "instance_count phải từ 1 đến 5 trong lab này."
  }
}

variable "instance_type" {
  type    = string
  default = "t3.micro"
}

Gán giá trị bằng terraform.tfvars, file -var, hoặc biến môi trường TF_VAR_instance_type. Không đưa password và access key vào tfvars rồi commit; sensitive = true chỉ che output/log hiển thị, không mã hóa state.

# dev.tfvars
instance_count = 2
instance_type  = "t3.micro"
terraform plan -var-file=dev.tfvars

Output: xuất thông tin cần dùng

output "instance_ids" {
  description = "ID các EC2 được tạo"
  value       = aws_instance.app[*].id
}

Sau apply, terraform output instance_ids có thể được script khác đọc. Output nhạy cảm nên khai báo sensitive = true.

count, for và function

resource "aws_instance" "app" {
  count         = var.instance_count
  ami           = data.aws_ami.amazon_linux.id
  instance_type = var.instance_type

  tags = {
    Name = format("app-%02d", count.index + 1)
  }
}

Với danh sách đã có, for tạo một map dễ dùng:

variable "team_names" {
  type    = list(string)
  default = ["api", "worker", "frontend"]
}

locals {
  team_tags = {
    for name in var.team_names : name => upper(name)
  }
}

count phù hợp khi các instance gần như giống nhau. Nếu mỗi phần tử có identity riêng và thứ tự có thể thay đổi, for_each thường an toàn hơn vì Terraform theo dõi theo key thay vì index.

Variable, local và output khác nhau thế nào?

  • Variable là input từ người gọi/root module hoặc environment.
  • Local là giá trị trung gian được tính bên trong module, ví dụ quy ước tên/tag.
  • Output là contract trả thông tin ra ngoài module hoặc cho pipeline.

Đừng dùng variable cho mọi thứ. Ví dụ name_prefix có thể là input, còn map tag đầy đủ nên là local:

variable "name_prefix" { type = string }
variable "environment" { type = string }

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

Khi đổi từ count sang for_each, địa chỉ resource thay đổi (aws_instance.app[0] thành aws_instance.app["api"]). Hãy đọc phần replace trong plan và cân nhắc moved block để giữ resource hiện có, thay vì vô tình destroy/recreate.

Bài tập nhỏ

Hãy mở rộng ví dụ để nhận environment, thêm tag Environment, rồi tạo hai plan với dev.tfvarsprod.tfvars. So sánh plan trước khi apply. Mục tiêu không phải tạo thật nhiều EC2 mà là học cách một cấu hình dùng lại được.

Expected state và failure drills

Dùng resource test rẻ hoặc chỉ chạy plan. Với dev.tfvars, expected state là số lượng/key/tag đúng; với prod.tfvars, plan phải khác có chủ đích nhưng không lẫn environment, secret hoặc provider region. Output ID phải khớp resource address; output chứa credential/token phải sensitive = true và state vẫn được bảo vệ.

Thực hiện các drill:

  1. Truyền instance_count = 0, 6, sai type và thiếu bắt buộc; ghi validation/type error và xác nhận không có apply.
  2. Đổi thứ tự list khi dùng count, xem address/index churn; chuyển bản sao sang for_each với key ổn định, đọc plan và viết moved block nếu cần giữ resource.
  3. Xóa một key khỏi map for_each, kiểm tra resource address nào bị destroy; không approve nếu key bị xóa chỉ vì typo.
  4. Đánh dấu output sensitive, chạy terraform output/show và kiểm tra giá trị không xuất hiện ở terminal/artifact công khai; nhớ sensitive không mã hóa state.

Quality gate

Pass khi người học giải thích variable/local/output boundary, validation/type behavior, count index risk và for_each key identity; tạo được hai plan reproducible, đọc replacement/destroy trước approval, dùng moved khi migration phù hợp và cleanup chỉ resource test sau plan -destroy. tfvars/output/plan không được chứa credential thật.