AWS CloudFormation 无法使用 CodeDeploy blue/green 部署创建 Stack

AWS CloudFormation cannot create Stack using CodeDeploy blue/green deployments

我正在尝试使用 CloudFormation 和 ECS 服务部署新堆栈,使用 CodeDeploy 启动类型启用 blue/green 部署。

在通过 CloudFormation 执行 blue/green 部署的 User Guide 中,他们声明如下:

To enable CloudFormation to perform blue/green deployments on a Stack, include the following information in its stack template:

At least one of the ECS resources that will trigger a blue/green deployment if replaced during a stack update. Currently, those resources are AWS::ECS::TaskDefinition and AWS::ECS::TaskSet.

当我排除 AWS::ECS::TaskSet 时,堆栈创建失败并且我收到以下错误:

Transform AWS::CodeDeployBlueGreen failed with: Failed to transform template. 
ECSAttributes must include TaskSets in AWS::CodeDeploy::BlueGreen Hook

如果我添加 AWS::ECS::TaskSet,堆栈将无法创建并出现以下错误:

Resource handler returned message: 
"Invalid request provided: Amazon ECS does not support task set management on services where deployments 
are controlled by AWS CodeDeploy. 
(Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; 
Request ID: 61b8c146-3ae9-4bc2-ac5c-08a11e194f06; Proxy: null)" 
(RequestToken: 86a8a3a5-fe89-9939-15c2-45b08b28c3f3, HandlerErrorCode: InvalidRequest)

这些是我的堆栈模板的相关部分:

Transform:
  - AWS::CodeDeployBlueGreen

Hooks:
  CodeDeployBlueGreenHook:
    Type: AWS::CodeDeploy::BlueGreen
    Properties:
      ServiceRole: BlueGreenDeploymentRole
      Applications:
        - Target:
            Type: AWS::ECS::Service
            LogicalID: EcsService
          ECSAttributes:
            TaskDefinitions:
              - TaskDefinitionBlue
              - TaskDefinitionGreen
            TaskSets:
              - TaskSetBlue
              - TaskSetGreen
            TrafficRouting:
              ProdTrafficRoute:
                Type: AWS::ElasticLoadBalancingV2::Listener
                LogicalID: LoadBalancerListener
              TargetGroups:
                - TargetGroupBlue
                - TargetGroupGreen
      TrafficRoutingConfig:
        Type: TimeBasedLinear
        TimeBasedLinear:
          StepPercentage: 20
          BakeTimeMins: 10
      AdditionalOptions:
        TerminationWaitTimeInMinutes: 60

