Import Infrastructure có sẵn vào Terraform
Hướng dẫn đưa hạ tầng đã tồn tại vào Terraform một cách an toàn bằng terraform import và Import Blocks, tránh tạo lại resource và từng bước chuyển sang Infrastructure as Code.

Import Infrastructure có sẵn vào Terraform
Ở những bài trước, chúng ta luôn bắt đầu từ một project hoàn toàn mới.
terraform init
terraform plan
terraform apply
Terraform sẽ tạo ra toàn bộ infrastructure từ đầu.
Nhưng thực tế ở doanh nghiệp lại hoàn toàn khác.
Rất hiếm khi bạn được bắt đầu với một tài khoản AWS hay Azure trống.
Thông thường bạn sẽ gặp những hệ thống như:
- Hàng trăm EC2 đã tồn tại
- VPC được tạo từ nhiều năm trước
- Database đang chạy production
- Cloudflare DNS đã cấu hình
- Vercel Project đang phục vụ hàng triệu request
- S3 Bucket chứa dữ liệu nhiều TB
Những resource này đều đang hoạt động.
Bạn không thể xóa đi rồi tạo lại chỉ để dùng Terraform.
Vậy Terraform sẽ quản lý chúng như thế nào?
Đó chính là mục đích của Terraform Import.
Một câu hỏi rất phổ biến
Rất nhiều người mới học Terraform thường nghĩ như sau:
Muốn Terraform quản lý thì phải tạo resource bằng Terraform.
Điều này không đúng.
Terraform không quan tâm ai đã tạo resource.
Terraform chỉ quan tâm:
"Resource này đã được ghi vào State hay chưa?"
Nếu State biết resource tồn tại, Terraform sẽ quản lý được.
Nếu State không biết, Terraform sẽ nghĩ resource chưa tồn tại.
Đó là lý do Import ra đời.
Terraform Import là gì?
Hiểu đơn giản:
Import chỉ làm một việc duy nhất.
Nó nói với Terraform rằng:
"Resource ngoài đời này đã tồn tại rồi. Hãy ghi nó vào Terraform State."
Ví dụ:
Production đang có một EC2.
EC2
ID:
i-0123456789
Terraform hoàn toàn không biết điều này.
State:
(empty)
Khi chạy:
terraform import aws_instance.web i-0123456789Terraform sẽ đọc thông tin resource từ AWS.
Sau đó ghi vào State.
Terraform State
↓
aws_instance.web
↓
ID = i-0123456789
Lưu ý.
Import không tạo resource mới.
Import cũng không sửa resource.
Nó chỉ cập nhật Terraform State.
Terraform Import không tạo Configuration
Đây là điểm khiến rất nhiều người bất ngờ.
Ví dụ sau khi import.
State đã có:
aws_instance.web
Nhưng project lại chưa có:
resource "aws_instance" "web" {
}Nếu chạy:
terraform planTerraform sẽ báo lỗi.
Bởi vì State đã biết resource.
Nhưng Configuration lại không tồn tại.
Terraform luôn cần hai thứ:
Configuration
+
State
Nếu thiếu một trong hai.
Terraform sẽ không hoạt động đúng.
Hai thành phần luôn phải khớp nhau
Terraform luôn so sánh:
Configuration
↓
State
↓
Infrastructure
Ba thành phần này cần đồng nhất.
Nếu chỉ có State.
Terraform không biết resource nên có thuộc tính gì.
Nếu chỉ có Configuration.
Terraform không biết resource đã tồn tại hay chưa.
Chỉ khi cả hai cùng tồn tại.
Terraform mới có thể thực hiện Plan chính xác.
Ví dụ thực tế
AWS đã có Bucket:
company-production-assets
Bạn viết:
resource "aws_s3_bucket" "assets" {
bucket = "company-production-assets"
}Sau đó chạy:
terraform import aws_s3_bucket.assets company-production-assetsKết quả:
Configuration
✓
State
✓
Infrastructure
✓
Từ thời điểm này.
Terraform chính thức quản lý Bucket đó.
Điều gì xảy ra nếu không Import?
Giả sử Bucket đã tồn tại.
Nhưng bạn lại viết:
resource "aws_s3_bucket" "assets" {
bucket = "company-production-assets"
}Rồi chạy:
terraform applyTerraform sẽ nghĩ:
Bucket chưa tồn tại
Nó sẽ gửi API tạo mới.
AWS trả về:
BucketAlreadyExists
Hoặc:
BucketAlreadyOwnedByYou
Đây là lỗi rất phổ biến khi migrate sang Terraform.
Import không phải Migration hoàn chỉnh
Nhiều người nghĩ quy trình chỉ là:
terraform import
↓
Done
Thực tế không phải vậy.
Import mới chỉ là bước đầu.
Sau khi Import.
Bạn vẫn cần:
- Viết Configuration đầy đủ
- Đồng bộ thuộc tính
- Kiểm tra Drift
- Chạy Plan
- Đảm bảo không có thay đổi ngoài ý muốn
Đó mới là quá trình migrate infrastructure sang Terraform.
Ở phần tiếp theo, chúng ta sẽ đi sâu vào toàn bộ workflow import trong production, tìm hiểu terraform import, import blocks của Terraform 1.5+, cách generate configuration và những lỗi phổ biến khi đưa hệ thống đang chạy vào Terraform.
# Workflow Import trong thực tế
Khi mới học Terraform, nhiều người thường nghĩ quy trình sẽ là:
Viết Configuration
↓
Import
↓
Done
Thực tế ở production, quy trình gần như ngược lại.
Xác định Resource
↓
Viết Configuration
↓
Import
↓
Plan
↓
Điều chỉnh Configuration
↓
Plan = No changes
↓
Commit
Mục tiêu cuối cùng luôn là:
> Terraform không tạo mới, không sửa gì ngoài ý muốn.
---
# Bước 1 - Xác định Resource cần Import
Đầu tiên, cần xác định chính xác resource muốn Terraform quản lý.
Ví dụ AWS có:
EC2 ID = i-0123456789
Hoặc
S3 Bucket company-assets
Hoặc
Cloudflare Zone
example.com
Điều quan trọng nhất là phải lấy đúng **ID** của resource.
Mỗi provider sẽ có cách định danh khác nhau.
Ví dụ:
AWS EC2
i-0123456789
AWS S3
company-assets
Cloudflare
zone_id
Vercel
project_id
Azure
Full Resource ID
Đọc tài liệu của provider luôn là bước đầu tiên.
---
# Bước 2 - Viết Terraform Configuration
Đây là điểm mà nhiều người làm sai.
Họ chạy Import trước.
Sau đó mới viết file `.tf`.
Điều này khiến project rất khó hiểu.
Thông thường nên tạo resource trước.
Ví dụ:
```hcl
resource "aws_s3_bucket" "assets" {
bucket = "company-assets"
}
Hoặc:
resource "aws_instance" "web" {
}Ban đầu có thể chưa đầy đủ.
Chỉ cần đúng tên resource.
Sau đó mới Import.
Bước 3 - Chạy terraform import
Ví dụ với EC2.
terraform import aws_instance.web i-0123456789Ví dụ với S3.
terraform import aws_s3_bucket.assets company-assetsTerraform sẽ:
AWS API
↓
Read Resource
↓
Terraform State
Lưu ý.
Terraform không sửa gì trên AWS.
Nó chỉ ghi dữ liệu vào State.
Kiểm tra Terraform State
Sau khi Import.
Có thể xem State bằng:
terraform state listVí dụ:
aws_instance.web
aws_security_group.web
aws_s3_bucket.assets
Muốn xem chi tiết:
terraform state show aws_instance.webTerraform sẽ hiển thị toàn bộ attribute.
Ví dụ:
instance_type = t3.micro
ami = ami-123456
availability_zone = ap-southeast-1a
private_ip = ...
...
Đây chính là thông tin Terraform đang lưu trong State.
Điều gì xảy ra khi chạy Plan?
Giả sử Configuration chỉ có:
resource "aws_instance" "web" {
}Sau khi Import.
Chạy:
terraform planTerraform có thể hiển thị:
~ instance_type
~ ami
~ tags
~ monitoring
~ ebs_optimized
...
Rất nhiều thay đổi.
Không phải vì Import sai.
Mà vì Configuration còn thiếu.
Terraform đang so sánh:
Configuration
↓
State
↓
Infrastructure
Configuration chưa mô tả đầy đủ resource.
Terraform nghĩ cần sửa lại.
Bổ sung Configuration
Lúc này chúng ta cần cập nhật file Terraform.
Ví dụ:
resource "aws_instance" "web" {
ami = "ami-123456"
instance_type = "t3.micro"
tags = {
Name = "production-web"
}
}Sau đó chạy:
terraform planNếu vẫn còn thay đổi.
Tiếp tục bổ sung.
Lặp lại cho tới khi:
No changes.
Đây mới là trạng thái mong muốn.
Mục tiêu cuối cùng
Một quá trình Import thành công sẽ có kết quả:
Configuration
✓
State
✓
Infrastructure
✓
Ba thành phần hoàn toàn giống nhau.
Khi chạy:
terraform planKết quả:
No changes.
Infrastructure is up-to-date.
Đây là thời điểm an toàn để commit source code.
Terraform 1.5 - Import Blocks
Trong nhiều năm.
Terraform chỉ hỗ trợ:
terraform importLệnh này hoạt động tốt.
Nhưng có một nhược điểm lớn.
Lịch sử Import không nằm trong source code.
Nếu đồng nghiệp clone project.
Họ sẽ không biết resource đã được Import như thế nào.
Terraform 1.5 giải quyết vấn đề này bằng Import Blocks.
Ví dụ:
import {
to = aws_s3_bucket.assets
id = "company-assets"
}Sau đó chạy:
terraform planTerraform sẽ tự thực hiện Import.
Không cần chạy lệnh thủ công nữa.
Điều này giúp toàn bộ quá trình migrate infrastructure trở thành một phần của source code.
Generate Configuration tự động
Terraform còn hỗ trợ sinh Configuration từ resource đã tồn tại.
Ví dụ:
terraform plan \
-generate-config-out=generated.tfTerraform sẽ đọc resource.
Sau đó tạo file:
generated.tf
Trong file sẽ có:
resource "aws_s3_bucket" "assets" {
...
}Đây là cách rất nhanh để bootstrap project Terraform từ hạ tầng hiện có.
Tuy nhiên.
Configuration được sinh ra thường khá dài.
Bao gồm rất nhiều giá trị mặc định.
Không nên commit trực tiếp.
Thay vào đó.
Hãy xem nó như một bản tham khảo.
Sau đó rút gọn lại thành style của team.
terraform import hay Import Blocks?
Hiện nay cả hai đều được hỗ trợ.
Nếu chỉ Import một vài resource.
Lệnh truyền thống vẫn rất nhanh.
terraform import
Nếu migrate cả một hệ thống lớn.
Import Blocks sẽ phù hợp hơn.
Bởi vì:
- Có thể review qua Pull Request
- Có lịch sử trong Git
- Dễ lặp lại
- Phù hợp CI/CD
- Không cần nhớ các lệnh Import
Đây cũng là hướng HashiCorp khuyến khích sử dụng trong các phiên bản Terraform mới.
Những sai lầm phổ biến khi Import
Bản thân lệnh Import không quá phức tạp.
Điều khó nằm ở việc đồng bộ giữa Configuration, State và Infrastructure.
Đây cũng là nơi phần lớn lỗi xảy ra.
Sai lầm 1 - Import trước rồi mới viết Configuration
Đây là lỗi phổ biến nhất.
Ví dụ.
Chạy:
terraform import aws_instance.web i-0123456789State sẽ có:
aws_instance.web
Nhưng project lại chưa có:
resource "aws_instance" "web" {
}Sau vài tuần.
Một thành viên khác mở project.
Họ nhìn vào source code.
Không có EC2 nào cả.
Nhưng trong State lại tồn tại.
Điều này khiến project rất khó bảo trì.
Configuration luôn nên được viết trước.
Sau đó mới Import.
Sai lầm 2 - Import nhầm Resource Address
Ví dụ.
Configuration:
resource "aws_instance" "frontend" {
}Nhưng lại chạy:
terraform import aws_instance.backend i-0123456789Terraform sẽ báo lỗi.
Hoặc tệ hơn.
Import vào sai Resource Address.
Sau này rất khó hiểu resource nào đang đại diện cho infrastructure thực tế.
Resource Address phải khớp hoàn toàn với Configuration.
Sai lầm 3 - Chỉ Import một phần Infrastructure
Ví dụ.
Một EC2 thường đi kèm:
- Security Group
- IAM Role
- Elastic IP
- EBS Volume
- Network Interface
Nhưng chỉ Import EC2.
EC2
✓ Imported
Security Group
✗
IAM Role
✗
Sau này.
Terraform sẽ cố tạo mới những resource còn thiếu.
Hoặc không thể resolve dependency.
Khi migrate.
Hãy xác định đầy đủ những resource liên quan.
Sai lầm 4 - Thấy Plan có thay đổi rồi Apply ngay
Sau khi Import.
Nhiều người chạy:
terraform planTerraform hiển thị:
~ instance_type
~ monitoring
~ tags
~ root_block_device
...
Thay vì tìm nguyên nhân.
Họ lại chạy:
terraform applyTerraform sẽ bắt đầu sửa production.
Đây là một trong những lỗi nguy hiểm nhất.
Sau khi Import.
Mục tiêu luôn là:
terraform plan
↓
No changes
Nếu còn thay đổi.
Phải hiểu rõ lý do trước khi Apply.
Sai lầm 5 - Tin hoàn toàn vào generated.tf
Terraform có thể sinh Configuration.
Ví dụ:
terraform plan \
-generate-config-out=generated.tfFile được tạo thường rất dài.
Ví dụ:
resource "aws_instance" "web" {
disable_api_stop = false
monitoring = false
ebs_optimized = false
...
}Rất nhiều thuộc tính thực ra chỉ là giá trị mặc định.
Nếu commit toàn bộ.
Project sẽ trở nên khó đọc.
Configuration nên được tinh gọn.
Chỉ giữ những thuộc tính mà team thực sự muốn quản lý.
Sai lầm 6 - Import trực tiếp trên Production
Một số team làm như sau.
Production
↓
terraform import
↓
terraform apply
Nếu có sai sót.
Production sẽ bị ảnh hưởng ngay lập tức.
Quy trình tốt hơn là:
Clone Configuration
↓
Import
↓
Plan
↓
Review
↓
Commit
↓
CI/CD
↓
Production
Import cũng nên được review giống như code.
Workflow Production mà nhiều team sử dụng
Trong thực tế.
Việc migrate một hệ thống lớn thường diễn ra theo từng bước.
Inventory Resource
↓
Viết Terraform
↓
Import
↓
Plan
↓
Fix Configuration
↓
Plan = No Changes
↓
Pull Request
↓
Review
↓
Merge
↓
CI/CD
Điều đáng chú ý là.
Terraform chỉ được phép quản lý resource sau khi:
Plan
↓
No changes
Đây gần như là một quy tắc bất thành văn trong các team DevOps.
Khi nào nên Import?
Import phù hợp khi:
- Bắt đầu áp dụng Terraform cho hệ thống cũ
- Chuyển từ quản lý thủ công sang IaC
- Tiếp quản hạ tầng từ team khác
- Đưa resource được tạo bằng Console vào Terraform
- Quản lý dịch vụ của bên thứ ba như Cloudflare, Vercel hoặc GitHub
Nếu toàn bộ infrastructure đều được tạo bằng Terraform ngay từ đầu.
Bạn gần như sẽ không cần Import.
Khi nào không nên Import?
Không phải resource nào cũng đáng để Import.
Ví dụ:
- Resource tạm thời
- Máy test
- Sandbox
- Hạ tầng chỉ tồn tại vài ngày
- Resource được tạo tự động bởi dịch vụ khác
Việc Import những resource này chỉ khiến State trở nên phức tạp hơn.
Terraform nên quản lý những thành phần có vòng đời dài và thực sự cần được khai báo dưới dạng Infrastructure as Code.
Một góc nhìn thú vị
Terraform Import thường khiến nhiều người nghĩ rằng:
"Terraform đang học về Infrastructure."
Thực ra thì ngược lại.
Infrastructure không thay đổi.
Terraform chỉ đang cập nhật "trí nhớ" của mình.
Nếu ở bài về Terraform State chúng ta đã ví:
Configuration là ý định.
State là trí nhớ.
Thì Import chính là quá trình:
Đồng bộ trí nhớ của Terraform với thế giới thực.
Sau khi quá trình này hoàn tất.
Terraform mới có đủ thông tin để đưa ra Execution Plan chính xác.
Tổng kết
Import là một trong những tính năng quan trọng nhất của Terraform khi làm việc với hệ thống đã tồn tại.
Điều cần nhớ là:
- Import không tạo resource mới
- Import không chỉnh sửa infrastructure
- Import chỉ ghi thông tin vào Terraform State
- Configuration và State luôn phải đồng bộ
- Chỉ Apply khi
terraform plantrả về No changes - Với Terraform 1.5+, nên ưu tiên Import Blocks để toàn bộ quá trình Import được quản lý ngay trong source code
Khi hiểu đúng Import, bạn sẽ có thể từng bước chuyển đổi những hệ thống đang chạy ngoài thực tế sang Infrastructure as Code mà không cần xây dựng lại từ đầu.
Bài tiếp theo
Đến thời điểm này, chúng ta đã biết cách viết Terraform, tổ chức project, sử dụng Module và đưa hạ tầng hiện có vào Terraform.
Tuy nhiên, vẫn còn một vấn đề rất lớn.
Làm thế nào để nhiều người cùng làm việc trên một Terraform project mà không ghi đè State của nhau?
Làm sao để lưu Terraform State an toàn trên cloud, hỗ trợ locking và hoạt động tốt trong CI/CD?
Ở bài tiếp theo, chúng ta sẽ tìm hiểu về Remote State Backend, nền tảng không thể thiếu của bất kỳ dự án Terraform production nào.
Tiếp tục series
Bình luận
Đang tải bình luận…