← 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.

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.

Nội dung được chuyển thể và bổ sung ví dụ; nguồn tham khảo: Programming in Terraform.