Bài 9. Terraform Provisioners: Tự Động Hóa Cấu Hình Web Server Trên EC2

Tại Sao Cần Sử Dụng Terraform Provisioners?

Terraform provisioners là công cụ mạnh mẽ để tự động hóa các tác vụ sau khi tài nguyên được tạo, giúp bạn cấu hình máy chủ hoặc triển khai ứng dụng mà không cần can thiệp thủ công. 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), quản lý nhiều môi trường với Terraform workspaces (bài 7), và quản lý trạng thái với Terraform state (bài 8).

Tuy nhiên, sau khi tạo EC2, bạn thường cần thực hiện các bước cấu hình như cài đặt phần mềm, copy file, hoặc chạy script. Terraform provisioners cho phép bạn thực hiện những tác vụ này ngay trong mã Terraform, đảm bảo tính tự động và nhất quán. Trong bài này, mình sẽ hướng dẫn bạn 5 bước để sử dụng Terraform provisioners, tự động cài đặt và cấu hình web server Nginx trên EC2, sau đó kiểm tra kết quả bằng cách truy cập web server.

Terraform Provisioners: 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).

    3. Tạo hoặc đảm bảo bạn đã có SSH key pair trên AWS:
      • Truy cập AWS Console > EC2 > Key Pairs.
      • Tạo key pair mới (VD: my-key) và tải file .pem (VD: my-key.pem).
      • Đặt quyền cho file .pem:
        chmod 400 my-key.pem
  • 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"
      }

      (Xác nhận AWS CLI đã được cấu hình đúng).

    • Kiểm tra file my-key.pem:
      ls -l my-key.pem

      Output sẽ là:

      -r--------  1 user user 1696 Mar 23 12:00 my-key.pem

      (Quyền 400 xác nhận file đã được bảo mật).

Bước 2: Tạo Thư Mục Dự Án Và Viết Mã Terraform

  • Hành động:

    1. Tạo một thư mục mới cho dự án:
      mkdir terraform-provisioners-example
      cd terraform-provisioners-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"
       }
      }
      }
      
      provider "aws" {
      region = "us-east-1"
      }
      
      # Tạo Security Group cho EC2
      resource "aws_security_group" "web_sg" {
      name_prefix = "web-sg-"
      
      ingress {
       from_port   = 22
       to_port     = 22
       protocol    = "tcp"
       cidr_blocks = ["0.0.0.0/0"]
      }
      
      ingress {
       from_port   = 80
       to_port     = 80
       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 = "WebSG"
      }
      }
      
      # Tạo EC2 với provisioner
      resource "aws_instance" "web_server" {
      ami           = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 in us-east-1
      instance_type = "t2.micro"
      key_name      = "my-key" # Thay bằng tên key pair của bạn
      vpc_security_group_ids = [aws_security_group.web_sg.id]
      associate_public_ip_address = true
      
      tags = {
       Name = "WebServer"
      }
      
      # Sử dụng provisioner để cài đặt Nginx
      provisioner "remote-exec" {
       inline = [
         "sudo yum update -y",
         "sudo yum install -y nginx",
         "sudo systemctl start nginx",
         "sudo systemctl enable nginx",
         "echo '<h1>Welcome to Nginx - Deployed by Terraform!</h1>' | sudo tee /usr/share/nginx/html/index.html"
       ]
      
       connection {
         type        = "ssh"
         user        = "ec2-user"
         private_key = file("my-key.pem") # Đường dẫn đến file .pem của bạn
         host        = self.public_ip
       }
      }
      }
      
      # Output public IP của EC2
      output "web_server_public_ip" {
      description = "Public IP of the web server"
      value       = aws_instance.web_server.public_ip
      }

      Giải thích:

      • aws_security_group: Tạo Security Group cho phép truy cập SSH (port 22) và HTTP (port 80).
      • aws_instance: Tạo EC2 với key pair my-key và gán Security Group.
      • provisioner "remote-exec": Sử dụng provisioner để SSH vào EC2 và chạy các lệnh cài đặt Nginx, khởi động dịch vụ, và tạo file index.html.
      • connection: Cấu hình kết nối SSH với EC2 bằng user ec2-user, file my-key.pem, và public IP của instance.
      • output: Xuất public IP của EC2 để truy cập web server.
  • Kết quả thực tế:
    • Cấu trúc thư mục sẽ là:
      terraform-provisioners-example/
      ├── main.tf
      └── my-key.pem

      (Kiểm tra bằng lệnh ls, bạn sẽ thấy file main.tfmy-key.pem nếu bạn đã copy file .pem vào thư mục).

