Lỗi Gặp Phải
Bạn chạy terraform apply và nó dừng lại đột ngột:
Error: A resource with the ID "my-s3-bucket" already exists
on main.tf line 12, in resource "aws_s3_bucket" "my_bucket":
12: resource "aws_s3_bucket" "my_bucket" {
Chuyện gì đang xảy ra: Terraform đang cố tạo mới một resource đã tồn tại trong tài khoản cloud của bạn. Resource đó không có trong state file, nên Terraform không biết nó đang ở đó. Nó cố tạo lại. Provider từ chối.
Nguyên Nhân
Có sự chênh lệch giữa những gì tồn tại trên cloud provider và những gì Terraform đang theo dõi. Một số tình huống dẫn đến điều này:
- Ai đó tạo resource thủ công — click trên AWS console, dùng lệnh
aws cli, GCP UI, hoặc bất kỳ cách nào khác. - Một công cụ khác đang quản lý nó: Terraform workspace khác, Pulumi, CloudFormation, hoặc script tùy chỉnh.
- State file bị xóa hoặc bị hỏng. Resource vẫn chạy; bộ nhớ của Terraform thì không còn nữa.
- Lệnh
terraform destroythất bại giữa chừng. State bị xóa sạch; resource vẫn tồn tại. - Bạn chuyển sang backend mới nhưng bỏ qua bước migrate state.
Cách Sửa 1: Import Resource Hiện Có Vào State (Khuyến Nghị)
Import resource vào state. Khi đã có trong state, Terraform biết nó tồn tại và không cố tạo lại nữa.
Bước 1: Tìm resource ID trên cloud provider
Với AWS S3:
aws s3 ls | grep my-bucket-name
Với EC2 instance:
aws ec2 describe-instances --filters "Name=tag:Name,Values=my-instance" \
--query 'Reservations[*].Instances[*].InstanceId' --output text
Với GCP:
gcloud compute instances list --filter="name=my-instance"
Bước 2: Chạy terraform import
Cú pháp:
terraform import <resource_type>.<resource_name> <provider_resource_id>
Ví dụ thực tế:
# AWS S3 bucket — tên bucket chính là ID
terraform import aws_s3_bucket.my_bucket my-actual-bucket-name
# AWS EC2 instance — dùng instance ID (i-...)
terraform import aws_instance.web i-0abc1234def56789
# AWS security group
terraform import aws_security_group.app sg-0123456789abcdef0
# GCP compute instance — đường dẫn resource đầy đủ
terraform import google_compute_instance.vm projects/my-project/zones/us-central1-a/instances/my-instance
# Azure resource group — ARM resource ID đầy đủ
terraform import azurerm_resource_group.rg /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg
Bước 3: Chạy terraform plan và sửa drift
Sau khi import, config .tf của bạn nhiều khả năng không khớp hoàn toàn với resource thực tế. Chạy:
terraform plan
Bạn sẽ thấy diff — các thuộc tính Terraform muốn thay đổi. Cập nhật config để phản ánh đúng giá trị thực:
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-actual-bucket-name"
# Khớp với các cài đặt hiện có để tránh thay đổi không mong muốn
}
Tiếp tục chỉnh cho đến khi plan hiển thị:
No changes. Infrastructure is up-to-date.
Cách Sửa 2: Dùng import Block (Terraform 1.5+)
Terraform 1.5 bổ sung block import theo kiểu khai báo. Không cần lệnh CLI — chỉ cần khai báo trong config:
import {
to = aws_s3_bucket.my_bucket
id = "my-actual-bucket-name"
}
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-actual-bucket-name"
}
Sau đó:
terraform plan # Xem trước những gì sẽ được import
terraform apply # Thực hiện import
Block này sẽ biến mất sau khi apply thành công. Một số team giữ lại trong version control như bằng chứng lịch sử cho các resource được onboard.
Cách Sửa 3: Xóa Resource và Để Terraform Tạo Lại
Nếu resource không chứa dữ liệu quan trọng và có thể chấp nhận downtime ngắn, hãy xóa nó và để Terraform tạo mới từ đầu.
# Xóa một S3 bucket rỗng
aws s3 rb s3://my-actual-bucket-name
# Sau đó apply bình thường
terraform apply
Không dùng cách này cho database, bucket có dữ liệu, hay bất kỳ thứ gì quan trọng. Chỉ dành cho các resource thực sự có thể bỏ đi như bucket rỗng hay security group thử nghiệm.
Cách Sửa 4: Dùng Tên Khác
Đôi khi giải pháp đúng đắn là chọn một tên không bị trùng. Thay đổi argument bucket, name, hoặc id trong file .tf của bạn:
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-bucket-name-v2" # Tên mới, không bị trùng
}
Hữu ích khi bạn muốn tạo mới một resource và không cần quan tâm đến resource đang tồn tại.
Kiểm Tra Lại
Sau khi import, xác nhận state đã ghi nhận resource:
# Xem toàn bộ resource đang được theo dõi
terraform state list
# Xem chi tiết một resource cụ thể
terraform state show aws_s3_bucket.my_bucket
Chạy plan lần cuối. Không có thay đổi nào nghĩa là bạn đã xong:
terraform plan
# Kết quả mong đợi:
# No changes. Infrastructure is up-to-date.
Vẫn còn thấy thay đổi? Config .tf của bạn có các thuộc tính chưa khớp với resource đã import. Tiếp tục điều chỉnh cho đến khi diff biến mất.
Phòng Ngừa
- Không tạo resource cloud thủ công nếu Terraform đang quản lý chúng. Click trên console hay dùng lệnh CLI ngoài Terraform chính là nguyên nhân gây ra vấn đề này.
- Dùng remote state kết hợp locking — S3 + DynamoDB hoặc Terraform Cloud. State file lưu local dễ bị mất, hỏng, hoặc bị ghi đè trong team.
- Lên kế hoạch import trước khi onboard hạ tầng hiện có. Đừng bao giờ viết block
resourcemới cho resource đã tồn tại rồi apply bừa. - Luôn chạy
terraform plantrướcapply. Nếu plan định tạo thứ gì đó lẽ ra đã tồn tại, đó là cảnh báo sớm cho bạn. - Gắn tag resource với
managed-by = terraform. Giúp đồng nghiệp biết rõ cái nào không được đụng vào.

