You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
  }
}

验证步骤

  1. 应用Terraform修改:terraform apply
  2. 等待EC2实例初始化完成(约2-3分钟)
  3. 查看目标组状态,确认实例变为「健康」
  4. 访问负载均衡器的DNS地址,验证是否返回正常页面

内容的提问来源于stack exchange,提问作者BentCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 20:16:57