CloudFormation部署Nginx镜像至ECS遇循环问题,服务无法完成部署
问题:CloudFormation部署ECS Fargate服务陷入准备/排空循环,本地Docker正常运行
我尝试通过CloudFormation模板部署React前端应用,本地Docker构建并运行的Nginx镜像可正常工作,但CloudFormation栈始终无法完成部署,陷入服务准备与排空的循环状态。已尝试修改Nginx配置及模板中的端口号排查冲突,但未能解决;日志流配置未成功,但非当前核心问题。
相关配置文件
CloudFormation模板
AWSTemplateFormatVersion: "2010-09-09" Parameters: FrontendImageName: Type: String Default: frontend_client Description: The name of the frontend image in AWS ECR ClusterName: Type: String Default: frontend-ecs-cluster Description: The name of the ECS cluster ServiceName: Type: String Default: frontend-ecs-service Description: The name of the ECS service DesiredCount: Type: Number Default: 1 Description: The number of tasks to run Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: "10.0.0.0/16" EnableDnsSupport: true EnableDnsHostnames: true Tags: - Key: Name Value: VPC PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: "10.0.1.0/24" MapPublicIpOnLaunch: true AvailabilityZone: !Select [0, !GetAZs ""] PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: "10.0.2.0/24" MapPublicIpOnLaunch: true AvailabilityZone: !Select [1, !GetAZs ""] InternetGateway: Type: AWS::EC2::InternetGateway AttachGateway: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC PublicRoute: Type: AWS::EC2::Route DependsOn: AttachGateway Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet1 RouteTableId: !Ref PublicRouteTable PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnet2 RouteTableId: !Ref PublicRouteTable ALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 SecurityGroups: - !Ref ALBSecurityGroup Scheme: internet-facing Type: application TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: VpcId: !Ref VPC Protocol: HTTP Port: 80 TargetType: ip HealthCheckPath: /health HealthCheckPort: 80 ALBListenerRule: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - Type: forward TargetGroupArn: !Ref TargetGroup Conditions: - Field: path-pattern Values: - /* ListenerArn: !Ref ALBListener Priority: 1 ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref TargetGroup LoadBalancerArn: !Ref ALB Port: 80 Protocol: HTTP ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for ALB VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 FrontendLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/ecs/${ServiceName}" ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref ClusterName FrontendTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Ref ServiceName Cpu: "256" Memory: "512" NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ExecutionRoleArn: !GetAtt FrontendTaskExecutionRole.Arn ContainerDefinitions: - Name: frontend Image: !Join - "" - - !Ref "AWS::AccountId" - ".dkr.ecr." - !Ref "AWS::Region" - ".amazonaws.com/" - !Ref FrontendImageName - ":latest" Essential: true PortMappings: - ContainerPort: 80 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref FrontendLogGroup awslogs-region: !Ref "AWS::Region" awslogs-stream-prefix: frontend ECSServiceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for ECS Service VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref ALBSecurityGroup FrontendService: Type: AWS::ECS::Service DependsOn: - ALB - ECSServiceSecurityGroup Properties: Cluster: !Ref ECSCluster ServiceName: !Ref ServiceName TaskDefinition: !Ref FrontendTaskDefinition DesiredCount: !Ref DesiredCount LaunchType: FARGATE LoadBalancers: - ContainerName: frontend ContainerPort: 80 TargetGroupArn: !Ref TargetGroup NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - !Ref ECSServiceSecurityGroup Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 FrontendTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - ecs-tasks.amazonaws.com Action: "sts:AssumeRole" Policies: - PolicyName: FrontendTaskExecutionRolePolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - ecr:GetAuthorizationToken - ecr:BatchCheckLayerAvailability - ecr:GetDownloadUrlForLayer - ecr:BatchGetImage Resource: "*" - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: !GetAtt FrontendLogGroup.Arn
Nginx配置
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s; server { listen 80; server_name localhost; location /health { access_log off; return 200 "OK\n"; } location / { limit_req zone=mylimit burst=20 nodelay; root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } location /latest { return 403; } location /api/latest { return 403; } }
Dockerfile
# Stage 1: Build React App FROM node:alpine AS build WORKDIR /app COPY package*.json ./ RUN npm install --production COPY . . RUN npm run build # Stage 2: Serve React App with Nginx FROM nginx:alpine COPY --from=build /app/build /usr/share/nginx/html COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
解决建议
修复Nginx的server_name配置:
当前Nginx配置的server_name localhost会导致ALB发起的健康检查请求(Host头为容器IP或内部主机名)无法匹配该server块,返回404触发健康检查失败。将server_name改为_(匹配任意主机名)或者直接删除该字段:server { listen 80; server_name _; # 替换原localhost location /health { access_log off; return 200 "OK\n"; } # 其余配置保持不变 }添加ECS服务安全组的出站规则:
当前ECSServiceSecurityGroup仅配置了入站规则,没有允许出站流量,可能导致容器无法正常初始化(比如DNS解析、依赖资源拉取等)。添加全量出站规则:ECSServiceSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Security group for ECS Service VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref ALBSecurityGroup SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0调整CloudFormation服务的依赖关系:
确保ECS服务在ALB监听器和目标组完全创建后再启动,避免因依赖未就绪导致注册失败。修改FrontendService的DependsOn:FrontendService: Type: AWS::ECS::Service DependsOn: - ALB - ALBListener - TargetGroup - ECSServiceSecurityGroup修复日志流配置(辅助排查):
放宽日志权限以便查看容器启动日志,帮助定位问题。修改FrontendTaskExecutionRole的日志权限资源:- Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: "arn:aws:logs:*:*:*"验证ECR镜像状态:
确认ECR中存在指定名称的镜像,且latest标签正确,同时检查任务执行角色的ECR拉取权限是否正常。
内容的提问来源于stack exchange,提问作者Steven K
相关产品推荐
相关产品推荐

