Bài 6. Sử Dụng Terraform Modules: Tái Sử Dụng Mã Để Quản Lý Hạ Tầng Hiệu Quả

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

Sử dụng Terraform modules là cách hiệu quả để tái sử dụng mã và quản lý hạ tầng một cách có tổ chức, đặc biệt trong các dự án lớn. 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), và tự động hóa triển khai với Load Balancer và Auto Scaling Group (bài 5).

Tuy nhiên, nếu bạn cần triển khai cùng một hạ tầng (VD: VPC và EC2) ở nhiều môi trường (dev, staging, production), việc sao chép mã sẽ dẫn đến lặp lại và khó bảo trì. Terraform modules giúp bạn đóng gói mã thành các khối tái sử dụng, giảm thiểu lỗi và tăng tính 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 modules, tạo một module cho VPC và EC2, sau đó áp dụng nó trong một dự án.

Sử Dụng Terraform Modules: 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 Module Và Viết Mã Terraform

  • Hành động:

    1. Tạo cấu trúc thư mục cho dự án:
      mkdir terraform-modules-example
      cd terraform-modules-example
      mkdir -p modules/vpc-ec2

      Cấu trúc thư mục sẽ như sau:

      terraform-modules-example/
      └── modules/
       └── vpc-ec2/
    2. Tạo file main.tf trong thư mục modules/vpc-ec2 để định nghĩa module:

      touch modules/vpc-ec2/main.tf

      Mở file modules/vpc-ec2/main.tf trong VS Code và dán nội dung sau:

      # Tạo VPC
      resource "aws_vpc" "module_vpc" {
      cidr_block = var.vpc_cidr
      tags = {
       Name = "${var.environment}-VPC"
      }
      }
      
      # Tạo Subnet
      resource "aws_subnet" "module_subnet" {
      vpc_id     = aws_vpc.module_vpc.id
      cidr_block = var.subnet_cidr
      tags = {
       Name = "${var.environment}-Subnet"
      }
      }
      
      # Tạo Internet Gateway
      resource "aws_internet_gateway" "module_igw" {
      vpc_id = aws_vpc.module_vpc.id
      tags = {
       Name = "${var.environment}-IGW"
      }
      }
      
      # Tạo Route Table
      resource "aws_route_table" "module_route_table" {
      vpc_id = aws_vpc.module_vpc.id
      
      route {
       cidr_block = "0.0.0.0/0"
       gateway_id = aws_internet_gateway.module_igw.id
      }
      
      tags = {
       Name = "${var.environment}-RouteTable"
      }
      }
      
      # Gắn Route Table với Subnet
      resource "aws_route_table_association" "module_route_table_association" {
      subnet_id      = aws_subnet.module_subnet.id
      route_table_id = aws_route_table.module_route_table.id
      }
      
      # Tạo Security Group cho EC2
      resource "aws_security_group" "module_sg" {
      vpc_id = aws_vpc.module_vpc.id
      
      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 = "${var.environment}-SG"
      }
      }
      
      # Tạo EC2
      resource "aws_instance" "module_ec2" {
      ami           = var.ami
      instance_type = var.instance_type
      subnet_id     = aws_subnet.module_subnet.id
      vpc_security_group_ids = [aws_security_group.module_sg.id]
      associate_public_ip_address = true
      
      tags = {
       Name = "${var.environment}-EC2"
      }
      }
    3. Tạo file variables.tf trong thư mục modules/vpc-ec2 để khai báo variables:

      touch modules/vpc-ec2/variables.tf

      Mở file modules/vpc-ec2/variables.tf và dán nội dung sau:

      variable "vpc_cidr" {
      description = "CIDR block for the VPC"
      type        = string
      default     = "10.0.0.0/16"
      }
      
      variable "subnet_cidr" {
      description = "CIDR block for the subnet"
      type        = string
      default     = "10.0.1.0/24"
      }
      
      variable "environment" {
      description = "Environment name (e.g., dev, staging, prod)"
      type        = string
      }
      
      variable "ami" {
      description = "AMI ID for the EC2 instance"
      type        = string
      default     = "ami-0c55b159cbfafe1f0" # Amazon Linux 2 in us-east-1
      }
      
      variable "instance_type" {
      description = "EC2 instance type"
      type        = string
      default     = "t2.micro"
      }
    4. Tạo file outputs.tf trong thư mục modules/vpc-ec2 để khai báo outputs:

      touch modules/vpc-ec2/outputs.tf

      Mở file modules/vpc-ec2/outputs.tf và dán nội dung sau:

      output "vpc_id" {
      description = "ID of the VPC"
      value       = aws_vpc.module_vpc.id
      }
      
      output "subnet_id" {
      description = "ID of the subnet"
      value       = aws_subnet.module_subnet.id
      }
      
      output "ec2_public_ip" {
      description = "Public IP of the EC2 instance"
      value       = aws_instance.module_ec2.public_ip
      }
  • Kết quả thực tế:
    • Sau khi tạo các file, cấu trúc thư mục của module sẽ là:
      terraform-modules-example/
      └── modules/
       └── vpc-ec2/
           ├── main.tf
           ├── variables.tf
           └── outputs.tf

      (Kiểm tra bằng lệnh ls -R, bạn sẽ thấy các file trong thư mục module).

