ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Terraform实战09:ALB + Target Group + Auto Scaling

2026/8/12 16:50:43 拓冰建站 浏览量
Terraform实战09:ALB + Target Group + Auto Scaling

Terraform实战09:ALB + Target Group + Auto Scaling

本篇目标

构建经典的Web架构:ALB负载均衡器接收流量,分发到Auto Scaling Group中的多台EC2实例。理解ALB、Target Group、Listener、Launch Template、ASG之间的关系。

学完本篇你将掌握:

  • Application Load Balancer的创建和配置
  • Target Group与健康检查
  • Listener的转发规则
  • Launch Template(EC2实例模板)
  • Auto Scaling Group的弹性伸缩配置
  • 安全组的精细化设计(ALB→EC2的单向放行)

前置条件

  • 已完成前八篇练习
  • 理解VPC公私网架构

架构图

用户浏览器 │ ▼ HTTP:80 ┌───────────────┐ │ ALB │ ← 公有子网,面向外网 │ (负载均衡器) │ └───────┬───────┘ │ 转发(Listener规则) ▼ ┌───────────────┐ │ Target Group │ ← 定义后端目标+健康检查 └───────┬───────┘ │ 分发流量 ┌───────┴───────────────┐ │ Auto Scaling Group │ ← 私有子网 │ │ │ ┌─────┐ ┌─────┐ │ │ │EC2-1│ │EC2-2│ │ ← 根据模板自动创建 │ │:80 │ │:80 │ │ │ └─────┘ └─────┘ │ │ │ │ min=1 desired=2 max=3│ └────────────────────────┘

各组件的关系

组件作用类比
ALB接收外部流量,分发到后端餐厅门口的领位员
Listener监听哪个端口,收到请求后怎么处理领位员的工作规则(“80端口的客人带到Target Group”)
Target Group后端实例的集合+健康检查规则一组可用的餐桌
Launch TemplateEC2的配置模板(AMI、规格、脚本)餐桌的标准配置
Auto Scaling Group根据模板管理EC2数量(扩缩容)根据客流量增减餐桌

流量路径:用户 → ALB(:80) → Listener(转发规则) → Target Group → EC2实例


目录结构

09-alb-asg/ ├── main.tf # 所有资源(VPC+ALB+TG+ASG) ├── variables.tf # 变量(实例规格、ASG数量等) └── outputs.tf # 输出(ALB的DNS地址)

完整代码

main.tf

terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } required_version = ">= 1.0" } provider "aws" { region = var.region } locals { name_prefix = "${var.project_name}-${var.environment}" common_tags = { Project = var.project_name Environment = var.environment ManagedBy = "terraform" } # 启动脚本:安装httpd,显示实例ID(验证负载均衡) user_data = <<-EOF #!/bin/bash yum install -y httpd INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) echo "<h1>Hello from $INSTANCE_ID</h1><p>Environment: ${var.environment}</p>" > /var/www/html/index.html systemctl start httpd systemctl enable httpd EOF } # VPC(社区模块) module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "5.16.0" name = "${local.name_prefix}-vpc" cidr = "10.0.0.0/16" azs = ["${var.region}a", "${var.region}b"] public_subnets = ["10.0.1.0/24", "10.0.2.0/24"] private_subnets = ["10.0.10.0/24", "10.0.11.0/24"] enable_nat_gateway = true single_nat_gateway = true enable_dns_hostnames = true enable_dns_support = true tags = local.common_tags } # ============================================ # 安全组设计(重点) # ALB安全组:允许外部HTTP # EC2安全组:只允许来自ALB的流量 # ============================================ resource "aws_security_group" "alb" { name = "${local.name_prefix}-alb-sg" vpc_id = module.vpc.vpc_id ingress { description = "HTTP from anywhere" from_port = 80 to_port = 80 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(local.common_tags, { Name = "${local.name_prefix}-alb-sg" }) } resource "aws_security_group" "ec2" { name = "${local.name_prefix}-ec2-sg" vpc_id = module.vpc.vpc_id ingress { description = "HTTP from ALB only" from_port = 80 to_port = 80 protocol = "tcp" security_groups = [aws_security_group.alb.id] # 【关键】只允许ALB安全组 } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = merge(local.common_tags, { Name = "${local.name_prefix}-ec2-sg" }) } # ============================================ # 【新资源】ALB - Application Load Balancer # ============================================ resource "aws_lb" "web" { name = "${local.name_prefix}-alb" internal = false # 面向外网 load_balancer_type = "application" # ALB类型 security_groups = [aws_security_group.alb.id] subnets = module.vpc.public_subnets # 至少2个AZ的公有子网 tags = merge(local.common_tags, { Name = "${local.name_prefix}-alb" }) } # ============================================ # 【新资源】Target Group - 后端目标组 # ============================================ resource "aws_lb_target_group" "web" { name = "${local.name_prefix}-tg" port = 80 protocol = "HTTP" vpc_id = module.vpc.vpc_id health_check { enabled = true path = "/" # 健康检查路径 port = "traffic-port" protocol = "HTTP" healthy_threshold = 2 # 连续2次成功→健康 unhealthy_threshold = 3 # 连续3次失败→不健康 timeout = 5 # 超时秒数 interval = 30 # 检查间隔 matcher = "200" # 期望返回200 } tags = merge(local.common_tags, { Name = "${local.name_prefix}-tg" }) } # ============================================ # 【新资源】Listener - ALB监听器 # 定义:收到80端口请求后,转发到Target Group # ============================================ resource "aws_lb_listener" "http" { load_balancer_arn = aws_lb.web.arn port = 80 protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.web.arn } } # ============================================ # 【新资源】Launch Template - EC2实例模板 # ASG根据这个模板创建新实例 # ============================================ resource "aws_launch_template" "web" { name_prefix = "${local.name_prefix}-lt-" image_id = data.aws_ami.amazon_linux.id instance_type = var.instance_type vpc_security_group_ids = [aws_security_group.ec2.id] user_data = base64encode(local.user_data) # 启动脚本(需base64编码) tag_specifications { resource_type = "instance" tags = merge(local.common_tags, { Name = "${local.name_prefix}-web" }) } tags = merge(local.common_tags, { Name = "${local.name_prefix}-launch-template" }) } # ============================================ # 【新资源】Auto Scaling Group - 弹性伸缩组 # ============================================ resource "aws_autoscaling_group" "web" { name = "${local.name_prefix}-asg" desired_capacity = var.desired_capacity min_size = var.min_size max_size = var.max_size vpc_zone_identifier = module.vpc.private_subnets # EC2在私有子网 launch_template { id = aws_launch_template.web.id version = "$Latest" } # 【关键】关联Target Group,新实例自动注册到ALB target_group_arns = [aws_lb_target_group.web.arn] # 用ELB健康检查(ALB判断实例是否健康) health_check_type = "ELB" health_check_grace_period = 60 tag { key = "Name" value = "${local.name_prefix}-web" propagate_at_launch = true } } data "aws_ami" "amazon_linux" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["al2023-ami-2023*-x86_64"] } filter { name = "state" values = ["available"] } }

variables.tf

variable "region" { default = "us-east-1" } variable "project_name" { default = "tf-practice" } variable "environment" { default = "dev" } variable "instance_type" { description = "EC2实例规格" default = "t3.micro" } variable "desired_capacity" { description = "ASG期望实例数" default = 2 } variable "min_size" { description = "ASG最小实例数" default = 1 } variable "max_size" { description = "ASG最大实例数" default = 3 }

outputs.tf

output "alb_dns_name" { description = "ALB的DNS地址(浏览器访问)" value = aws_lb.web.dns_name } output "alb_url" { description = "完整访问URL" value = "http://${aws_lb.web.dns_name}" } output "target_group_arn" { value = aws_lb_target_group.web.arn } output "asg_name" { value = aws_autoscaling_group.web.name }

新增资源说明

ALB关键字段

字段含义
internal = false面向外网(true=内部ALB)
load_balancer_type = "application"ALB类型(还有network、gateway)
security_groupsALB自己的安全组
subnetsALB部署的子网(至少2个AZ)

Target Group关键字段

字段含义
port后端实例监听的端口
protocol后端使用的协议
health_check.path健康检查的URL路径
health_check.healthy_threshold连续几次成功算健康
health_check.unhealthy_threshold连续几次失败算不健康
health_check.interval检查间隔(秒)
health_check.matcher期望的HTTP状态码

Launch Template关键字段

字段含义
image_idAMI ID
instance_type实例规格
vpc_security_group_ids安全组
user_data启动脚本(需base64编码)
tag_specifications实例标签

Auto Scaling Group关键字段

字段含义
desired_capacity期望运行几台
min_size缩容最少保留几台
max_size扩容最多到几台
vpc_zone_identifier实例创建在哪些子网
launch_template使用哪个实例模板
target_group_arns关联的Target Group(新实例自动注册)
health_check_type“EC2"或"ELB”(推荐ELB)
health_check_grace_period新实例启动后等多久再检查

安全组设计要点

外部流量 → ALB安全组(允许0.0.0.0/0:80)→ EC2安全组(只允许ALB安全组)

EC2的安全组不直接开放给外网,而是用security_groups = [ALB的安全组ID]限制来源。这样:

  • 外网只能通过ALB访问EC2
  • 直接访问EC2的公网IP会被拒绝
  • 即使EC2有公网IP也不怕(事实上私有子网里没有)

操作步骤与实际输出

Apply

terraform apply -auto-approve
aws_lb.web: Creation complete after 3m17s ← ALB创建较慢 aws_autoscaling_group.web: Creation complete after 14s Apply complete! Resources: 26 added, 0 changed, 0 destroyed. Outputs: alb_dns_name = "tf-practice-dev-alb-799249280.us-east-1.elb.amazonaws.com" alb_url = "http://tf-practice-dev-alb-799249280.us-east-1.elb.amazonaws.com" asg_name = "tf-practice-dev-asg"

验证负载均衡

第1次刷新:Hello from i-0abc123... 第2次刷新:Hello from i-0def456... ← 不同实例,负载均衡生效

控制台验证

ALB概览:

  • 状态:Active
  • DNS名称
  • 类型:application

Target Group健康状态:

  • 2个实例注册
  • 状态:Healthy

Listener规则:

  • HTTP:80 → Forward to target group

ASG详情:

  • Desired: 2, Min: 1, Max: 3

EC2实例:

  • 2台实例,由ASG创建

Destroy

terraform destroy -auto-approve# Destroy complete! Resources: 26 destroyed.

延伸思考:面试常见问题

面试问题答案要点
ALB和NLB的区别?ALB工作在7层(HTTP),支持路径/域名路由;NLB工作在4层(TCP),性能更高
Target Group的健康检查有什么用?自动摘除不健康的实例,流量不会转发到故障节点
ASG怎么实现弹性伸缩?根据策略(CPU利用率、请求数等)自动调整desired_capacity
为什么EC2安全组只允许ALB安全组?最小权限原则,EC2不直接暴露给外网
Launch Template和Launch Configuration的区别?Template更新,支持版本管理、混合实例等,Configuration已废弃
ASG的health_check_type选EC2还是ELB?推荐ELB——如果应用挂了但EC2没挂,ELB能检测到,EC2检测不到

费用说明

资源费用
ALB~$0.022/小时
NAT Gateway~$0.045/小时
EC2 t3.micro × 2~$0.021/小时
VPC / 子网 / 安全组免费
总计~$0.09/小时

本次练习(约40分钟):约$0.06


小结

本篇核心收获:

  1. ALB + Target Group + ASG是AWS最经典的Web架构
  2. 流量路径:用户→ALB→Listener→Target Group→EC2
  3. ASG关联Target Group:新实例自动注册到ALB,无需手动操作
  4. 安全组链式设计:EC2只接受ALB的流量,不直接暴露
  5. Launch Template:EC2的"模板",ASG根据它创建新实例
  6. 健康检查:自动摘除不健康实例,保证服务可用性

下一篇预告

Terraform实战10:RDS + Secrets Manager

下一篇我们将学习:

  • 创建RDS MySQL/PostgreSQL数据库
  • 数据库子网组配置
  • 用Secrets Manager管理数据库密码
  • 安全组限制只允许应用访问数据库

参考链接

  • 本系列配套代码(GitHub)
  • Terraform aws_lb文档
  • Terraform aws_lb_target_group文档
  • Terraform aws_autoscaling_group文档
  • AWS ALB官方文档
  • AWS Auto Scaling官方文档