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 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:
- Đả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 Module Và Viết Mã Terraform
-
Hành động:
- 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/
-
Tạo file
main.tf
trong thư mụcmodules/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" } }
-
Tạo file
variables.tf
trong thư mụcmodules/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" }
-
Tạo file
outputs.tf
trong thư mụcmodules/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 }
- Tạo cấu trúc thư mục cho dự án:
- 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).
- Sau khi tạo các file, cấu trúc thư mục của module sẽ là:
Bước 3: Sử Dụng Module Trong Dự Án Chính
-
Hành động:
-
Tạo file
main.tf
trong thư mục gốcterraform-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 modulevpc-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 filemain.tf
ở thư mục gốc và các file trong thư mục module).
- Cấu trúc thư mục hoàn chỉnh sẽ là:
Bước 4: Khởi Tạo Và Áp Dụng Mã Terraform
- Hành động:
- Trong thư mục
terraform-modules-example
, chạy lệnh để khởi tạo dự án:terraform init
- Xem trước các thay đổi:
terraform plan
- Á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.
- 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).
-
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
, CIDR10.1.0.0/16
. - EC2 Dashboard: Một instance mới với tag
Name: dev-EC2
, trạng tháiRunning
.
-
Bước 5: Xóa Tài Nguyên Để Dọn Dẹp
- Hành động:
- 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.
- Chạy lệnh để xóa tài nguyên:
-
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à instancedev-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 blockmodule
mới trongmain.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ạyterraform 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).