Bài 12: Terraform Module: Mô-đun Hóa Cấu Hình


Danh sách bài viết trong series Terraform Associate (003)

Terraform Module Là Gì?

eeef9137-d100-42bc-837f-d05c3af0a6bd

Terraform Module là một tập hợp các file Terraform (.tf hoặc .tfvars) được đóng gói thành một đơn vị tái sử dụng, cho phép bạn tổ chức và tái sử dụng mã cấu hình. Một module có thể bao gồm các resource, variable, output, và thậm chí các module con (nested modules). Module giúp bạn mô-đun hóa hạ tầng, giảm trùng lặp mã, và quản lý cấu hình phức tạp một cách hiệu quả. Hiểu và sử dụng module là kỹ năng quan trọng được kiểm tra trong kỳ thi Terraform Associate (003), liên quan đến mục tiêu 7 (Read, Generate, and Modify Configuration).

Vai Trò Của Module Trong Quản Lý Hạ Tầng

Module đóng vai trò quan trọng trong quản lý hạ tầng:

  • Tái sử dụng mã: Dùng lại cấu hình (VD: EC2 instance) cho nhiều môi trường hoặc dự án.
  • Tổ chức mã: Chia nhỏ mã thành các module (VD: module cho network, module cho compute) để dễ quản lý.
  • Chuẩn hóa hạ tầng: Đảm bảo tài nguyên được triển khai nhất quán giữa các nhóm.
  • Hỗ trợ hợp tác: Các nhóm có thể chia sẻ module qua Terraform Registry hoặc Git.
  • Tăng tốc triển khai: Giảm thời gian viết mã bằng cách sử dụng module có sẵn.

Cấu Trúc Và Khai Báo Module

Cấu Trúc Thư Mục Của Module

Một module thường được tổ chức trong một thư mục riêng:

modules/
  └── ec2-instance/
      ├── main.tf
      ├── variables.tf
      ├── outputs.tf
  • main.tf: Chứa khai báo tài nguyên (resources).
  • variables.tf: Khai báo biến đầu vào.
  • outputs.tf: Khai báo giá trị đầu ra.

Khai Báo Module Trong File Terraform

Module được gọi trong file chính bằng block module:

module "<NAME>" {
  source = "<PATH>"
  [VARIABLES]
}
  • <NAME>: Tên module, duy nhất trong dự án.
  • source: Đường dẫn đến module (cục bộ, Git, hoặc Terraform Registry).
  • [VARIABLES]: Biến đầu vào truyền vào module.

Sử Dụng Module Từ Nguồn Cục Bộ

  • Thư mục module modules/ec2-instance/main.tf:
    resource "aws_instance" "instance" {
    ami           = var.ami
    instance_type = var.instance_type
    tags = {
      Name = "${var.environment}-instance"
    }
    }
  • Thư mục module modules/ec2-instance/variables.tf:

    variable "ami" {
    type        = string
    description = "AMI ID for the EC2 instance"
    }
    
    variable "instance_type" {
    type        = string
    description = "EC2 instance type"
    default     = "t2.micro"
    }
    
    variable "environment" {
    type        = string
    description = "Environment name (e.g., dev, prod)"
    }
  • Thư mục module modules/ec2-instance/outputs.tf:

    output "instance_id" {
    value       = aws_instance.instance.id
    description = "The ID of the EC2 instance"
    }
    
    output "instance_public_ip" {
    value       = aws_instance.instance.public_ip
    description = "The public IP of the EC2 instance"
    }
  • File chính main.tf:

    provider "aws" {
    region     = "us-east-1"
    access_key = "YOUR_ACCESS_KEY"
    secret_key = "YOUR_SECRET_KEY"
    }
    
    module "ec2_dev" {
    source        = "./modules/ec2-instance"
    ami           = "ami-0c55b159cbfafe1f0"
    instance_type = "t2.micro"
    environment   = "dev"
    }
    
    output "dev_instance_id" {
    value = module.ec2_dev.instance_id
    }
    
    output "dev_instance_public_ip" {
    value = module.ec2_dev.instance_public_ip
    }
  • Quy trình:
    1. terraform init: Output:
      Initializing provider plugins...
      Finding hashicorp/aws versions matching "~> 5.0"...
      Installing hashicorp/aws v5.17.0...
      Installed hashicorp/aws v5.17.0 (signed by HashiCorp)
      Terraform has been successfully initialized!
    2. terraform apply -auto-approve: Output:
      module.ec2_dev.aws_instance.instance: Creating...
      module.ec2_dev.aws_instance.instance: Creation complete after 45s [id=i-0abcdef123456789]
      Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
      Outputs:
      dev_instance_id = "i-0abcdef123456789"
      dev_instance_public_ip = "54.123.45.67"
