ECS任务无法访问公网问题排查求助
问题排查:ECS容器无法访问公网端点
环境配置概述
- 基于EC2实例的ECS集群
- 已关联VPC的Internet Gateway(IGW)
- IGW与公网子网已关联路由表
- API前端部署API Gateway,通过服务发现路由流量到ECS容器
- 集群部署在公网子网,未使用NAT网关
- ECS底层EC2实例已分配公网IP,安全组仅允许API Gateway入站流量,允许所有出站流量
- 容器无法访问Stripe API、Cognito-IDP等公网端点
相关Terraform配置
任务定义
resource "aws_ecs_task_definition" "aws-ecs-api-task" { family = "myservice-api-task" container_definitions = <<DEFINITION [ { "name": "${local.api_container_name}", "image": "${aws_ecr_repository.aws-ecr-api.repository_url}:latest", "cpu": ${var.api_container_cpu}, "memory": ${var.api_container_memory}, "portMappings": [ { "containerPort": ${var.api_container_port}, "hostPort": ${var.api_container_host_port} } ], "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "${aws_cloudwatch_log_group.api-log-group.id}", "awslogs-region": "${var.region}", "awslogs-stream-prefix": "${var.app_name}-${var.environment}" } }, "healthcheck": { "command": ["CMD-SHELL", "curl -f http://localhost:${var.api_container_port}/api/1.0/general/version || exit 1"] }, "essential": true, "networkMode": "awsvpc" } ] DEFINITION requires_compatibilities = ["EC2"] network_mode = "awsvpc" memory = var.api_container_memory cpu = var.api_container_cpu execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn task_role_arn = aws_iam_role.ecs_task_role.arn tags = { Name = "${var.app_name}-ecs-api-task-definition" Environment = var.environment } }
ECS服务配置
resource "aws_ecs_service" "aws-ecs-service_api" { name = "ecs_service-api-${var.environment}" cluster = var.ecs_cluster_id task_definition = aws_ecs_task_definition.aws-ecs-api-task.arn deployment_maximum_percent = 200 #during red/green it is allowed to spawn 200% of desired tasks deployment_minimum_healthy_percent = 100 #always have one healthy pod desired_count = var.api_container_desired_count scheduling_strategy = "REPLICA" force_new_deployment = false capacity_provider_strategy { capacity_provider = var.capacity_provider_name weight = 100 base = 1 } network_configuration { subnets = var.ecs_service_subnet_ids assign_public_ip = false security_groups = [aws_security_group.ecs_service_api_sg.id] } service_registries { registry_arn = aws_service_discovery_service.ecs-discovery-service.arn port = var.api_container_port } tags = { Name = "${var.app_name}-ecs_service-api" Environment = var.environment } }
排查步骤
1. 检查awsvpc模式下的公网IP分配
使用awsvpc网络模式时,容器会获得独立的弹性网络接口(ENI),与EC2主机的公网IP无关。你当前服务配置中assign_public_ip = false,容器没有公网IP,自然无法直接访问公网。
- 临时修改ECS服务的
assign_public_ip = true,重新部署后测试容器公网访问能力。如果恢复正常,说明问题根源在此。
2. 验证容器安全组的出站规则
awsvpc模式下,容器使用单独的安全组(ecs_service_api_sg),EC2主机的安全组规则不作用于容器。
- 检查
ecs_service_api_sg的出站规则,确保包含0.0.0.0/0的全允许规则,或至少允许到Stripe(443端口)、Cognito-IDP等目标的出站流量。
3. 确认子网路由表配置
公网子网的路由表必须包含指向IGW的默认路由,否则容器的公网流量无法转发出去。
- 进入VPC控制台,找到容器所在子网关联的路由表,检查是否存在
0.0.0.0/0 -> IGW的路由条目。若缺失,添加该路由。
4. 测试DNS解析能力
容器无法访问公网可能是DNS解析失败导致的。
- 进入容器内部,执行
nslookup stripe.com或nslookup cognito-idp.<region>.amazonaws.com,检查是否能正常解析到目标IP。 - 若解析失败,检查VPC配置:确保
enableDnsSupport和enableDnsHostnames均设为true,子网DNS配置继承VPC设置。
5. 检查EC2实例的IP转发设置
awsvpc模式依赖EC2实例的IP转发功能,否则容器流量无法通过主机转发到公网。
- 登录EC2实例,执行
sysctl net.ipv4.ip_forward,若返回net.ipv4.ip_forward = 0,说明未开启。 - 临时开启:
sysctl -w net.ipv4.ip_forward=1,测试容器网络。若有效,在实例用户数据中添加配置确保重启后生效:echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf sysctl -p /etc/sysctl.conf
总结
最可能的问题是awsvpc模式下容器未分配公网IP或容器安全组未允许出站流量,优先排查这两个点。
内容的提问来源于stack exchange,提问作者Jeppe Christensen
相关产品推荐
相关产品推荐

