AWS 基础设施实战
使用 Terraform 构建完整的 AWS 基础设施。
一、项目概述
1.1 架构设计
构建一个三层 Web 应用架构:
┌─────────────────────────────────────────┐
│ Internet Gateway │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Application Load Balancer │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Web Tier (Auto Scaling Group) │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ EC2 │ │ EC2 │ │ EC2 │ │
│ └──────┘ └──────┘ └──────┘ │
└─────────────────┬───────────────────────┘
│
┌─────────────────▼───────────────────────┐
│ Database Tier (RDS Multi-AZ) │
│ ┌──────────────────┐ │
│ │ PostgreSQL │ │
│ └──────────────────┘ │
└─────────────────────────────────────────┘
1.2 项目结构
aws-infrastructure/
├── main.tf
├── variables.tf
├── outputs.tf
├── terraform.tfvars
├── modules/
│ ├── vpc/
│ ├── security/
│ ├── compute/
│ └── database/
└── environments/
├── dev.tfvars
├── staging.tfvars
└── prod.tfvars
二、网络层
2.1 VPC 模块
modules/vpc/main.tf:
locals {
az_count = length(var.availability_zones)
}
# VPC
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-vpc"
}
)
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-igw"
}
)
}
# 公有子网
resource "aws_subnet" "public" {
count = local.az_count
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-public-${count.index + 1}"
Tier = "Public"
}
)
}
# 私有子网(应用层)
resource "aws_subnet" "private_app" {
count = local.az_count
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 10)
availability_zone = var.availability_zones[count.index]
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-private-app-${count.index + 1}"
Tier = "Application"
}
)
}
# 私有子网(数据库层)
resource "aws_subnet" "private_db" {
count = local.az_count
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index + 20)
availability_zone = var.availability_zones[count.index]
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-private-db-${count.index + 1}"
Tier = "Database"
}
)
}
# NAT Gateway EIP
resource "aws_eip" "nat" {
count = var.enable_nat_gateway ? local.az_count : 0
domain = "vpc"
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-nat-eip-${count.index + 1}"
}
)
depends_on = [aws_internet_gateway.main]
}
# NAT Gateway
resource "aws_nat_gateway" "main" {
count = var.enable_nat_gateway ? local.az_count : 0
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.public[count.index].id
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-nat-${count.index + 1}"
}
)
}
# 路由表配置(省略)...
# VPC Endpoints(可选)
resource "aws_vpc_endpoint" "s3" {
vpc_id = aws_vpc.main.id
service_name = "com.amazonaws.${var.region}.s3"
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-s3-endpoint"
}
)
}
三、安全层
3.1 安全组
modules/security/main.tf:
# ALB 安全组
resource "aws_security_group" "alb" {
name_prefix = "${var.project_name}-${var.environment}-alb-"
description = "Security group for Application Load Balancer"
vpc_id = var.vpc_id
ingress {
description = "HTTP from Internet"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "HTTPS from Internet"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-alb-sg"
}
)
lifecycle {
create_before_destroy = true
}
}
# 应用服务器安全组
resource "aws_security_group" "app" {
name_prefix = "${var.project_name}-${var.environment}-app-"
description = "Security group for application servers"
vpc_id = var.vpc_id
ingress {
description = "HTTP from ALB"
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.alb.id]
}
ingress {
description = "SSH from bastion"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.allowed_ssh_cidrs
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-app-sg"
}
)
lifecycle {
create_before_destroy = true
}
}
# 数据库安全组
resource "aws_security_group" "database" {
name_prefix = "${var.project_name}-${var.environment}-db-"
description = "Security group for database"
vpc_id = var.vpc_id
ingress {
description = "PostgreSQL from app servers"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-db-sg"
}
)
lifecycle {
create_before_destroy = true
}
}
四、计算层
4.1 Auto Scaling Group
modules/compute/main.tf:
# Launch Template
resource "aws_launch_template" "app" {
name_prefix = "${var.project_name}-${var.environment}-"
image_id = var.ami_id
instance_type = var.instance_type
network_interfaces {
associate_public_ip_address = false
security_groups = [var.security_group_id]
delete_on_termination = true
}
iam_instance_profile {
name = aws_iam_instance_profile.app.name
}
user_data = base64encode(templatefile("${path.module}/user-data.sh", {
db_endpoint = var.db_endpoint
db_name = var.db_name
db_user = var.db_username
region = var.region
}))
tag_specifications {
resource_type = "instance"
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-app"
}
)
}
lifecycle {
create_before_destroy = true
}
}
# Auto Scaling Group
resource "aws_autoscaling_group" "app" {
name = "${var.project_name}-${var.environment}-asg"
vpc_zone_identifier = var.subnet_ids
target_group_arns = [aws_lb_target_group.app.arn]
health_check_type = "ELB"
health_check_grace_period = 300
min_size = var.asg_min_size
max_size = var.asg_max_size
desired_capacity = var.asg_desired_capacity
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
dynamic "tag" {
for_each = var.common_tags
content {
key = tag.key
value = tag.value
propagate_at_launch = true
}
}
lifecycle {
create_before_destroy = true
ignore_changes = [desired_capacity]
}
}
# Auto Scaling Policy
resource "aws_autoscaling_policy" "scale_up" {
name = "${var.project_name}-${var.environment}-scale-up"
scaling_adjustment = 1
adjustment_type = "ChangeInCapacity"
cooldown = 300
autoscaling_group_name = aws_autoscaling_group.app.name
}
resource "aws_autoscaling_policy" "scale_down" {
name = "${var.project_name}-${var.environment}-scale-down"
scaling_adjustment = -1
adjustment_type = "ChangeInCapacity"
cooldown = 300
autoscaling_group_name = aws_autoscaling_group.app.name
}
# CloudWatch Alarms
resource "aws_cloudwatch_metric_alarm" "cpu_high" {
alarm_name = "${var.project_name}-${var.environment}-cpu-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 2
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 120
statistic = "Average"
threshold = 70
dimensions = {
AutoScalingGroupName = aws_autoscaling_group.app.name
}
alarm_actions = [aws_autoscaling_policy.scale_up.arn]
}
resource "aws_cloudwatch_metric_alarm" "cpu_low" {
alarm_name = "${var.project_name}-${var.environment}-cpu-low"
comparison_operator = "LessThanThreshold"
evaluation_periods = 2
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 120
statistic = "Average"
threshold = 30
dimensions = {
AutoScalingGroupName = aws_autoscaling_group.app.name
}
alarm_actions = [aws_autoscaling_policy.scale_down.arn]
}
# Application Load Balancer
resource "aws_lb" "app" {
name = "${var.project_name}-${var.environment}-alb"
internal = false
load_balancer_type = "application"
security_groups = [var.alb_security_group_id]
subnets = var.public_subnet_ids
enable_deletion_protection = var.environment == "prod"
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-alb"
}
)
}
# Target Group
resource "aws_lb_target_group" "app" {
name = "${var.project_name}-${var.environment}-tg"
port = 8080
protocol = "HTTP"
vpc_id = var.vpc_id
health_check {
enabled = true
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 5
interval = 30
path = "/health"
matcher = "200"
}
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-tg"
}
)
}
# Listener
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.app.arn
port = 80
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
}
五、数据库层
5.1 RDS PostgreSQL
modules/database/main.tf:
# DB Subnet Group
resource "aws_db_subnet_group" "main" {
name = "${var.project_name}-${var.environment}-db-subnet-group"
subnet_ids = var.subnet_ids
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-db-subnet-group"
}
)
}
# DB Parameter Group
resource "aws_db_parameter_group" "postgres" {
name = "${var.project_name}-${var.environment}-postgres14"
family = "postgres14"
parameter {
name = "log_connections"
value = "1"
}
parameter {
name = "log_disconnections"
value = "1"
}
parameter {
name = "log_duration"
value = "1"
}
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-postgres14"
}
)
}
# RDS Instance
resource "aws_db_instance" "main" {
identifier = "${var.project_name}-${var.environment}-db"
# 引擎配置
engine = "postgres"
engine_version = "14.7"
instance_class = var.db_instance_class
allocated_storage = var.db_allocated_storage
storage_type = "gp3"
storage_encrypted = true
# 数据库配置
db_name = var.db_name
username = var.db_username
password = var.db_password
port = 5432
# 网络配置
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [var.security_group_id]
publicly_accessible = false
# 高可用配置
multi_az = var.environment == "prod"
# 备份配置
backup_retention_period = var.environment == "prod" ? 30 : 7
backup_window = "03:00-04:00"
maintenance_window = "sun:04:00-sun:05:00"
# 其他配置
parameter_group_name = aws_db_parameter_group.postgres.name
enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"]
auto_minor_version_upgrade = true
deletion_protection = var.environment == "prod"
skip_final_snapshot = var.environment != "prod"
final_snapshot_identifier = var.environment == "prod" ? "${var.project_name}-${var.environment}-final-snapshot-${formatdate("YYYY-MM-DD-hhmm", timestamp())}" : null
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-db"
}
)
}
# Read Replica(生产环境)
resource "aws_db_instance" "replica" {
count = var.environment == "prod" && var.enable_read_replica ? 1 : 0
identifier = "${var.project_name}-${var.environment}-db-replica"
replicate_source_db = aws_db_instance.main.identifier
instance_class = var.db_instance_class
publicly_accessible = false
skip_final_snapshot = true
tags = merge(
var.common_tags,
{
Name = "${var.project_name}-${var.environment}-db-replica"
}
)
}
六、主配置
main.tf:
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "aws-infrastructure/terraform.tfstate"
region = "us-west-2"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
provider "aws" {
region = var.region
default_tags {
tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "Terraform"
}
}
}
# 网络层
module "vpc" {
source = "./modules/vpc"
project_name = var.project_name
environment = var.environment
vpc_cidr = var.vpc_cidr
availability_zones = var.availability_zones
enable_nat_gateway = var.enable_nat_gateway
common_tags = local.common_tags
region = var.region
}
# 安全层
module "security" {
source = "./modules/security"
project_name = var.project_name
environment = var.environment
vpc_id = module.vpc.vpc_id
allowed_ssh_cidrs = var.allowed_ssh_cidrs
common_tags = local.common_tags
}
# 数据库层
module "database" {
source = "./modules/database"
project_name = var.project_name
environment = var.environment
subnet_ids = module.vpc.private_db_subnet_ids
security_group_id = module.security.database_sg_id
db_instance_class = var.db_instance_class
db_allocated_storage = var.db_allocated_storage
db_name = var.db_name
db_username = var.db_username
db_password = var.db_password
enable_read_replica = var.enable_db_read_replica
common_tags = local.common_tags
}
# 计算层
module "compute" {
source = "./modules/compute"
project_name = var.project_name
environment = var.environment
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_app_subnet_ids
public_subnet_ids = module.vpc.public_subnet_ids
security_group_id = module.security.app_sg_id
alb_security_group_id = module.security.alb_sg_id
ami_id = var.ami_id
instance_type = var.instance_type
asg_min_size = var.asg_min_size
asg_max_size = var.asg_max_size
asg_desired_capacity = var.asg_desired_capacity
db_endpoint = module.database.db_endpoint
db_name = var.db_name
db_username = var.db_username
region = var.region
common_tags = local.common_tags
}
locals {
common_tags = {
Project = var.project_name
Environment = var.environment
ManagedBy = "Terraform"
CreatedAt = formatdate("YYYY-MM-DD", timestamp())
}
}
七、部署
7.1 初始化
terraform init
7.2 规划(开发环境)
terraform plan -var-file="environments/dev.tfvars"
7.3 应用
terraform apply -var-file="environments/dev.tfvars"
7.4 销毁
terraform destroy -var-file="environments/dev.tfvars"
小结
本章构建了一个完整的三层 Web 应用基础设施:
- 网络层:VPC、子网、NAT 网关
- 安全层:安全组、网络 ACL
- 计算层:ALB、Auto Scaling、EC2
- 数据库层:RDS PostgreSQL
这是一个可直接用于生产的架构模板!