Terraform搭建AWS Application ELB遇502错误,目标组不健康求助
问题:AWS应用负载均衡返回502 Bad Gateway,目标组显示不健康
我尝试实现AWS负载均衡器粘性子网路由架构(为符合免费层免收费条件,未使用弹性IP),但访问负载均衡器时持续返回502 Bad Gateway错误。EC2实例的「系统可达性检查」和「实例可达性检查」均已通过,但关联的目标组始终显示「不健康」。我缺乏AWS基础设施搭建和Terraform使用经验,以下是我编写的Terraform代码,恳请帮忙排查问题。
Terraform代码
terraform { required_version = "~> 1.4.4" required_providers { aws = { source = "hashicorp/aws" version = "~> 4.30.0" } } } provider "aws" { profile = "development" region = local.region } # -- VARS ---------------------------------------------------------------------- locals { project = "app" region = "eu-west-1" vpc_cidr = "10.0.0.0/16" public_subnets = { "a1" = { az = "${local.region}a" cidr = "10.0.10.0/24" }, "b1" = { az = "${local.region}b" cidr = "10.0.20.0/24" } } private_subnets = { "a1" = { az = "${local.region}a" cidr = "10.0.135.0/24" }, "b1" = { az = "${local.region}b" cidr = "10.0.145.0/24" } } ec2_ami = "ami-0fb2f0b847d44d4f0" // Amazon Linux 2023 AMI 2023.1.20230705.0 x86_64 HVM kernel-6.1 ec2_instance_type = "t2.micro" } # -- VPC ----------------------------------------------------------------------- resource "aws_vpc" "vpc" { cidr_block = local.vpc_cidr enable_dns_support = true enable_dns_hostnames = true tags = { Name = local.project } } # -- ROUTE TABLE --------------------------------------------------------------- resource "aws_route_table" "public" { vpc_id = aws_vpc.vpc.id tags = { Name = "${local.project}-public" } } resource "aws_route_table" "private" { vpc_id = aws_vpc.vpc.id tags = { Name = "${local.project}-private" } } # -- INTERNET GATEWAY ---------------------------------------------------------- resource "aws_internet_gateway" "public" { vpc_id = aws_vpc.vpc.id tags = { Name = local.project } } resource "aws_route" "public" { destination_cidr_block = "0.0.0.0/0" route_table_id = aws_route_table.public.id gateway_id = aws_internet_gateway.public.id } # -- SUBNET -------------------------------------------------------------------- resource "aws_subnet" "public" { for_each = local.public_subnets vpc_id = aws_vpc.vpc.id cidr_block = each.value.cidr availability_zone = each.value.az tags = { Name = "${local.project}-public-${each.key}" } } resource "aws_subnet" "private" { for_each = local.private_subnets vpc_id = aws_vpc.vpc.id cidr_block = each.value.cidr availability_zone = each.value.az tags = { Name = "${local.project}-private-${each.key}" } } resource "aws_route_table_association" "public" { for_each = local.public_subnets subnet_id = aws_subnet.public[each.key].id route_table_id = aws_route_table.public.id } resource "aws_route_table_association" "private" { for_each = local.private_subnets subnet_id = aws_subnet.private[each.key].id route_table_id = aws_route_table.private.id } # -- SECURITY GROUP ------------------------------------------------------------ resource "aws_security_group" "elb" { name = "${local.project}-elb" vpc_id = aws_vpc.vpc.id ingress { description = "From Internet to ELB" from_port = "80" to_port = "80" protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { description = "From ELB to Internet" from_port = "0" to_port = "0" protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_security_group" "ec2" { name = "${local.project}-ec2" vpc_id = aws_vpc.vpc.id ingress { description = "From ELB to EC2" from_port = "80" to_port = "80" protocol = "tcp" security_groups = [aws_security_group.elb.id] } egress { description = "From EC2 to ELB" from_port = "0" to_port = "0" protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } # -- EC2 ----------------------------------------------------------------------- resource "aws_instance" "ec2" { for_each = local.private_subnets ami = local.ec2_ami instance_type = local.ec2_instance_type subnet_id = aws_subnet.private[each.key].id vpc_security_group_ids = [aws_security_group.ec2.id] associate_public_ip_address = true tags = { Name = "${local.project}-ec2-private-subnet-${each.key}" } } # -- LOAD BALANCER ------------------------------------------------------------- resource "aws_lb" "application" { name = "${local.project}-application-load-balancer" load_balancer_type = "application" security_groups = [aws_security_group.elb.id] subnets = [for sub in aws_subnet.public : sub.id] } resource "aws_lb_target_group" "application" { name = "${local.project}-http-application" port = 80 protocol = "HTTP" vpc_id = aws_vpc.vpc.id load_balancing_algorithm_type = "least_outstanding_requests" health_check { protocol = "HTTP" port = 80 path = "/" healthy_threshold = 2 unhealthy_threshold = 2 timeout = 10 interval = 30 matcher = 200 } } resource "aws_lb_target_group_attachment" "ec2" { for_each = aws_instance.ec2 port = 80 target_id = each.value.id target_group_arn = aws_lb_target_group.application.arn } resource "aws_lb_listener" "application" { load_balancer_arn = aws_lb.application.arn port = "80" protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.application.arn } tags = { Name = "${local.project}-application-load-listener" } }
问题排查与修复方案
1. EC2实例未部署Web服务
你的EC2使用的是Amazon Linux 2023基础AMI,默认没有安装任何监听80端口的Web服务(如Nginx、Apache),目标组的健康检查请求http://<实例IP>/会返回404或连接失败,导致实例被标记为不健康。
修复: 在aws_instance.ec2资源中添加user_data脚本,自动安装并启动Nginx:
resource "aws_instance" "ec2" { for_each = local.private_subnets ami = local.ec2_ami instance_type = local.ec2_instance_type subnet_id = aws_subnet.private[each.key].id vpc_security_group_ids = [aws_security_group.ec2.id] associate_public_ip_address = true # 添加以下user_data user_data = <<-EOF #!/bin/bash yum update -y yum install -y nginx systemctl start nginx systemctl enable nginx echo "<h1>Hello from $(hostname -f)</h1>" > /usr/share/nginx/html/index.html EOF tags = { Name = "${local.project}-ec2-private-subnet-${each.key}" } }
2. 私有子网路由缺失(无法访问互联网)
虽然你给私有子网的EC2分配了公网IP,但私有子网的路由表没有指向互联网网关的路由,导致EC2无法下载安装Web服务的依赖包,初始化失败。
修复: 给私有子网的路由表添加默认路由指向互联网网关(临时方案,适合测试;生产环境建议使用NAT网关,免费层的弹性IP关联运行中的NAT网关不收费):
resource "aws_route" "private_internet" { destination_cidr_block = "0.0.0.0/0" route_table_id = aws_route_table.private.id gateway_id = aws_internet_gateway.public.id }
3. 健康检查配置过严
当前健康检查的timeout=10秒、interval=30秒,若EC2实例启动较慢,可能来不及响应健康检查请求就被标记为不健康。
修复: 调整目标组的健康检查参数为更宽松的配置:
resource "aws_lb_target_group" "application" { name = "${local.project}-http-application" port = 80 protocol = "HTTP" vpc_id = aws_vpc.vpc.id load_balancing_algorithm_type = "least_outstanding_requests" health_check { protocol = "HTTP" port = 80 path = "/" healthy_threshold = 3 unhealthy_threshold = 3 timeout = 5 interval = 15 matcher = 200 } }
验证步骤
- 应用Terraform修改:
terraform apply - 等待EC2实例初始化完成(约2-3分钟)
- 查看目标组状态,确认实例变为「健康」
- 访问负载均衡器的DNS地址,验证是否返回正常页面
内容的提问来源于stack exchange,提问作者BentCoder
相关产品推荐
相关产品推荐