Sử Dụng Module Từ Registry
  • Ví dụ: Sử dụng module chính thức từ Terraform Registry (VD: module aws-vpc).
  • File main.tf:

    provider "aws" {
    region     = "us-east-1"
    access_key = "YOUR_ACCESS_KEY"
    secret_key = "YOUR_SECRET_KEY"
    }
    
    module "vpc" {
    source  = "terraform-aws-modules/vpc/aws"
    version = "5.8.1"
    
    name = "my-vpc"
    cidr = "10.0.0.0/16"
    
    azs             = ["us-east-1a", "us-east-1b"]
    private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
    public_subnets  = ["10.0.101.0/24", "10.0.102.0/24"]
    
    enable_nat_gateway = true
    single_nat_gateway = true
    }
    
    output "vpc_id" {
    value = module.vpc.vpc_id
    }
  • Quy trình:
    1. terraform init: Output:
      Initializing modules...
      vpc in .terraform/modules/vpc/terraform-aws-modules-vpc-aws-5.8.1
      Initializing provider plugins...
      Finding hashicorp/aws versions matching "~> 5.0"...
      Installing hashicorp/aws v5.17.0...
      Installed hashicorp/aws v5.17.0 (signed by HashiCorp)
      Terraform has been successfully initialized!
    2. terraform apply -auto-approve: Output (tóm tắt):
      module.vpc.aws_vpc.this[0]: Creating...
      module.vpc.aws_vpc.this[0]: Creation complete after 10s [id=vpc-12345678]
      module.vpc.aws_subnet.public[0]: Creating...
      module.vpc.aws_subnet.public[1]: Creating...
      module.vpc.aws_subnet.public[0]: Creation complete after 5s [id=subnet-12345678]
      module.vpc.aws_subnet.public[1]: Creation complete after 5s [id=subnet-87654321]
      Apply complete! Resources: 10 added, 0 changed, 0 destroyed.
      Outputs:
      vpc_id = "vpc-12345678"

Truyền Biến Vào Module

Module hỗ trợ truyền biến để tùy chỉnh tài nguyên:

  • Module modules/ec2-instance/variables.tf:

    variable "ami" {
    type = string
    }
    
    variable "instance_type" {
    type = string
    }
    
    variable "environment" {
    type = string
    }
  • File main.tf (truyền biến vào module):

    module "ec2_dev" {
    source        = "./modules/ec2-instance"
    ami           = "ami-0c55b159cbfafe1f0"
    instance_type = "t2.micro"
    environment   = "dev"
    }
    
    module "ec2_prod" {
    source        = "./modules/ec2-instance"
    ami           = "ami-0c55b159cbfafe1f0"
    instance_type = "t2.large"
    environment   = "prod"
    }
  • Ý nghĩa: Module ec2-instance được tái sử dụng với cấu hình khác nhau cho devprod.

