Quay lại

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    comment-3 Created with Sketch Beta. 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.tfvarsprod.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)

Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough
Michael Gough

Bài viết liên quan

Learning English Everyday