通过AWS ALB访问EKS上Next.js应用时持续出现503错误求助
问题:AWS EKS + ALB 部署Next.js应用持续返回503错误
我使用Terraform在AWS上部署基于Docker镜像的Next.js应用,配置了Application Load Balancer(ALB)将流量路由到EKS集群中的应用,但通过ALB的URL访问时,一直收到503 Service Temporarily Unavailable错误。
配置概况
- ALB:将端口80的HTTP流量转发到目标组
- 目标组:指向运行Next.js应用的EKS工作节点,监听端口3000
- EKS:包含Next.js应用的Deployment,以及对应的Service将流量导向Pod
相关Terraform配置
ALB配置(alb.internet_facing.tf)
resource "aws_lb" "internet_facing_alb" { name = "internet-facing-alb" internal = false load_balancer_type = "application" security_groups = [aws_security_group.internet_facing_alb_sg.id] subnets = module.vpc.public_subnets tags = { Environment = "${var.stage}" } }
监听器配置(alb.listener.app_nextjs.tf)
resource "aws_lb_listener" "http_listener" { load_balancer_arn = aws_lb.internet_facing_alb.arn port = 80 protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.nextjs_tg.arn } }
目标组配置(alb.tg.app_nextjs.tf)
resource "aws_lb_target_group" "nextjs_tg" { name = "${var.name}-nextjs-tg" target_type = "instance" port = 3000 protocol = "HTTP" vpc_id = module.vpc.vpc_id }
安全组配置
ALB安全组(sg.alb.internet_facing.tf)
# Security Group for Application Load Balancer (Public subnet) resource "aws_security_group" "internet_facing_alb_sg" { name = "${var.stage}-alb-sg" description = "Security group for Application Load Balancer" vpc_id = module.vpc.vpc_id ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } # ingress { # from_port = 443 # to_port = 443 # protocol = "tcp" # cidr_blocks = ["0.0.0.0/0"] # } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "${var.stage}-alb-sg" } }
EKS节点安全组(sg.k8s.eks.wk.node.tf)
# security_group listening traffic from alb nextjs_container_port # Security Group for EKS Nodes resource "aws_security_group" "eks_nodes_sg" { name = "${var.stage}-eks-nodes-sg" description = "Security group for EKS Nodes" vpc_id = module.vpc.vpc_id # Allow inbound traffic from the ALB to the application port (3000) ingress { from_port = 80 # Should be the port that the ALB sends traffic to, typically 3000 if that's where your app listens to_port = var.nextjs_container_port # The port your Next.js app is listening on protocol = "tcp" security_groups = [aws_security_group.internet_facing_alb_sg.id] } # Allow all outbound traffic egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "${var.stage}-eks-nodes-sg" } }
补充EKS配置
EKS Service(deployment/k8s.service.nextjs.tf)
resource "kubernetes_service" "nextjs_service" { metadata { name = "nextjs-service" namespace = "ns-nextjs" # Correct namespace name annotations = { "service.beta.kubernetes.io/aws-load-balancer-type" = "alb" "service.beta.kubernetes.io/aws-load-balancer-backend-protocol" = "http" "service.beta.kubernetes.io/aws-load-balancer-healthcheck-path" = "/" "service.beta.kubernetes.io/aws-load-balancer-healthcheck-port" = 80 "service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval" = 30 "service.beta.kubernetes.io/aws-load-balancer-target-group-arn" = aws_lb_target_group.nextjs_tg.arn } } spec { selector = { app = var.nextjs_docker_app_name } port { protocol = "TCP" port = 80 target_port = var.nextjs_container_port } # Uncomment below for SSL # port { # protocol = "TCP" # port = 443 # target_port = var.nextjs_container_port # } type = "LoadBalancer" } depends_on = [module.eks] }
EKS Deployment(k8s.app.deployment.nextjs.tf)
resource "kubernetes_deployment" "nextjs_deployment" { metadata { name = "${var.stage}-nextjs-app" namespace = "ns-nextjs" # Correct namespace name annotations = { "nextjs-docker-image" = var.nextjs_docker_image } } spec { replicas = 2 # var.nextjs_replica_count selector { match_labels = { app = var.nextjs_docker_app_name } } template { metadata { labels = { app = var.nextjs_docker_app_name } } spec { container { image = var.nextjs_docker_image name = var.nextjs_docker_app_name port { container_port = var.nextjs_container_port } resources { limits = { cpu = "0.5" memory = "512Mi" } requests = { cpu = "250m" memory = "256Mi" } } liveness_probe { http_get { path = "/" port = var.nextjs_container_port } initial_delay_seconds = 3 period_seconds = 3 } readiness_probe { http_get { path = "/" port = var.nextjs_container_port } initial_delay_seconds = 30 period_seconds = 10 } } } } } depends_on = [ module.eks, kubernetes_service.nextjs_service ] }
问题排查与修复方案
1. 安全组端口范围错误
EKS节点安全组的ingress规则中,from_port = 80与目标组监听的3000端口不匹配,导致ALB的流量被节点安全组拦截。
修复:
将节点安全组的ingress规则的from_port和to_port统一设置为var.nextjs_container_port(即3000):
ingress { from_port = var.nextjs_container_port to_port = var.nextjs_container_port protocol = "tcp" security_groups = [aws_security_group.internet_facing_alb_sg.id] }
2. 目标组与Service的配置冲突
你同时手动创建了instance类型的目标组,又在EKS Service中配置了ALB注解并绑定该目标组,存在两个核心问题:
- 手动创建的目标组不会自动注册EKS节点的NodePort(Service为
LoadBalancer类型时会分配随机NodePort,而非3000) - Service注解中指定的健康检查端口为80,与目标组监听的3000端口不匹配,导致健康检查失败
修复二选一:
方案A:保留手动ALB/目标组
- 修改目标组配置,添加健康检查规则,路径设为
/,端口设为var.nextjs_container_port - 将EKS Service的
type改为NodePort,并将目标组的监听端口改为Service分配的NodePort(或固定NodePort) - 手动将EKS工作节点注册到目标组
方案B:通过EKS Service自动生成ALB(推荐)
- 删除手动创建的
aws_lb、aws_lb_listener、aws_lb_target_group资源 - 调整Service注解,移除
aws-load-balancer-target-group-arn,让AWS Load Balancer Controller自动创建ALB和目标组,Kubernetes会自动处理节点/ Pod注册及健康检查
3. 目标组无健康注册目标
ALB返回503的常见原因是目标组中没有健康的后端节点。
验证与修复:
- 登录AWS控制台,查看目标组的「目标」标签页,确认EKS节点已注册且状态为「健康」
- 在EKS节点上执行
curl localhost:<节点端口>(节点端口为Service的NodePort或容器端口3000),验证Next.js应用是否正常响应 - 确保Next.js应用的根路径
/返回200状态码,检查容器的liveness/readiness探针是否正常通过
内容的提问来源于stack exchange,提问作者kawa
相关产品推荐
相关产品推荐

