
Terraform Modules: Tái sử dụng infrastructure code hiệu quả
Tiếp tục series Terraform, bài này hướng dẫn về Modules – cách tổ chức và tái sử dụng Terraform code hiệu quả cho production.
Nội dung chính
Terraform Modules là gì?
Module là container cho nhiều resources được sử dụng cùng nhau. Thay vì copy-paste code, bạn đóng gói thành module và tái sử dụng.
Cấu trúc Module
modules/
└── vpc/
├── main.tf # Resources
├── variables.tf # Input variables
├── outputs.tf # Output values
└── README.md # DocumentationTạo Module VPC
modules/vpc/variables.tf
variable "name" {
description = "VPC name prefix"
type = string
}
variable "cidr" {
description = "VPC CIDR block"
type = string
default = "10.0.0.0/16"
}
variable "azs" {
description = "Availability zones"
type = list(string)
}
variable "enable_nat" {
description = "Enable NAT gateway"
type = bool
default = true
}modules/vpc/main.tf
resource "aws_vpc" "this" {
cidr_block = var.cidr
enable_dns_hostnames = true
tags = { Name = "${var.name}-vpc" }
}
resource "aws_subnet" "public" {
count = length(var.azs)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.cidr, 8, count.index)
availability_zone = var.azs[count.index]
tags = { Name = "${var.name}-public-${count.index + 1}" }
}
resource "aws_subnet" "private" {
count = length(var.azs)
vpc_id = aws_vpc.this.id
cidr_block = cidrsubnet(var.cidr, 8, count.index + 10)
availability_zone = var.azs[count.index]
tags = { Name = "${var.name}-private-${count.index + 1}" }
}
resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.this.id
}
resource "aws_nat_gateway" "this" {
count = var.enable_nat ? 1 : 0
allocation_id = aws_eip.nat[0].id
subnet_id = aws_subnet.public[0].id
}
resource "aws_eip" "nat" {
count = var.enable_nat ? 1 : 0
domain = "vpc"
}modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.this.id
}
output "public_subnet_ids" {
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}Sử dụng Module
# main.tf
module "vpc_prod" {
source = "./modules/vpc"
name = "prod"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c"]
enable_nat = true
}
module "vpc_staging" {
source = "./modules/vpc"
name = "staging"
cidr = "10.1.0.0/16"
azs = ["ap-northeast-1a"]
enable_nat = false # Tiết kiệm chi phí
}
# Sử dụng outputs
resource "aws_instance" "web" {
subnet_id = module.vpc_prod.public_subnet_ids[0]
# ...
}Module từ Terraform Registry
# Sử dụng module public
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["ap-northeast-1a", "ap-northeast-1c"]
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
}Best Practices
- Version modules – Dùng git tags hoặc semantic versioning
- Documentation – README.md với examples
- Validation – Dùng variable validation
- Testing – Terratest cho automated testing
# Variable validation
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}Module Composition
# Kết hợp nhiều modules
module "vpc" {
source = "./modules/vpc"
# ...
}
module "eks" {
source = "./modules/eks"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
}
module "rds" {
source = "./modules/rds"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnet_ids
}Fullstack Station Tips
Modules là cách organize Terraform code cho teams:
- Bắt đầu với modules nhỏ, đơn giản
- Dùng modules từ Registry khi phù hợp – đã được test kỹ
- Pin versions để tránh breaking changes
- Document inputs/outputs rõ ràng
