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

Terraform部署到ECS EC2的Next.js应用API调用出现504网关超时

问题描述

调用Next.js应用内编写的API时出现504网关超时。该Web应用与API部署在同一ECS任务中,通过Terraform部署至AWS ECS,采用Application Load Balancer(应用负载均衡器)和EC2启动类型,任务配置awsvpc网络模式。目前可通过HTTPS正常访问页面,说明安全组基础配置无问题。

任务出站规则已设置为允许所有协议与端口,但页面调用Next.js API时始终返回504网关超时。基础设施及VPC等网络组件均通过Terraform创建,API请求还需与Cognito、DynamoDB交互,且ECS任务的IAM角色已附加对应权限策略。已检查带Internet Gateway的路由表规则,问题仍未解决。


相关配置代码

VPC与子网配置

# VPC and subnets
data "aws_vpc" "default_vpc" {
  default = true
}

data "aws_subnets" "all_default_subnets" {
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.default_vpc.id]
  }
}

应用负载均衡器(ALB)配置

# ALB
resource "aws_lb" "alb" {
  name               = "alb"
  load_balancer_type = "application"
  security_groups    = [ aws_security_group.alb.id ]
  subnets            = data.aws_subnets.all_default_subnets.ids
  enable_deletion_protection = false
}

resource "aws_lb_target_group" "lb_target_group" {
  name        = "target-alb-name"
  port        = "80"
  protocol    = "HTTP"
  vpc_id      = data.aws_vpc.default_vpc.id
  target_type = "ip"

  health_check {
    healthy_threshold   = "3"
    interval            = "10"
    path                = "/api/health"
    protocol            = "HTTP"
    unhealthy_threshold = "3"
  }
}

resource "aws_lb_listener" "alb_80" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "443"
  protocol          = "HTTPS"
  # 由Terraform生成的证书
  certificate_arn = aws_acm_certificate.loadbalancer_cert.arn

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.lb_target_group.arn
  }
  tags = {
    environment = "prod"
  }
}

ECS服务配置

# AWS ECS-SERVICE
resource "aws_ecs_service" "service" {
  cluster                = aws_ecs_cluster.cluster.id
  desired_count          = 1
  launch_type            = "EC2"
  name                   = "service"
  task_definition        = aws_ecs_task_definition.task_definition.arn
  force_new_deployment = true
  deployment_minimum_healthy_percent = 0
  network_configuration {
    subnets = data.aws_subnets.all_default_subnets.ids
    security_groups = [aws_security_group.ecs_tasks.id]
    assign_public_ip = false
  }
  load_balancer {
    container_name = "ecs-container"
    container_port = 3000
    target_group_arn = aws_lb_target_group.lb_target_group.arn
  }
  depends_on = [aws_lb_listener.alb_80]
}

ECS任务定义配置

# AWS ECS-TASK
resource "aws_ecs_task_definition" "task_definition" {
  container_definitions    = data.template_file.task_definition_json.rendered
  execution_role_arn       = var.execution_task_role_arn
  family                   = "web-task"
  network_mode             = "awsvpc"
  cpu                      = "128"
  memory                   = "256"
  requires_compatibilities = ["EC2"]
  task_role_arn            = var.prod_task_role_arn
}

data "template_file" "task_definition_json" {
  template = file("${path.module}/task_definition.json")
  vars = {
    BASE_URL = var.BASE_URL,
    APP_AWS_REGION = var.APP_AWS_REGION,
    COGNITO_WEB_CLIENT_ID = var.COGNITO_WEB_CLIENT_ID,
    COGNITO_USER_POOL_ID = var.COGNITO_USER_POOL_ID,
    AWS_ACCESS_KEY_ID = var.AWS_ACCESS_KEY_ID,
    AWS_SECRET_ACCESS_KEY = var.AWS_SECRET_ACCESS_KEY,
    DYNAMODB_TABLE_NAME = var.DYNAMODB_TABLE_NAME,
    COGNITO_REGION = var.COGNITO_REGION,
  }
}

ECS EC2实例配置

# AWS ECS-EC2
module "ec2_instance" {
  source  = "terraform-aws-modules/ec2-instance/aws"
  version = "~> 4.3.0"

  name = "ec2-instance"

  create_spot_instance = false
  iam_instance_profile = aws_iam_instance_profile.ecs_agent.name
  user_data            = data.template_file.user_data.rendered

  ami                    = var.prod_ami_id
  instance_type          = var.prod_instance_type
  key_name               = "key-pairs"
  monitoring             = true
  vpc_security_group_ids = [aws_security_group.ecs_tasks.id]
  subnet_id              = data.aws_subnets.all_default_subnets.ids[0]

  root_block_device = [
    {
      volume_type           = "gp3"
      volume_size           = 30
      delete_on_termination = true
    }
  ]

  tags = {
    environment = "prod"
  }
}

data "template_file" "user_data" {
  template = file("${path.module}/user_data.tpl")
}

安全组配置

# Security Group Config
resource "aws_security_group" "ecs_tasks" {
  name = "sg-ecs-tasks"
  vpc_id = data.aws_vpc.default_vpc.id
  ingress {
    protocol="tcp"
    from_port=3000
    to_port=3000
    cidr_blocks=["0.0.0.0/0"]
  }
  ingress {
    protocol="tcp"
    from_port=443
    to_port=443
    cidr_blocks=["0.0.0.0/0"]
  }
  ingress {
    protocol="tcp"
    from_port=80
    to_port=80
    cidr_blocks=["0.0.0.0/0"]
  }
  egress {
    protocol="-1"
    from_port=0
    to_port=0
    cidr_blocks=["0.0.0.0/0"]
  }
}

resource "aws_security_group" "alb" {
  name = "sg-alb"
  vpc_id = data.aws_vpc.default_vpc.id
  ingress {
    protocol="tcp"
    from_port=3000
    to_port=3000
    cidr_blocks=["0.0.0.0/0"]
  }
  ingress {
    protocol="tcp"
    from_port=443
    to_port=443
    cidr_blocks=["0.0.0.0/0"]
  }
  ingress {
    protocol="tcp"
    from_port=80
    to_port=80
    cidr_blocks=["0.0.0.0/0"]
  }
  egress {
    protocol="-1"
    from_port=0
    to_port=0
    cidr_blocks=["0.0.0.0/0"]
  }
}

EC2实例User Data配置

#!/bin/bash

cat <<'EOF' >> /etc/ecs/ecs.config
ECS_CLUSTER=ecs-cluster
ECS_ENABLE_SPOT_INSTANCE_DRAINING=true
ECS_ENABLE_CONTAINER_METADATA=true
ECS_AVAILABLE_LOGGING_DRIVERS=["json-file","awslogs"]
ECS_IMAGE_PULL_BEHAVIOR=always
EOF

yum update -y
yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 19:50:19