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)