Bước 3: Sử Dụng Module Trong Dự Án Chính

  • Hành động:

    1. Tạo file main.tf trong thư mục gốc terraform-modules-example:

      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"
      }
      
      # Sử dụng module vpc-ec2 cho môi trường dev
      module "dev_vpc_ec2" {
      source = "./modules/vpc-ec2"
      
      environment    = "dev"
      vpc_cidr       = "10.1.0.0/16"
      subnet_cidr    = "10.1.1.0/24"
      ami            = "ami-0c55b159cbfafe1f0"
      instance_type  = "t2.micro"
      }
      
      # Output từ module
      output "dev_vpc_id" {
      description = "VPC ID for dev environment"
      value       = module.dev_vpc_ec2.vpc_id
      }
      
      output "dev_subnet_id" {
      description = "Subnet ID for dev environment"
      value       = module.dev_vpc_ec2.subnet_id
      }
      
      output "dev_ec2_public_ip" {
      description = "Public IP of the EC2 instance in dev environment"
      value       = module.dev_vpc_ec2.ec2_public_ip
      }

      Giải thích:

      • module "dev_vpc_ec2": Gọi module vpc-ec2 và truyền các giá trị cho variables (environment, vpc_cidr, subnet_cidr, v.v.).
      • output: Sử dụng outputs từ module để hiển thị thông tin về VPC, subnet, và EC2.
  • Kết quả thực tế:
    • Cấu trúc thư mục hoàn chỉnh sẽ là:
      terraform-modules-example/
      ├── main.tf
      └── modules/
       └── vpc-ec2/
           ├── main.tf
           ├── variables.tf
           └── outputs.tf

      (Kiểm tra bằng lệnh ls -R, bạn sẽ thấy file main.tf ở thư mục gốc và các file trong thư mục module).

