Danh sách bài viết trong series Hành Trình Làm Chủ Terraform
- Bài 1. Học Terraform Cơ Bản: Terraform Là Gì? Cài Đặt Và Viết Mã Đầu Tiên
- Bài 2. Học Terraform Với AWS: 5 Bước Tạo Máy Chủ EC2 Đầu Tiên
- Bài 3. Tạo VPC Với Terraform: Xây Dựng Hạ Tầng Mạng Trên AWS
- Bài 4. Quản Lý Tài Nguyên Với Terraform: Sử Dụng Variables Và Outputs
- Bài 5. Tự Động Hóa Triển Khai Với Terraform: Tạo Load Balancer Và Auto Scaling Group
- Bài 6. Sử Dụng Terraform Modules: Tái Sử Dụng Mã Để Quản Lý Hạ Tầng Hiệu Quả
- Bài 7. Terraform Workspaces: Quản Lý Nhiều Môi Trường Hiệu Quả Trên AWS
- Bài 8. Terraform State: Quản Lý Trạng Thái Hạ Tầng Với S3 Và DynamoDB
- Bài 9. Terraform Provisioners: Tự Động Hóa Cấu Hình Web Server Trên EC2
- Bài 10. Terraform CI/CD: Tự Động Triển Khai Hạ Tầng Với GitHub Actions
Tại Sao Cần Quản Lý Terraform State?
Terraform state là một thành phần cốt lõi để Terraform theo dõi trạng thái của hạ tầng mà nó quản lý, giúp đảm bảo tính nhất quán và chính xác khi triển khai. Trong các bài trước, chúng ta đã làm quen với Terraform cơ bản (bài 1), tạo máy chủ EC2 (bài 2), xây dựng hạ tầng mạng VPC (bài 3), sử dụng variables/outputs (bài 4), tự động hóa triển khai với Load Balancer và Auto Scaling Group (bài 5), sử dụng Terraform modules (bài 6), và quản lý nhiều môi trường với Terraform workspaces (bài 7).
Tuy nhiên, trong các dự án thực tế, đặc biệt khi làm việc nhóm, việc lưu trữ file state cục bộ (terraform.tfstate
) có thể gây ra vấn đề: file state có thể bị mất, không đồng bộ giữa các thành viên, hoặc gây xung đột khi nhiều người cùng chạy lệnh Terraform. Để giải quyết, bạn có thể lưu trữ Terraform state từ xa trên AWS S3 và sử dụng DynamoDB để hỗ trợ khóa (locking), đảm bảo an toàn và đồng bộ. Trong bài này, mình sẽ hướng dẫn bạn 5 bước để quản lý Terraform state, sử dụng S3 và DynamoDB để lưu trữ và khóa state khi triển khai một EC2 đơn giản.
Terraform State: Hướng Dẫn Từng Bước
Bước 1: Chuẩn Bị Môi Trường Và Cấu Hình AWS CLI
- Hành động:
- Đảm bảo bạn đã cài đặt Terraform 1.11.2 và AWS CLI. Nếu chưa, tham khảo bài 1 và bài 2 để cài đặt.
- Kiểm tra cấu hình AWS CLI:
aws configure
Đảm bảo bạn đã nhập đúng Access Key, Secret Key, và vùng (VD:
us-east-1
).
- Kết quả thực tế:
- Nếu AWS CLI đã được cấu hình từ trước, bạn có thể kiểm tra bằng lệnh:
aws sts get-caller-identity
Output sẽ là:
{ "UserId": "AIDAXYZ1234567890", "Account": "123456789012", "Arn": "arn:aws:iam::123456789012:user/your-user-name" }
(Output xác nhận AWS CLI đã được cấu hình đúng và có thể kết nối với tài khoản AWS của bạn).
- Nếu AWS CLI đã được cấu hình từ trước, bạn có thể kiểm tra bằng lệnh:
Bước 2: Tạo S3 Bucket Và DynamoDB Table Cho Terraform State
- Hành động:
- Tạo S3 Bucket để lưu trữ state:
aws s3api create-bucket --bucket terraform-state-example-123 --region us-east-1
(Thay
terraform-state-example-123
bằng một tên bucket duy nhất, vì tên bucket trên S3 phải là duy nhất toàn cầu). - Kích hoạt versioning cho S3 Bucket để bảo vệ state:
aws s3api put-bucket-versioning --bucket terraform-state-example-123 --versioning-configuration Status=Enabled
- Tạo DynamoDB Table để hỗ trợ khóa:
aws dynamodb create-table \ --table-name TerraformStateLock \ --attribute-definitions AttributeName=LockID,AttributeType=S \ --key-schema AttributeName=LockID,KeyType=HASH \ --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \ --region us-east-1
- Tạo S3 Bucket để lưu trữ state:
- Kết quả thực tế:
- Sau khi chạy lệnh tạo S3 Bucket, terminal sẽ hiển thị:
{ "Location": "/terraform-state-example-123" }
(Xác nhận bucket đã được tạo).
- Kiểm tra versioning của bucket bằng lệnh:
aws s3api get-bucket-versioning --bucket terraform-state-example-123
Output sẽ là:
{ "Status": "Enabled" }
(Xác nhận versioning đã được kích hoạt).
- Sau khi chạy lệnh tạo DynamoDB Table, terminal sẽ hiển thị (được rút gọn):
{ "TableDescription": { "TableName": "TerraformStateLock", "TableStatus": "ACTIVE", "ProvisionedThroughput": { "ReadCapacityUnits": 5, "WriteCapacityUnits": 5 } } }
(Xác nhận DynamoDB Table đã được tạo).
- Kiểm tra trên AWS Console:
- S3 Dashboard: Bucket
terraform-state-example-123
đã được tạo, với versioning enabled. - DynamoDB Dashboard: Table
TerraformStateLock
đã được tạo, với primary keyLockID
.
- Sau khi chạy lệnh tạo S3 Bucket, terminal sẽ hiển thị:
Bước 3: Cấu Hình Backend Trong Mã Terraform
-
Hành động:
- Tạo một thư mục mới cho dự án:
mkdir terraform-state-example cd terraform-state-example
-
Tạo file
main.tf
:touch main.tf
Mở file
main.tf
trong VS Code và dán nội dung sau:terraform { required_providers { aws = { source = "hashicorp/aws" version = "5.0.0" } } backend "s3" { bucket = "terraform-state-example-123" key = "terraform.tfstate" region = "us-east-1" dynamodb_table = "TerraformStateLock" } } provider "aws" { region = "us-east-1" } # Tạo Security Group cho EC2 resource "aws_security_group" "state_sg" { name_prefix = "state-sg-" ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "StateSG" } } # Tạo EC2 resource "aws_instance" "state_ec2" { ami = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 in us-east-1 instance_type = "t2.micro" vpc_security_group_ids = [aws_security_group.state_sg.id] tags = { Name = "StateEC2" } } # Output public IP của EC2 output "ec2_public_ip" { description = "Public IP of the EC2 instance" value = aws_instance.state_ec2.public_ip }
Giải thích:
backend "s3"
: Cấu hình backend để lưu trữ state trên S3 Bucketterraform-state-example-123
, với file state làterraform.tfstate
, và sử dụng DynamoDB TableTerraformStateLock
để khóa.aws_security_group
vàaws_instance
: Tạo một EC2 đơn giản để thử nghiệm.output
: Xuất public IP của EC2 để kiểm tra sau khi triển khai.
- Tạo một thư mục mới cho dự án:
- Kết quả thực tế:
- Cấu trúc thư mục sẽ là:
terraform-state-example/ └── main.tf
(Kiểm tra bằng lệnh
ls
, bạn sẽ thấy filemain.tf
).
- Cấu trúc thư mục sẽ là:
Bước 4: Triển Khai Hạ Tầng Và Kiểm Tra State
- Hành động:
- Trong thư mục
terraform-state-example
, khởi tạo dự án:terraform init
- Triển khai hạ tầng:
terraform apply
Khi được hỏi “Do you want to perform these actions?”, gõ
yes
và nhấn Enter. - Kiểm tra state trên S3 và DynamoDB.
- Trong thư mục
-
Kết quả thực tế:
-
Sau khi chạy
terraform init
, terminal sẽ hiển thị:Initializing the backend... Initializing provider plugins... - Finding hashicorp/aws versions matching "5.0.0"... - Installing hashicorp/aws v5.0.0... - Installed hashicorp/aws v5.0.0 (signed by HashiCorp) Terraform has been successfully initialized!
(Dòng “Terraform has been successfully initialized!” xác nhận quá trình khởi tạo thành công, và backend đã được cấu hình).
-
Sau khi chạy
terraform apply
, terminal sẽ hiển thị:Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # aws_instance.state_ec2 will be created + resource "aws_instance" "state_ec2" { + ami = "ami-0c55b159cbfafe1f0" + instance_type = "t2.micro" + tags = { + "Name" = "StateEC2" } } # aws_security_group.state_sg will be created + resource "aws_security_group" "state_sg" { + name_prefix = "state-sg-" + tags = { + "Name" = "StateSG" } } Plan: 2 to add, 0 to change, 0 to destroy. Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_security_group.state_sg: Creating... aws_security_group.state_sg: Creation complete after 2s [id=sg-0123456789abcdef0] aws_instance.state_ec2: Creating... aws_instance.state_ec2: Still creating... [10s elapsed] aws_instance.state_ec2: Creation complete after 15s [id=i-0123456789abcdef0] Apply complete! Resources: 2 added, 0 changed, 0 destroyed. Outputs: ec2_public_ip = "54.123.45.67"
(Dòng “Apply complete! Resources: 2 added, 0 changed, 0 destroyed” xác nhận EC2 đã được tạo).
- Kiểm tra state trên S3:
- Truy cập S3 Bucket
terraform-state-example-123
trên AWS Console, bạn sẽ thấy fileterraform.tfstate
. - Kiểm tra bằng lệnh:
aws s3 ls s3://terraform-state-example-123/
Output sẽ là:
2025-03-23 12:00:00 1234 terraform.tfstate
(Xác nhận file state đã được lưu trên S3).
- Kiểm tra khóa trên DynamoDB:
- Trong quá trình chạy
terraform apply
, DynamoDB TableTerraformStateLock
sẽ tạm thời có một record để khóa state. Sau khi hoàn thành, record này sẽ bị xóa. - Kiểm tra bằng lệnh:
aws dynamodb scan --table-name TerraformStateLock
Output sẽ là:
{ "Items": [], "Count": 0, "ScannedCount": 0 }
(Không có record vì quá trình apply đã hoàn tất và khóa đã được giải phóng).
- Kiểm tra trên AWS Console (EC2 Dashboard):
- Một instance với tag
Name: StateEC2
, trạng tháiRunning
.
-
Bước 5: Xóa Tài Nguyên Để Dọn Dẹp
- Hành động:
- Xóa tài nguyên được quản lý bởi Terraform:
terraform destroy
Khi được hỏi “Do you really want to destroy all resources?”, gõ
yes
và nhấn Enter. - Xóa S3 Bucket và DynamoDB Table:
aws s3 rb s3://terraform-state-example-123 --force aws dynamodb delete-table --table-name TerraformStateLock
- Xóa tài nguyên được quản lý bởi Terraform:
-
Kết quả thực tế:
-
Sau khi chạy
terraform destroy
, terminal sẽ hiển thị:Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: - destroy Terraform will perform the following actions: # aws_instance.state_ec2 will be destroyed - resource "aws_instance" "state_ec2" { - ami = "ami-0c55b159cbfafe1f0" -> null - instance_type = "t2.micro" -> null - id = "i-0123456789abcdef0" -> null } # aws_security_group.state_sg will be destroyed - resource "aws_security_group" "state_sg" { - name_prefix = "state-sg-" -> null - id = "sg-0123456789abcdef0" -> null } Plan: 0 to add, 0 to change, 2 to destroy. Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes aws_instance.state_ec2: Destroying... [id=i-0123456789abcdef0] aws_instance.state_ec2: Still destroying... [10s elapsed] aws_instance.state_ec2: Destruction complete after 15s aws_security_group.state_sg: Destroying... [id=sg-0123456789abcdef0] aws_security_group.state_sg: Destruction complete after 2s Destroy complete! Resources: 2 destroyed.
(Dòng “Destroy complete! Resources: 2 destroyed” xác nhận EC2 và Security Group đã bị xóa).
- Sau khi chạy lệnh xóa S3 Bucket, terminal sẽ không hiển thị output (xóa thành công).
- Sau khi chạy lệnh xóa DynamoDB Table, terminal sẽ hiển thị (được rút gọn):
{ "TableDescription": { "TableName": "TerraformStateLock", "TableStatus": "DELETING" } }
(Xác nhận DynamoDB Table đang được xóa).
- Kiểm tra lại trên AWS Console:
- EC2 Dashboard: Instance
StateEC2
không còn tồn tại. - S3 Dashboard: Bucket
terraform-state-example-123
không còn tồn tại. - DynamoDB Dashboard: Table
TerraformStateLock
không còn tồn tại.
-
Kết Quả Đạt Được
- Bạn đã học cách quản lý Terraform state bằng cách lưu trữ từ xa trên S3 và sử dụng DynamoDB để khóa state, đảm bảo an toàn và đồng bộ khi làm việc nhóm.
- Bạn đã triển khai một EC2 đơn giản và xác nhận state được lưu trữ trên S3.
- Bạn đã kiểm tra cơ chế khóa trên DynamoDB trong quá trình triển khai.
- Bạn đã xóa tài nguyên, bao gồm cả S3 Bucket và DynamoDB Table, để dọn dẹp.
Lưu Ý Quan Trọng
- Bảo mật state: File state chứa thông tin nhạy cảm (VD: ID tài nguyên, output). Đảm bảo S3 Bucket được bảo mật bằng IAM policy và bật mã hóa (encryption).
- Chi phí AWS: S3 và DynamoDB có chi phí thấp (khoảng $0.023/GB/tháng cho S3 và $1.25/tháng cho DynamoDB với 25 WCU/RCU), nhưng hãy xóa tài nguyên sau khi thử nghiệm.
- Làm việc nhóm: Khi nhiều người cùng làm việc, luôn sử dụng khóa (locking) để tránh xung đột state. DynamoDB là một lựa chọn tốt cho việc này.
- Tài liệu tham khảo: Xem thêm về Terraform state trong tài liệu chính thức (Terraform State) và backend S3 (S3 Backend).