Kịch bản lỗiBạn đang xây dựng hạ tầng trong đó một tài nguyên phụ thuộc vào đầu ra của một tài nguyên khác. Ví dụ, bạn có thể đang tạo một tập hợp các subnet và sau đó cố gắng khởi chạy một instance EC2 cho mỗi subnet được tạo. Mọi thứ trông có vẻ hợp lý về mặt logic trong mã nguồn của bạn, nhưng khi chạy terraform plan, bạn gặp phải rào cản này:
Lỗi: Đối số count không hợp lệ
tại main.tf dòng 24, trong resource "aws_instance" "web":
24: count = length(aws_subnet.public_subnets[*].id)
Giá trị "count" phụ thuộc vào các thuộc tính tài nguyên không thể xác định cho đến khi apply, vì vậy Terraform không thể dự đoán có bao nhiêu instance sẽ được tạo.
Tại sao điều này xảy raTerraform hoạt động theo các giai đoạn riêng biệt. Trong giai đoạn Plan, Terraform xây dựng một biểu đồ phụ thuộc và tính toán chính xác số lượng tài nguyên cần tạo, cập nhật hoặc hủy bỏ. Để làm được điều này, bất kỳ giá trị nào được truyền vào count hoặc for_each phải được xác định trước khi bất kỳ hạ tầng nào thực sự được tác động.
Lỗi xảy ra khi bạn gán count cho một thuộc tính chỉ tồn tại sau khi tài nguyên được tạo (như ID được tạo tự động, ARN được tính toán, hoặc danh sách ID từ một tài nguyên chưa tồn tại). Vì Terraform không thể dự đoán có bao nhiêu ID sẽ được trả về cho đến khi quá trình apply hoàn tất, nó sẽ từ chối tiếp tục.
Cách khắc phụcCó một vài cách để xử lý vấn đề này, tùy thuộc vào cách cấu trúc module của bạn. Dưới đây là những chiến lược hiệu quả nhất.
1. Điều hướng logic từ Variables hoặc Locals (Khuyên dùng)Thay vì để count phụ thuộc vào đầu ra của một tài nguyên, hãy để nó phụ thuộc vào đầu vào định nghĩa tài nguyên đó. Nếu bạn đang tạo các subnet dựa trên một danh sách các khối CIDR, hãy sử dụng chính danh sách đó để xác định số lượng instance của bạn.
Cách làm sai:
resource "aws_subnet" "example" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
}
resource "aws_instance" "server" {
# LỖI: Các ID không được xác định cho đến khi subnet được tạo
count = length(aws_subnet.example[*].id)
ami = "ami-123456"
instance_type = "t3.micro"
}
Cách làm đúng:
locals {
subnet_cidrs = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}
resource "aws_subnet" "example" {
for_each = toset(local.subnet_cidrs)
vpc_id = aws_vpc.main.id
cidr_block = each.value
}
resource "aws_instance" "server" {
# THÀNH CÔNG: local.subnet_cidrs đã được xác định tại thời điểm plan
for_each = toset(local.subnet_cidrs)
ami = "ami-123456"
instance_type = "t3.micro"
subnet_id = aws_subnet.example[each.value].id
}
2. Sử dụng Data Sources với FiltersNếu bạn đang cố gắng đếm các tài nguyên đã tồn tại hoặc đang được quản lý trong một file state khác, hãy sử dụng một data source với bộ lọc (filter). Terraform thường có thể giải quyết các data source trong giai đoạn plan nếu các bộ lọc là các chuỗi tĩnh.
data "aws_subnets" "existing" {
filter {
name = "vpc-id"
values = [var.vpc_id]
}
}
resource "aws_instance" "worker" {
count = length(data.aws_subnets.existing.ids)
ami = "ami-xxxxxx"
instance_type = "t2.micro"
}
3. Apply "Hai bước" (Giải pháp nhanh)Nếu bạn đang trong tình huống khẩn cấp và không thể cấu trúc lại mã ngay lập tức, bạn có thể buộc Terraform tìm hiểu các thuộc tính bằng cách nhắm mục tiêu (target) vào tài nguyên phụ thuộc trước. Đây là một giải pháp tạm thời thủ công và không phải là giải pháp lâu dài cho các pipeline CI/CD.
- Chạy
terraform apply -target=aws_subnet.example - Khi các subnet đã tồn tại và ID của chúng được lưu trong file state, hãy chạy
terraform applythông thường. Bây giờ các ID đã có trong state, Terraform có thể giải quyết hàmlength()trong giai đoạn plan của lần chạy thứ hai.
Xác minhĐể xác nhận việc khắc phục đã thành công, hãy chạy plan và kiểm tra số lượng tài nguyên trong đầu ra:
terraform plan
Nếu khắc phục thành công, bạn sẽ thấy một danh sách rõ ràng các tài nguyên dự kiến (ví dụ: Plan: 5 to add, 0 to change, 0 to destroy) thay vì lỗi "depends on resource attributes". Nếu bạn đang sử dụng for_each, hãy đảm bảo các key trong đầu ra của plan khớp với các định danh tĩnh mong muốn của bạn (như khối CIDR hoặc tên) thay vì (known after apply).
Phòng ngừa
- Static Keys: Luôn sử dụng các chuỗi tĩnh (tên, CIDR, tag) làm key cho
for_eachthay vì các ID cơ sở dữ liệu hoặc UID được tạo tự động. - Tránh
count = length(data.something.ids): Nếu data source đó phụ thuộc vào một tài nguyên được tạo trong cùng một workspace, nó có khả năng cao sẽ thất bại. - Thiết kế hướng đầu vào (Input-Driven Design): Cấu trúc các module của bạn sao cho "nguồn sự thật" (source of truth) về số lượng tài nguyên luôn là một biến hoặc một hằng số local.

