Bài 8: Bài lab kết hợp Terraform Module + Workspace để thiết lập VPC Chuyên mục Devops 2025-05-15 3 Lượt xem 3 Lượt thích 0 Bình luận
💡 Mục tiêu bài Lab
-
Tạo VPC mới bằng Terraform
-
Chia 4 subnet: 2 public, 2 private
-
Tạo Internet Gateway cho public
-
Tạo NAT Gateway cho private subnet để có outbound Internet
-
Tạo các Route Table và liên kết phù hợp
-
Quản lý multi-environment qua Terraform Workspace (dev, stage, prod)
-
Sử dụng module để tái sử dụng cấu trúc
🧱 Cấu trúc thư mục
terraform-vpc-workspace/
├── envs/
│ ├── dev.tfvars
│ ├── stage.tfvars
│ └── prod.tfvars
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tf
├── modules/
│ └── vpc/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
🧩 1. File envs/dev.tfvars
project = "myproject"
environment = "dev"
vpc_cidr_block = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
private_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
region = "us-east-1"
Các file stage.tfvars và prod.tfvars tương tự, chỉ thay đổi CIDR nếu cần.
⚙️ 2. main.tf (gọi module)
terraform {
required_version = ">= 1.0"
}
provider "aws" {
region = var.region
}
module "vpc" {
source = "./modules/vpc"
project = var.project
environment = var.environment
vpc_cidr_block = var.vpc_cidr_block
public_subnets = var.public_subnets
private_subnets = var.private_subnets
}
🎛️ 3. variables.tf
variable "project" {}
variable "environment" {}
variable "vpc_cidr_block" {}
variable "public_subnets" {
type = list(string)
}
variable "private_subnets" {
type = list(string)
}
variable "region" {}
📤 4. outputs.tf
output "vpc_id" {
value = module.vpc.vpc_id
}
output "public_subnets" {
value = module.vpc.public_subnet_ids
}
output "private_subnets" {
value = module.vpc.private_subnet_ids
}
📦 5. Module modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr_block
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.project}-${var.environment}-vpc"
}
}
resource "aws_internet_gateway" "igw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project}-${var.environment}-igw"
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
map_public_ip_on_launch = true
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.project}-${var.environment}-public-${count.index + 1}"
}
}
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.private_subnets[count.index]
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = {
Name = "${var.project}-${var.environment}-private-${count.index + 1}"
}
}
resource "aws_eip" "nat" {
count = 1
vpc = true
depends_on = [aws_internet_gateway.igw]
}
resource "aws_nat_gateway" "nat" {
allocation_id = aws_eip.nat[0].id
subnet_id = aws_subnet.public[0].id
depends_on = [aws_internet_gateway.igw]
tags = {
Name = "${var.project}-${var.environment}-natgw"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw.id
}
tags = {
Name = "${var.project}-${var.environment}-public-rt"
}
}
resource "aws_route_table_association" "public" {
count = length(aws_subnet.public)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table" "private" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.nat.id
}
tags = {
Name = "${var.project}-${var.environment}-private-rt"
}
}
resource "aws_route_table_association" "private" {
count = length(aws_subnet.private)
subnet_id = aws_subnet.private[count.index].id
route_table_id = aws_route_table.private.id
}
data "aws_availability_zones" "available" {}
🧮 6. modules/vpc/variables.tf
variable "project" {}
variable "environment" {}
variable "vpc_cidr_block" {}
variable "public_subnets" {
type = list(string)
}
variable "private_subnets" {
type = list(string)
}
📤 7. modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
}
output "public_subnet_ids" {
value = aws_subnet.public[*].id
}
output "private_subnet_ids" {
value = aws_subnet.private[*].id
}
🧪 Chạy thử với Workspace
terraform init
terraform workspace new dev
terraform workspace new stage
terraform workspace new prod
terraform workspace select dev
terraform apply -var-file="envs/dev.tfvars"
📌 Những điểm quan trọng cần nhớ
-
Workspace giúp tách biệt resource theo môi trường nhưng dùng chung code.
-
Module giúp tách logic, dễ bảo trì, có thể dùng lại.
-
Route Table phải liên kết subnet phù hợp (public/Internet Gateway, private/NAT).
-
Public subnet phải bật map_public_ip_on_launch = true.
-
AZs nên phân bố đều giữa các subnet để HA.
Bạn đã hoàn thành một lab rất thực tế, có thể dùng cho:
-
hệ thống microservice trên ECS/EKS
-
public EC2 + private RDS
-
bảo mật theo từng lớp subnet
Bình luận (0)