Resources:
  # IAM Role for blue/green deployments
  BlueGreenDeploymentRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: blue-green-deployment-role
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: codedeploy.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: BlueGreenDeploymentPolicy
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - codedeploy:Get*
                  - codedeploy:CreateCloudFormationDeployment
                Resource: '*'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSCodeDeployRoleForECS

  #########################
  # Load Balancer
  #########################

  # Application Load Balancer
  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      IpAddressType: ipv4
      Name: service-alb
      Scheme: internal
      Subnets:
        - !Ref SubnetOne
        - !Ref SubnetTwo
      SecurityGroups:
        - !Ref SecurityGroup

  # Load Balancer Listener
  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          ForwardConfig:
            TargetGroups:
              - TargetGroupArn: !Ref TargetGroupBlue
                Weight: 1
              - TargetGroupArn: !Ref TargetGroupGreen
                Weight: 1
      LoadBalancerArn: !Ref LoadBalancer
      Port: 8080
      Protocol: HTTP

  # Load Balancer Target Groups
  TargetGroupBlue:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${ServiceName}-blue
      TargetType: ip
      VpcId: !Ref Vpc
      Port: 8080
      Protocol: HTTP
      HealthCheckPort: 8080
      HealthCheckPath: /actuator/health

  TargetGroupGreen:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${ServiceName}-green
      TargetType: ip
      VpcId: !Ref Vpc
      Port: 8080
      Protocol: HTTP
      HealthCheckPort: 8080
      HealthCheckPath: /actuator/health

  #########################
  # ECS
  #########################

  # ECS Cluster
  Cluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Ref ServiceName

  # ECS Service
  EcsService:
    Type: AWS::ECS::Service
    DependsOn: LoadBalancerListener
    Properties:
      ServiceName: !Ref ServiceName
      Cluster: !Ref Cluster
      TaskDefinition: !Ref TaskDefinitionBlue
      DeploymentController:
        Type: CODE_DEPLOY
      DesiredCount: 0
      LaunchType: FARGATE
      LoadBalancers:
        - ContainerName: !Sub ${ServiceName}-container
          ContainerPort: 8080
          TargetGroupArn: !Ref TargetGroupBlue
        - ContainerName: !Sub ${ServiceName}-container
          ContainerPort: 8080
          TargetGroupArn: !Ref TargetGroupGreen
      NetworkConfiguration:
        AwsvpcConfiguration:
          Subnets:
            - !Ref SubnetOne
            - !Ref SubnetTwo
          SecurityGroups:
            - !Ref SecurityGroup
      SchedulingStrategy: REPLICA

  # Task Definitions
  TaskDefinitionBlue:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Name: !Sub ${ServiceName}-container
          Image: !Sub ${ImageRepository.RepositoryUri}:latest
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref LogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: payments
          PortMappings:
            - ContainerPort: 8080
      Cpu: 256
      Memory: 512
      NetworkMode: awsvpc
      Family: !Sub ${ServiceName}
      ExecutionRoleArn: !Ref TaskExecutionRole
      RequiresCompatibilities:
        - FARGATE

  TaskDefinitionGreen:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Name: !Sub ${ServiceName}-container
          Image: !Sub ${ImageRepository.RepositoryUri}:latest
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref LogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: payments
          PortMappings:
            - ContainerPort: 8080
      Cpu: 256
      Memory: 512
      NetworkMode: awsvpc
      Family: !Sub ${ServiceName}
      ExecutionRoleArn: !Ref TaskExecutionRole
      RequiresCompatibilities:
        - FARGATE

  # Image Repository
  ImageRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: !Sub ${ServiceName}
      LifecyclePolicy:
        LifecyclePolicyText: |
          {
            "rules": [
              {
                "rulePriority": 1,
                "description": "Maintain at most 25 images",
                "selection": {
                  "tagStatus": "untagged",
                  "countType": "imageCountMoreThan",
                  "countNumber": 25
                },
                "action": {
                  "type": "expire"
                }
              }
            ]
          }

  TaskSetBlue:
    Type: AWS::ECS::TaskSet
    Properties:
      Cluster: !Ref Cluster
      LaunchType: FARGATE
      Service: !Ref EcsService
      TaskDefinition: !Ref TaskDefinitionBlue
      NetworkConfiguration:
        AwsVpcConfiguration:
          Subnets:
            - !Ref SubnetOne
            - !Ref SubnetTwo
          SecurityGroups:
            - !Ref SecurityGroup
      LoadBalancers:
        - ContainerName: !Sub ${ServiceName}-container
          ContainerPort: 8080
          TargetGroupArn: !Ref TargetGroupBlue

如何更新我的模板以允许通过 CodeDeploy blue/green 部署策略?

G/B 使用 CFN 的部署是 EXTERNAL不是 CODE_DEPLOY。您的模板可能还有许多其他问题,但您当前的错误与使用错误 DeploymentController 有关。请研究 AWS 文档和示例:

确切地说,AWS 不支持 EC2/ASG 上的蓝绿部署...! 我刚刚发现的最简单的方法是使用 In-Place 方法创建部署组 && 然后手动将部署组配置从 In-place 更改为 Blue Green

或者您可以使用 lambda 函数,但自定义它有点困难

希望这对你有所帮助