Bước 4: Khởi Tạo Và Áp Dụng Mã Terraform

  • Hành động:
    1. Trong thư mục terraform-modules-example, chạy lệnh để khởi tạo dự án:
      terraform init
    2. Xem trước các thay đổi:
      terraform plan
    3. Áp dụng mã để tạo hạ tầng:
      terraform apply

      Khi được hỏi “Do you want to perform these actions?”, gõ yes và nhấn Enter.

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

    • Sau khi chạy terraform plan, terminal sẽ hiển thị kế hoạch thực thi (được rút gọn để dễ đọc):

      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:
      
      # module.dev_vpc_ec2.aws_instance.module_ec2 will be created
      + resource "aws_instance" "module_ec2" {
       + ami                          = "ami-0c55b159cbfafe1f0"
       + instance_type                = "t2.micro"
       + tags                         = {
           + "Name" = "dev-EC2"
         }
      }
      
      # module.dev_vpc_ec2.aws_vpc.module_vpc will be created
      + resource "aws_vpc" "module_vpc" {
       + cidr_block = "10.1.0.0/16"
       + tags       = {
           + "Name" = "dev-VPC"
         }
      }
      
      # module.dev_vpc_ec2.aws_subnet.module_subnet will be created
      + resource "aws_subnet" "module_subnet" {
       + cidr_block = "10.1.1.0/24"
       + tags       = {
           + "Name" = "dev-Subnet"
         }
      }
      
      Plan: 6 to add, 0 to change, 0 to destroy.

      (Kế hoạch cho thấy Terraform sẽ tạo 6 tài nguyên: VPC, subnet, internet gateway, route table, route table association, security group, và EC2).

    • Sau khi chạy terraform apply và gõ yes, 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:
      
      # (Tương tự như terraform plan ở trên)
      
      Plan: 6 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
      
      module.dev_vpc_ec2.aws_vpc.module_vpc: Creating...
      module.dev_vpc_ec2.aws_vpc.module_vpc: Creation complete after 2s [id=vpc-0abcdef1234567890]
      module.dev_vpc_ec2.aws_subnet.module_subnet: Creating...
      module.dev_vpc_ec2.aws_internet_gateway.module_igw: Creating...
      module.dev_vpc_ec2.aws_security_group.module_sg: Creating...
      module.dev_vpc_ec2.aws_subnet.module_subnet: Creation complete after 1s [id=subnet-0abcdef1234567890]
      module.dev_vpc_ec2.aws_internet_gateway.module_igw: Creation complete after 1s [id=igw-0abcdef1234567890]
      module.dev_vpc_ec2.aws_security_group.module_sg: Creation complete after 2s [id=sg-0abcdef1234567890]
      module.dev_vpc_ec2.aws_route_table.module_route_table: Creating...
      module.dev_vpc_ec2.aws_route_table.module_route_table: Creation complete after 1s [id=rtb-0abcdef1234567890]
      module.dev_vpc_ec2.aws_route_table_association.module_route_table_association: Creating...
      module.dev_vpc_ec2.aws_route_table_association.module_route_table_association: Creation complete after 1s [id=rtbassoc-0abcdef1234567890]
      module.dev_vpc_ec2.aws_instance.module_ec2: Creating...
      module.dev_vpc_ec2.aws_instance.module_ec2: Still creating... [10s elapsed]
      module.dev_vpc_ec2.aws_instance.module_ec2: Creation complete after 15s [id=i-0abcdef1234567890]
      
      Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
      
      Outputs:
      
      dev_vpc_id = "vpc-0abcdef1234567890"
      dev_subnet_id = "subnet-0abcdef1234567890"
      dev_ec2_public_ip = "54.123.45.67"

      (Dòng “Apply complete! Resources: 6 added, 0 changed, 0 destroyed” xác nhận hạ tầng đã được tạo. Outputs hiển thị ID của VPC, subnet, và public IP của EC2).

    • Kiểm tra trên AWS Console:
    • VPC Dashboard: Một VPC mới với tag Name: dev-VPC, CIDR 10.1.0.0/16.
    • EC2 Dashboard: Một instance mới với tag Name: dev-EC2, trạng thái Running.

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

  • Hành động:
    1. Chạy lệnh để 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 và gõ yes, 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:
      
      # module.dev_vpc_ec2.aws_instance.module_ec2 will be destroyed
      - resource "aws_instance" "module_ec2" {
       - ami                          = "ami-0c55b159cbfafe1f0" -> null
       - instance_type                = "t2.micro" -> null
       - id                           = "i-0abcdef1234567890" -> null
      }
      
      # module.dev_vpc_ec2.aws_vpc.module_vpc will be destroyed
      - resource "aws_vpc" "module_vpc" {
       - cidr_block = "10.1.0.0/16" -> null
       - id         = "vpc-0abcdef1234567890" -> null
      }
      
      Plan: 0 to add, 0 to change, 6 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
      
      module.dev_vpc_ec2.aws_instance.module_ec2: Destroying... [id=i-0abcdef1234567890]
      module.dev_vpc_ec2.aws_instance.module_ec2: Still destroying... [10s elapsed]
      module.dev_vpc_ec2.aws_instance.module_ec2: Destruction complete after 15s
      module.dev_vpc_ec2.aws_route_table_association.module_route_table_association: Destroying... [id=rtbassoc-0abcdef1234567890]
      module.dev_vpc_ec2.aws_route_table_association.module_route_table_association: Destruction complete after 1s
      module.dev_vpc_ec2.aws_route_table.module_route_table: Destroying... [id=rtb-0abcdef1234567890]
      module.dev_vpc_ec2.aws_route_table.module_route_table: Destruction complete after 1s
      module.dev_vpc_ec2.aws_security_group.module_sg: Destroying... [id=sg-0abcdef1234567890]
      module.dev_vpc_ec2.aws_security_group.module_sg: Destruction complete after 2s
      module.dev_vpc_ec2.aws_internet_gateway.module_igw: Destroying... [id=igw-0abcdef1234567890]
      module.dev_vpc_ec2.aws_internet_gateway.module_igw: Destruction complete after 1s
      module.dev_vpc_ec2.aws_subnet.module_subnet: Destroying... [id=subnet-0abcdef1234567890]
      module.dev_vpc_ec2.aws_subnet.module_subnet: Destruction complete after 1s
      module.dev_vpc_ec2.aws_vpc.module_vpc: Destroying... [id=vpc-0abcdef1234567890]
      module.dev_vpc_ec2.aws_vpc.module_vpc: Destruction complete after 2s
      
      Destroy complete! Resources: 6 destroyed.

      (Dòng “Destroy complete! Resources: 6 destroyed” xác nhận hạ tầng đã bị xóa).

    • Kiểm tra lại trên AWS Console, VPC dev-VPC và instance dev-EC2 không còn tồn tại.

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

  • Bạn đã học cách sử dụng Terraform modules để tái sử dụng mã, tạo một module cho VPC và EC2.
  • Bạn đã áp dụng module trong một dự án chính để triển khai hạ tầng cho môi trường dev.
  • Bạn đã kiểm tra và xác nhận hạ tầng hoạt động đúng trên AWS Console.
  • 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

  • Tái sử dụng module: Bạn có thể gọi module vpc-ec2 nhiều lần trong cùng một dự án với các giá trị khác nhau (VD: tạo thêm môi trường staging hoặc prod) bằng cách thêm block module mới trong main.tf.
  • Chi phí AWS: VPC và EC2 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 module cho phép SSH (port 22) 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 bastion host.
  • Tài liệu tham khảo: Xem thêm về Terraform modules trong tài liệu chính thức (Terraform Modules).
Điều hướng chuỗi bài viết<< Bài 5. Tự Động Hóa Triển Khai Với Terraform: Tạo Load Balancer Và Auto Scaling Group
>> Bài 7. Terraform Workspaces: Quản Lý Nhiều Môi Trường Hiệu Quả Trên AWS
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