Ví Dụ Thực Tế: Sử Dụng Module Để Tái Sử Dụng Cấu Hình

  • Module modules/web-app/main.tf:

    resource "aws_s3_bucket" "app_bucket" {
    bucket = "web-app-${var.environment}-20230518"
    tags = {
      Name = "AppBucket-${var.environment}"
    }
    }
    
    resource "aws_instance" "app_server" {
    ami           = var.ami
    instance_type = var.instance_type
    tags = {
      Name = "AppServer-${var.environment}"
    }
    
    depends_on = [aws_s3_bucket.app_bucket]
    }
  • Module modules/web-app/variables.tf:

    variable "ami" {
    type        = string
    description = "AMI ID for the EC2 instance"
    }
    
    variable "instance_type" {
    type        = string
    description = "EC2 instance type"
    }
    
    variable "environment" {
    type        = string
    description = "Environment name"
    }
  • Module modules/web-app/outputs.tf:

    output "bucket_name" {
    value = aws_s3_bucket.app_bucket.bucket
    }
    
    output "instance_id" {
    value = aws_instance.app_server.id
    }
    
    output "instance_public_ip" {
    value = aws_instance.app_server.public_ip
    }
  • File chính main.tf (kết hợp workspace và module):

    terraform {
    backend "s3" {
      bucket         = "my-terraform-state"
      key            = "state/${terraform.workspace}/terraform.tfstate"
      region         = "us-east-1"
      dynamodb_table = "terraform-locks"
      encrypt        = true
    }
    }
    
    provider "aws" {
    region     = "us-east-1"
    access_key = "YOUR_ACCESS_KEY"
    secret_key = "YOUR_SECRET_KEY"
    }
    
    module "web_app" {
    source        = "./modules/web-app"
    ami           = "ami-0c55b159cbfafe1f0"
    instance_type = terraform.workspace == "prod" ? "t2.large" : "t2.micro"
    environment   = terraform.workspace
    }
    
    output "bucket_name" {
    value = module.web_app.bucket_name
    }
    
    output "instance_id" {
    value = module.web_app.instance_id
    }
    
    output "instance_public_ip" {
    value = module.web_app.instance_public_ip
    }
  • Quy trình:
    1. Khởi tạo backend:
      terraform init

      Output:

      Initializing the backend...
      Successfully configured the backend "s3"! Terraform will automatically
      use this backend unless the backend configuration changes.
      Initializing provider plugins...
      Finding hashicorp/aws versions matching "~> 5.0"...
      Installing hashicorp/aws v5.17.0...
      Installed hashicorp/aws v5.17.0 (signed by HashiCorp)
      Terraform has been successfully initialized!
    2. Tạo workspace dev:
      terraform workspace new dev

      Output:

      Created and switched to workspace "dev"!
    3. Áp dụng cho dev:
      terraform apply -auto-approve

      Output:

      module.web_app.aws_s3_bucket.app_bucket: Creating...
      module.web_app.aws_s3_bucket.app_bucket: Creation complete after 5s [id=web-app-dev-20230518]
      module.web_app.aws_instance.app_server: Creating...
      module.web_app.aws_instance.app_server: Creation complete after 45s [id=i-0abcdef123456789]
      Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
      Outputs:
      bucket_name = "web-app-dev-20230518"
      instance_id = "i-0abcdef123456789"
      instance_public_ip = "54.123.45.67"
    4. Tạo workspace prod:
      terraform workspace new prod

      Output:

      Created and switched to workspace "prod"!
    5. Áp dụng cho prod:
      terraform apply -auto-approve

      Output:

      module.web_app.aws_s3_bucket.app_bucket: Creating...
      module.web_app.aws_s3_bucket.app_bucket: Creation complete after 5s [id=web-app-prod-20230518]
      module.web_app.aws_instance.app_server: Creating...
      module.web_app.aws_instance.app_server: Creation complete after 45s [id=i-0prod123456789]
      Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
      Outputs:
      bucket_name = "web-app-prod-20230518"
      instance_id = "i-0prod123456789"
      instance_public_ip = "54.123.45.68"

Lưu Ý Quan Trọng Khi Sử Dụng Module

  • Tên module duy nhất: Đảm bảo tên module không trùng lặp trong cùng file .tf.
  • Phiên bản module: Khi dùng module từ Registry, chỉ định version để tránh cập nhật không mong muốn (VD: version = "5.8.1").
  • Truyền biến đầy đủ: Module yêu cầu biến bắt buộc phải được truyền giá trị, nếu không sẽ báo lỗi.
  • Tổ chức thư mục: Đặt module trong thư mục modules/ để dễ quản lý.
  • Kiểm tra tài liệu: Với module từ Registry, đọc tài liệu để hiểu biến đầu vào và đầu ra.

Liên Hệ Với Chứng Chỉ Terraform Associate (003)

Kỳ thi Terraform Associate (003) kiểm tra khả năng sử dụng module. Bạn cần nắm:

  • Câu hỏi mẫu:
    • “Module trong Terraform được khai báo như thế nào?”
      Đáp án: Sử dụng block module với source và các biến đầu vào.
    • “Lợi ích chính của việc sử dụng module là gì?”
      Đáp án: Tái sử dụng mã, chuẩn hóa hạ tầng, và tổ chức mã hiệu quả.
    • “Lệnh nào tải module từ Terraform Registry?”
      Đáp án: terraform init.
  • Thực hành: Kỳ thi có thể yêu cầu nhận diện cấu hình module hoặc dự đoán output khi sử dụng module.

Kết Luận

Terraform Module là công cụ mạnh mẽ để mô-đun hóa cấu hình, giúp tái sử dụng mã và quản lý hạ tầng hiệu quả. Hiểu cách tạo, sử dụng module, và thực hành với ví dụ thực tế sẽ giúp bạn tự tin thi đỗ Terraform Associate (003). Ở bài tiếp theo, chúng ta sẽ tìm hiểu cách sử dụng Terraform Data Sources để truy vấn thông tin hạ tầng.

Điều hướng chuỗi bài viết<< Bài 11: Terraform Workspace Quản Lý Nhiều Môi Trường
>> Bài 13: Terraform Data Sources Truy Vấn Thông Tin Hạ Tầng

Bài viết khác

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

Có thể bạn quan tâm