用于将 Nginx 映像部署到 ECS 的 CloudFormation 模板不起作用

问题描述 投票:0回答:1

我一直在尝试使用 CloudFormation 模板部署 React 前端应用程序,并且部署本身似乎可以正常工作,在本地 docker 中构建和运行的 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: 8080 
    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: 8080
                  LogConfiguration:
                      LogDriver: awslogs
                      Options:
                          awslogs-group: !Ref FrontendLogGroup
                          awslogs-region: !Ref "AWS::Region"
                          awslogs-stream-prefix: frontend
    FrontendService:
        Type: AWS::ECS::Service
        DependsOn: ALB
        Properties:
            Cluster: !Ref ECSCluster
            ServiceName: !Ref ServiceName
            TaskDefinition: !Ref FrontendTaskDefinition
            DesiredCount: !Ref DesiredCount
            LaunchType: FARGATE
            LoadBalancers:
                - ContainerName: frontend
                  ContainerPort: 8080
                  TargetGroupArn: !Ref TargetGroup
            NetworkConfiguration:
                AwsvpcConfiguration:
                    AssignPublicIp: ENABLED
                    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: "*"

以及 nginx 配置:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;

server {
    listen 8080;
    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 8080
CMD ["nginx", "-g", "daemon off;"]

任何建议表示赞赏。

我尝试更改 nginx 配置和模板上的端口号,以防发生冲突。但我无法弄清楚出了什么问题。

由于它在本地构建并工作,我希望它在从 ECR 构建时能够正常工作。

我也尝试过让日志流正常工作,但没有成功,但这不是主要问题。

docker nginx aws-cloudformation amazon-ecs
1个回答
0
投票

我立即看到两个问题:

  1. 您似乎没有为 ECS 服务分配安全组。这意味着该服务上的所有端口都将被阻止,并且 ALB/TargetGroup 将永远无法连接到该服务。您需要向 ECS 服务添加一个安全组,以允许来自负载均衡器的端口

    8080
    上的入站连接。

  2. 目标组为运行状况检查配置了正确的端口

    8080
    ,但也为所有其他流量配置了端口
    80
    。目标组上的两个端口配置都应为端口
    8080
    。这是您告诉目标组连接到您的 ECS 服务的端口,因此他们必须与您的 ECS 服务正在侦听的端口相匹配。


我尝试更改 nginx 配置和模板上的端口号,以防发生冲突。

这是在 Fargate 上运行的单个容器,因此这里不存在端口冲突的可能性。

© www.soinside.com 2019 - 2024. All rights reserved.