Những tính năng Terraform mình dùng mỗi ngày (for_each, count, dynamic, locals, depends_on, lifecycle, ...)
Khám phá những tính năng Terraform được sử dụng nhiều nhất trong thực tế như for_each, count, locals, dynamic blocks, depends_on và lifecycle để viết Infrastructure as Code gọn gàng, dễ bảo trì và mở rộng.

Những tính năng Terraform mình dùng mỗi ngày
Ở những bài trước, chúng ta đã biết:
- Terraform hoạt động như thế nào
- Terraform State là gì
- Variables và Outputs
- Modules
- Data Sources
Đến đây, bạn hoàn toàn có thể viết được một project Terraform cơ bản.
Nhưng nếu nhìn vào các project production trên GitHub hoặc trong doanh nghiệp, bạn sẽ thấy rất nhiều syntax như:
for_each = ...
count = ...
locals {
...
}
dynamic "ingress" {
...
}
lifecycle {
...
}
depends_on = [...]Người mới thường có cảm giác:
Terraform sao nhiều keyword quá.
Thực tế thì không phải.
Terraform có rất ít syntax.
Chỉ là có khoảng 6–7 tính năng gần như xuất hiện ở mọi project.
Nếu hiểu chúng, bạn sẽ đọc được phần lớn code Terraform ngoài đời thực.
Terraform không phải là ngôn ngữ lập trình
Đây là điều rất quan trọng.
Terraform không phải Java.
Không phải Go.
Không phải Python.
Terraform không có:
- class
- function
- loop truyền thống
- if/else đầy đủ
Terraform chỉ là một ngôn ngữ khai báo (Declarative Language).
Bạn chỉ mô tả:
"Infrastructure cuối cùng phải như thế này."
Terraform sẽ tự tính toán cách tạo ra nó.
Vì vậy những thứ như:
- for_each
- count
- dynamic
không phải loop theo nghĩa truyền thống.
Chúng chỉ giúp Terraform tạo ra nhiều resource từ cùng một template.
Tổng quan những tính năng dùng nhiều nhất
Trong thực tế, mình gần như dùng đi dùng lại đúng những tính năng này.
| Feature | Mục đích |
|---|---|
| locals | Tạo biến trung gian |
| for_each | Tạo nhiều resource từ map hoặc set |
| count | Tạo nhiều resource theo số lượng |
| dynamic | Sinh nested block |
| depends_on | Khai báo dependency thủ công |
| lifecycle | Điều khiển cách Terraform cập nhật resource |
Nếu biết sử dụng tốt 6 tính năng này thì bạn đã đọc được khoảng 80–90% code Terraform production.
locals — Biến trung gian
Giả sử project có nhiều nơi cùng dùng một prefix.
Không nên viết lặp lại:
resource "aws_s3_bucket" "logs" {
bucket = "company-dev-logs"
}
resource "aws_s3_bucket" "backup" {
bucket = "company-dev-backup"
}Thay vào đó:
locals {
prefix = "company-dev"
}
resource "aws_s3_bucket" "logs" {
bucket = "${local.prefix}-logs"
}
resource "aws_s3_bucket" "backup" {
bucket = "${local.prefix}-backup"
}Mọi nơi chỉ cần dùng:
local.prefixlocals không phải variable
Đây là điều nhiều người nhầm.
Variable:
variable "environment" {}được truyền từ bên ngoài.
Ví dụ:
terraform apply \
-var="environment=dev"
Trong khi đó:
locals {
prefix = "company-${var.environment}"
}là giá trị được Terraform tính toán bên trong.
Nói đơn giản:
- Variable là input
- Local là kết quả xử lý từ input
count — Tạo nhiều resource theo số lượng
Ví dụ muốn tạo ba EC2 giống hệt nhau.
resource "aws_instance" "web" {
count = 3
instance_type = "t3.micro"
}Terraform sẽ tạo:
web[0]
web[1]
web[2]
Có thể truy cập bằng:
aws_instance.web[0]count phù hợp khi nào?
Count phù hợp nếu:
- mọi resource giống nhau
- chỉ khác index
Ví dụ:
- nhiều VM giống nhau
- nhiều disk giống nhau
Nhược điểm của count
Giả sử:
count = 3
Terraform tạo:
0
1
2
Sau đó sửa thành:
count = 2
Terraform sẽ xóa:
2
Nhưng nếu thay đổi thứ tự dữ liệu đầu vào, index có thể thay đổi và Terraform sẽ hiểu nhầm là resource cũ bị xóa, resource mới được tạo.
Đây là lý do nhiều project hiện nay ưu tiên for_each hơn count.
for_each — Cách phổ biến nhất để tạo nhiều resource
Ví dụ:
locals {
buckets = {
logs = "company-logs"
backup = "company-backup"
assets = "company-assets"
}
}Sau đó:
resource "aws_s3_bucket" "bucket" {
for_each = local.buckets
bucket = each.value
}Terraform sẽ tạo:
bucket["logs"]
bucket["backup"]
bucket["assets"]
each.key và each.value
Ví dụ:
locals {
buckets = {
logs = "company-logs"
}
}thì:
each.keylà:
logs
Còn:
each.valuelà:
company-logs
Vì sao for_each tốt hơn count?
Giả sử có:
logs
backup
assets
Sau này thêm:
media
Terraform sẽ chỉ tạo:
media
Những resource còn lại giữ nguyên.
Không có chuyện index bị đổi.
Đây là lý do hầu hết project production đều ưu tiên dùng for_each.
dynamic block — Sinh nested block
Một số resource có nested block.
Ví dụ:
resource "aws_security_group" "web" {
ingress {
...
}
ingress {
...
}
ingress {
...
}
}Nếu có hàng chục rule thì sẽ rất dài.
Terraform cho phép:
dynamic "ingress" {
}Ví dụ:
dynamic "ingress" {
for_each = var.ingress_rules
content {
from_port = ingress.value.port
to_port = ingress.value.port
protocol = "tcp"
cidr_blocks = ingress.value.cidr
}
}Terraform sẽ tự sinh ra nhiều block:
ingress {}
ingress {}
ingress {}
thay vì phải viết tay.
depends_on — Dependency thủ công
Thông thường Terraform tự biết dependency.
Ví dụ:
resource "aws_instance" "web" {
subnet_id = aws_subnet.private.id
}Terraform hiểu:
Subnet
↓
EC2
Không cần viết gì thêm.
Khi nào cần depends_on?
Đôi khi dependency không thể suy ra.
Ví dụ:
depends_on = [
aws_iam_role.example
]Terraform sẽ luôn tạo IAM Role trước.
Hoặc:
CloudFront
↓
Route53
dù hai resource không tham chiếu trực tiếp.
Không nên lạm dụng depends_on
Nhiều người mới học Terraform có thói quen:
depends_on
ở mọi resource.
Điều này làm graph của Terraform trở nên phức tạp hơn cần thiết.
Hãy để Terraform tự suy luận trước.
Chỉ dùng depends_on khi thật sự cần.
lifecycle — Điều khiển hành vi của Terraform
Đây là một trong những tính năng rất mạnh.
Ví dụ:
lifecycle {
}bên trong có nhiều tùy chọn.
create_before_destroy
Mặc định:
Destroy
↓
Create
Điều này có thể gây downtime.
Có thể đổi thành:
lifecycle {
create_before_destroy = true
}Terraform sẽ:
Create
↓
Destroy
Đây là lựa chọn rất hữu ích khi thay thế:
- Load Balancer
- Launch Template
- ASG
- DNS
prevent_destroy
Ví dụ:
lifecycle {
prevent_destroy = true
}Nếu ai đó chạy:
terraform destroy
Terraform sẽ báo lỗi thay vì xóa resource.
Rất hữu ích cho:
- Production Database
- KMS Key
- S3 Bucket chứa dữ liệu
- DNS Zone
ignore_changes
Ví dụ:
lifecycle {
ignore_changes = [
tags
]
}Terraform sẽ bỏ qua việc so sánh trường tags.
Điều này thường dùng khi:
- tags được hệ thống khác cập nhật
- Azure Policy tự thêm tag
- AWS Organizations tự thêm metadata
Nếu không ignore, mỗi lần terraform plan đều xuất hiện thay đổi không mong muốn.
Những tính năng mình dùng nhiều nhất
Nếu nhìn vào các project Terraform mình đang sử dụng hằng ngày, mức độ xuất hiện sẽ gần như sau:
| Feature | Tần suất |
|---|---|
| locals | ⭐⭐⭐⭐⭐ |
| for_each | ⭐⭐⭐⭐⭐ |
| lifecycle | ⭐⭐⭐⭐ |
| data sources | ⭐⭐⭐⭐ |
| dynamic | ⭐⭐⭐ |
| depends_on | ⭐⭐ |
| count | ⭐⭐ |
Đặc biệt:
localsfor_each
gần như xuất hiện trong mọi module.
Tổng kết
Terraform không có quá nhiều cú pháp.
Trong phần lớn dự án thực tế, bạn sẽ làm việc lặp đi lặp lại với một nhóm tính năng quen thuộc:
localsđể giảm lặp codefor_eachđể tạo nhiều resource ổn địnhcountcho các trường hợp đơn giảndynamicđể sinh nested blockdepends_onkhi Terraform không thể tự suy luận dependencylifecycleđể kiểm soát cách resource được tạo, cập nhật hoặc xóa
Hiểu rõ những tính năng này sẽ giúp bạn đọc được hầu hết các Terraform Module trên GitHub cũng như code trong các dự án production.
Ở bài tiếp theo, chúng ta sẽ chuyển sang một chủ đề quan trọng hơn:
Làm thế nào để tổ chức một project Terraform theo đúng cấu trúc khi số lượng resource ngày càng lớn? Chúng ta sẽ cùng tìm hiểu cách chia module, phân tách thư mục và xây dựng một kiến trúc Terraform dễ mở rộng và bảo trì..
Tiếp tục series
Bình luận
Đang tải bình luận…