Bài 8. Terraform State: Quản Lý Trạng Thái Hạ Tầng Với S3 Và DynamoDB

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:
    1. Đả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.
    2. 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).

Bước 2: Tạo S3 Bucket Và DynamoDB Table Cho Terraform State

  • Hành động:
    1. 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).

    2. 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
    3. 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
  • 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 key LockID.

Bước 3: Cấu Hình Backend Trong Mã Terraform

  • Hành động:

    1. Tạo một thư mục mới cho dự án:
      mkdir terraform-state-example
      cd terraform-state-example
    2. 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 Bucket terraform-state-example-123, với file state là terraform.tfstate, và sử dụng DynamoDB Table TerraformStateLock để khóa.
      • aws_security_groupaws_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.
  • 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 file main.tf).

Bước 4: Triển Khai Hạ Tầng Và Kiểm Tra State

  • Hành động:
    1. Trong thư mục terraform-state-example, khởi tạo dự án:
      terraform init
    2. 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.

    3. Kiểm tra state trên S3 và DynamoDB.
  • 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 file terraform.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 Table TerraformStateLock 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ái Running.

Bước 5: Xóa Tài Nguyên Để Dọn Dẹp

  • Hành động:
    1. 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.

    2. Xóa S3 Bucket và DynamoDB Table:
      aws s3 rb s3://terraform-state-example-123 --force
      aws dynamodb delete-table --table-name TerraformStateLock
  • 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).
Điều hướng chuỗi bài viết<< Bài 7. Terraform Workspaces: Quản Lý Nhiều Môi Trường Hiệu Quả Trên AWS
>> Bài 9. Terraform Provisioners: Tự Động Hóa Cấu Hình Web Server Trên EC2
Chia sẻ bài viết:
Theo dõi
Thông báo của
0 Góp ý
Được bỏ phiếu nhiều nhất
Mới nhất Cũ nhất
Phản hồi nội tuyến
Xem tất cả bình luận