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
相关产品推荐
相关产品推荐

