CI/CD 发布时,AWS ECS 计划任务不是 运行

AWS ECS Scheduled task not running when released by CI/CD

我遇到了一个非常烦人的问题。我使用 AWS CodePipeline 和 CloudFormation 创建了一个 CI/CD 管道。

这是 CloudFormation 用于在 ECS 上创建 ScheduledTask 的 template.yml。

AWSTemplateFormatVersion: "2010-09-09"
Description: Template for deploying a ECR image on ECS

Resources:
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: "10.0.0.0/16"
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default

  Subnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [0, !GetAZs ""]
      CidrBlock: !Sub "10.0.0.0/20"
      MapPublicIpOnLaunch: true

  Subnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      AvailabilityZone: !Select [1, !GetAZs ""]
      CidrBlock: !Sub "10.0.32.0/20"
      MapPublicIpOnLaunch: true

  InternetGateway:
    Type: "AWS::EC2::InternetGateway"

  VPCGatewayAttachment:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC

  RouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref VPC

  RouteTableAssociation1:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref Subnet1
      RouteTableId: !Ref RouteTable

  RouteTableAssociation2:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref Subnet2
      RouteTableId: !Ref RouteTable

  InternetRoute:
    Type: "AWS::EC2::Route"
    DependsOn: VPCGatewayAttachment
    Properties:
      GatewayId: !Ref InternetGateway
      RouteTableId: !Ref RouteTable
      DestinationCidrBlock: "0.0.0.0/0"

  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: "SLAComputation"

  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: ecs-services
      Subnets:
        - !Ref "Subnet1"
        - !Ref "Subnet2"
      SecurityGroups:
        - !Ref LoadBalancerSecurityGroup

  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Protocol: HTTP
      Port: 80
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref DefaultTargetGroup

  LoadBalancerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for loadbalancer to services on ECS
      VpcId: !Ref "VPC"
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1

  DefaultTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: default
      VpcId: !Ref "VPC"
      Protocol: "HTTP"
      Port: "80"

  CloudWatchLogsGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: "sla_computation"
      RetentionInDays: 1

  ContainerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      VpcId: !Ref "VPC"
      GroupDescription: for ecs containers
      SecurityGroupIngress:
        - SourceSecurityGroupId: !Ref "LoadBalancerSecurityGroup"
          IpProtocol: -1

  Task:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: apis
      Cpu: 1024
      Memory: 2048
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !Ref ECSTaskExecutionRole
      ContainerDefinitions:
        - Name: ass001
          Image: !Sub 649905970782.dkr.ecr.eu-west-1.amazonaws.com/ass001:latest
          Cpu: 1024
          Memory: 2048
          HealthCheck:
            Command: [ "CMD-SHELL", "exit 0" ]
            Interval: 30
            Retries: 5
            Timeout: 10
            StartPeriod: 30
          PortMappings:
            - ContainerPort: 8080
              Protocol: tcp
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: "sla_computation"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: "ass001"

  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: employee-tg
      VpcId: !Ref VPC
      Port: 80
      Protocol: HTTP
      Matcher:
        HttpCode: 200-299
      TargetType: ip

  ListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      ListenerArn: !Ref LoadBalancerListener
      Priority: 2
      Conditions:
        - Field: path-pattern
          Values:
            - /*
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward

  ECSTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: [ecs-tasks.amazonaws.com]
            Action: ["sts:AssumeRole"]
      Path: /
      Policies:
        - PolicyName: AmazonECSTaskExecutionRolePolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  # ECS Tasks to download images from ECR
                  - "ecr:GetAuthorizationToken"
                  - "ecr:BatchCheckLayerAvailability"
                  - "ecr:GetDownloadUrlForLayer"
                  - "ecr:BatchGetImage"
                  # ECS tasks to upload logs to CloudWatch
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                Resource: "*"

  TaskSchedule:
    Type: AWS::Events::Rule
    Properties:
      Description: SLA rule ass001
      Name: ass001
      ScheduleExpression: cron(0/5 * * * ? *)
      State: ENABLED
      Targets:
        - Arn:
            !GetAtt ECSCluster.Arn
          Id: dump-data-ecs-task
          RoleArn:
            !GetAtt ECSTaskExecutionRole.Arn
          EcsParameters:
            TaskDefinitionArn:
              !Ref Task
            TaskCount: 1
            LaunchType: FARGATE
            PlatformVersion: LATEST
            NetworkConfiguration:
              AwsVpcConfiguration:
                AssignPublicIp: ENABLED
                SecurityGroups: 
                  - sg-07db5ae6616a8c5fc
                Subnets: 
                  - subnet-031d0787ad492c1c4

  TaskSchedule:
    Type: AWS::Events::Rule
    Properties:
      Description: SLA rule ass002
      Name: ass002
      ScheduleExpression: cron(0/5 * * * ? *)
      State: ENABLED
      Targets:
        - Arn:
            !GetAtt ECSCluster.Arn
          Id: dump-data-ecs-task
          RoleArn:
            !GetAtt ECSTaskExecutionRole.Arn
          EcsParameters:
            TaskDefinitionArn:
              !Ref Task
            TaskCount: 1
            LaunchType: FARGATE
            PlatformVersion: LATEST
            NetworkConfiguration:
              AwsVpcConfiguration:
                AssignPublicIp: ENABLED
                SecurityGroups:
                  - sg-07db5ae6616a8c5fc
                Subnets:
                  - subnet-031d0787ad492c1c4

Outputs:
  ApiEndpoint:
    Description: Employee API Endpoint
    Value: !Join ["", ["http://", !GetAtt LoadBalancer.DNSName, "/employees"]]
    Export:
      Name: "EmployeeApiEndpoint"

已成功创建 ScheduledTask 但实际上不是 运行。很奇怪。但最奇怪的是,当我从 AWS 控制台单击“编辑”并且(不做任何更改)我保存时,ScheduledTask 开始工作。

我看到的主要问题是您为预定规则使用了错误的角色。不可能是!GetAtt ECSTaskExecutionRole.Arn。相反,您应该创建具有 AmazonEC2ContainerServiceEventsRole AWS 托管策略的新角色(或编辑现有角色)。

它在您在控制台中编辑后起作用,因为 AWS 控制台可能会在后台创建正确的角色并使用它代替您的角色。