Skip to content

Terraform Tutorial

Minh Nguyen edited this page Nov 27, 2025 · 1 revision

Phần 1: Variables (Input của module)

hcl variable "environment" { type = string # Kiểu dữ liệu: text }

 variable "vpc_cidr" {
   type    = string
   default = "10.0.0.0/16"  # Dải IP cho VPC (65,536 IPs)
 }

 variable "availability_zones" {
   type    = list(string)   # Kiểu: danh sách text
   default = ["ap-southeast-1a", "ap-southeast-1b"]  # 2 datacenter ở Singapore
 }

Giải thích CIDR: • 10.0.0.0/16 = 10.0.0.0 → 10.0.255.255 (65,536 IPs) • /16 càng nhỏ → càng nhiều IP

──────────────────────────────────────────

Phần 2: VPC + Internet Gateway

hcl # Tạo VPC resource "aws_vpc" "main" { cidr_block = var.vpc_cidr # Dải IP enable_dns_hostnames = true # Cho phép DNS names enable_dns_support = true # Bật DNS

   tags = {
     Name = "mapvibe-vpc-${var.environment}"     # Tên hiển thị trên Console
   }
 }

 # Internet Gateway - "Cổng ra Internet"
 resource "aws_internet_gateway" "main" {
   vpc_id = aws_vpc.main.id    # Gắn vào VPC ở trên
   # aws_vpc.main.id = Reference đến resource đã tạo
 }

Reference giữa resources:

 aws_vpc.main.id
    ↑      ↑    ↑
  loại   tên   thuộc tính

──────────────────────────────────────────

Phần 3: Subnets (count = tạo nhiều cái)

hcl resource "aws_subnet" "public" { count = length(var.availability_zones) # = 2 → Tạo 2 subnets

   vpc_id            = aws_vpc.main.id
   cidr_block        = cidrsubnet(var.vpc_cidr, 8, count.index)
   #                   ↑ Hàm tự tính CIDR con
   #                   10.0.0.0/16, 8, 0 → 10.0.0.0/24
   #                   10.0.0.0/16, 8, 1 → 10.0.1.0/24

   availability_zone = var.availability_zones[count.index]
   #                   count.index = 0, 1, 2...
 }

count pattern: • count = 2 → Terraform tạo 2 resources giống nhau • count.index = 0, 1, 2... (index của mỗi resource) • Truy cập: aws_subnet.public[0], aws_subnet.public[1]

──────────────────────────────────────────

Phần 4: NAT Gateway

hcl # Elastic IP (IP tĩnh) resource "aws_eip" "nat" { domain = "vpc" depends_on = [aws_internet_gateway.main] # Chờ IGW tạo xong }

 # NAT Gateway
 resource "aws_nat_gateway" "main" {
   allocation_id = aws_eip.nat.id           # Gắn IP tĩnh
   subnet_id     = aws_subnet.public[0].id  # Đặt trong public subnet
 }

depends_on là gì? • Bắt Terraform chờ resource khác tạo xong trước • Thường Terraform tự biết, nhưng đôi khi cần chỉ rõ

──────────────────────────────────────────

Phần 5: Route Tables

hcl # Public Route: Internet → qua Internet Gateway resource "aws_route_table" "public" { route { cidr_block = "0.0.0.0/0" # Mọi traffic gateway_id = aws_internet_gateway.main.id # → đi qua IGW } }

 # Private Route: Internet → qua NAT Gateway
 resource "aws_route_table" "private" {
   route {
     cidr_block     = "0.0.0.0/0"          # Mọi traffic
     nat_gateway_id = aws_nat_gateway.main.id   # → đi qua NAT
   }
 }

Tại sao Private cần NAT? • Lambda trong Private Subnet muốn gọi API bên ngoài • Không có NAT → Lambda không ra được Internet • NAT cho phép ra ngoài, nhưng bên ngoài không vào được

──────────────────────────────────────────

Phần 6: Outputs

hcl output "vpc_id" { value = aws_vpc.main.id # Trả về ID của VPC }

 output "private_subnet_ids" {
   value = aws_subnet.private[*].id   # [*] = lấy tất cả
   # → ["subnet-123", "subnet-456"]
 }

[] là gì?* (Splat expression) • Lấy thuộc tính của TẤT CẢ resources trong list • aws_subnet.private[*].id = IDs của mọi private subnets

──────────────────────────────────────────

  1. Các "bẫy" thường gặp

Bẫy │ Hậu quả │ Cách tránh
------------------------+-----------------------------------------+---------------------------------- Xóa terraform.tfstate │ Terraform quên hết đã tạo gì │ Backup state, dùng remote backend Sửa resource name │ Terraform xóa cũ, tạo mới │ Dùng terraform state mv Quên depends_on │ Resource tạo trước khi dependency ready │ Thêm depends_on nếu cần NAT Gateway tốn tiền │ ~$32/tháng │ Tắt khi dev không dùng

──────────────────────────────────────────

  1. Key Takeaway
**VPC = Mạng riêng, chia thành Public (ra Internet trực tiếp) và Private (ra qua NAT). RDS và Lambda nằm trong Private để bảo mật.**

Clone this wiki locally