Bước 3: Khởi Tạo Dự Án Terraform

  • Hành động:
    1. Trong thư mục terraform-provisioners-example, chạy lệnh:
      terraform init
  • Kết quả thực tế:

    • 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).

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

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

    2. Truy cập web server qua public IP của EC2.
  • Kết quả thực tế:

    • 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.web_server will be created
      + resource "aws_instance" "web_server" {
       + ami                          = "ami-0c55b159cbfafe1f0"
       + instance_type                = "t2.micro"
       + key_name                     = "my-key"
       + tags                         = {
           + "Name" = "WebServer"
         }
      }
      
      # aws_security_group.web_sg will be created
      + resource "aws_security_group" "web_sg" {
       + name_prefix = "web-sg-"
       + tags        = {
           + "Name" = "WebSG"
         }
      }
      
      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.web_sg: Creating...
      aws_security_group.web_sg: Creation complete after 2s [id=sg-0123456789abcdef0]
      aws_instance.web_server: Creating...
      aws_instance.web_server: Still creating... [10s elapsed]
      aws_instance.web_server: Creation complete after 15s [id=i-0123456789abcdef0]
      aws_instance.web_server: Provisioning with 'remote-exec'...
      aws_instance.web_server (remote-exec): Connecting to remote host via SSH...
      aws_instance.web_server (remote-exec):   Host: 54.123.45.67
      aws_instance.web_server (remote-exec):   User: ec2-user
      aws_instance.web_server (remote-exec):   Private key: true
      aws_instance.web_server (remote-exec): Connected!
      aws_instance.web_server (remote-exec): Loaded plugins: extras_suggestions, langpacks, priorities, update-motd
      aws_instance.web_server (remote-exec): No packages marked for update
      aws_instance.web_server (remote-exec): Resolving Dependencies
      aws_instance.web_server (remote-exec): --> Running transaction check
      aws_instance.web_server (remote-exec): ---> Package nginx.x86_64 1:1.20.0-1.amzn2 will be installed
      aws_instance.web_server (remote-exec): --> Finished Dependency Resolution
      aws_instance.web_server (remote-exec): Installed:
      aws_instance.web_server (remote-exec):   nginx.x86_64 1:1.20.0-1.amzn2
      aws_instance.web_server (remote-exec): Complete!
      aws_instance.web_server (remote-exec): Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
      
      Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
      
      Outputs:
      
      web_server_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 và provisioner đã chạy thành công để cài đặt Nginx).

    • Truy cập public IP của EC2 (VD: http://54.123.45.67) trên trình duyệt, bạn sẽ thấy:
      <h1>Welcome to Nginx - Deployed by Terraform!</h1>
    • Kiểm tra trên AWS Console (EC2 Dashboard):
    • Một instance với tag Name: WebServer, 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:
      terraform destroy

      Khi được hỏi “Do you really want to destroy all resources?”, gõ yes và nhấn Enter.

  • 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.web_server will be destroyed
      - resource "aws_instance" "web_server" {
       - ami                          = "ami-0c55b159cbfafe1f0" -> null
       - instance_type                = "t2.micro" -> null
       - id                           = "i-0123456789abcdef0" -> null
      }
      
      # aws_security_group.web_sg will be destroyed
      - resource "aws_security_group" "web_sg" {
       - name_prefix = "web-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.web_server: Destroying... [id=i-0123456789abcdef0]
      aws_instance.web_server: Still destroying... [10s elapsed]
      aws_instance.web_server: Destruction complete after 15s
      aws_security_group.web_sg: Destroying... [id=sg-0123456789abcdef0]
      aws_security_group.web_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).

    • Kiểm tra lại trên AWS Console, instance WebServer không còn tồn tại.

Kết Quả Đạt Được

  • Bạn đã học cách sử dụng Terraform provisioners để tự động hóa tác vụ sau khi tạo tài nguyên, cụ thể là cài đặt và cấu hình Nginx trên EC2.
  • Bạn đã triển khai một EC2, tự động cài đặt web server, và truy cập public IP để kiểm tra kết quả.
  • Bạn đã xóa tài nguyên để dọn dẹp, tránh phát sinh chi phí không cần thiết.

Lưu Ý Quan Trọng

  • Hạn chế của provisioners: Terraform khuyến nghị sử dụng provisioners như giải pháp cuối cùng, vì chúng có thể làm mã phức tạp và khó bảo trì. Nên ưu tiên sử dụng user_data hoặc công cụ quản lý cấu hình như Ansible/Chef nếu có thể.
  • Chi phí AWS: Instance t2.micro trong bài này nằm trong Free Tier, nhưng nếu bạn dùng loại instance khác, có thể phát sinh chi phí. Luôn chạy terraform destroy sau khi thử nghiệm.
  • Bảo mật: Security Group trong bài cho phép SSH (port 22) và HTTP (port 80) từ 0.0.0.0/0. Trong môi trường production, hãy giới hạn CIDR block hoặc sử dụng VPN.
  • Tài liệu tham khảo: Xem thêm về Terraform provisioners trong tài liệu chính thức (Terraform Provisioners).
Điều hướng chuỗi bài viết<< Bài 8. Terraform State: Quản Lý Trạng Thái Hạ Tầng Với S3 Và DynamoDB
>> Bài 10. Terraform CI/CD: Tự Động Triển Khai Hạ Tầng Với GitHub Actions
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