将 ECS 服务转换为 cloudformation

Translate ECS service to cloudformation

我正在尝试将手动创建的服务转换为 cloudformation 模板,但我不断收到错误。

已经使用 UI 创建了任务定义,因为它需要一些特定角色

这个模板给我:Classic Load Balancers are not supported with Fargate

  ServicesSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for cluster services
      VpcId: !Ref 'VPC'
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          SourceSecurityGroupId: !Ref "PublicLoadBalancerSG"

  ServiceStaging:
    Type: AWS::ECS::Service
    Properties:
      ServiceName: pouch-svc-staging
      TaskDefinition: pouch-td-staging:4
      Cluster: !Ref 'ClusterECS'
      DesiredCount: 2
      SchedulingStrategy: REPLICA
      LaunchType: FARGATE
      EnableECSManagedTags: true
      DeploymentConfiguration:
        MinimumHealthyPercent: 100
        MaximumPercent: 200
        DeploymentCircuitBreaker:
          Enable: false
          Rollback: false
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          Subnets:
            - !Ref PublicSubnetOne
            - !Ref PublicSubnetTwo
          SecurityGroups:
            - !Ref ServicesSG
      LoadBalancers:
        - ContainerName: pouch-image-staging
          LoadBalancerName: !Ref 'LoadBalancerName'
          ContainerPort: 3100

更新:这是修改后的完整 cloudformation 模板,没有一些评论明确指出的负载均衡器名称

AWSTemplateFormatVersion: '2010-09-09'
Description: VPC, subnets and external, public facing load balancer, for forwarding public traffic to containers
Parameters:
  LoadBalancerName:
    Type: String
    Default: pouch-api-elb
  ClusterName:
    Type: String
    Default: pouch-api-cluster

Mappings:
  SubnetConfig:
    VPC:
      CIDR: '172.16.0.0/16'
    PublicOne:
      CIDR: '172.16.0.0/24'
    PublicTwo:
      CIDR: '172.16.1.0/24'

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']

  PublicSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
      MapPublicIpOnLaunch: true
  PublicSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
      MapPublicIpOnLaunch: true

  InternetGateway:
    Type: AWS::EC2::InternetGateway
  GatewayAttachement:
    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: GatewayAttachement
    Properties:
      RouteTableId: !Ref 'PublicRouteTable'
      DestinationCidrBlock: '0.0.0.0/0'
      GatewayId: !Ref 'InternetGateway'
  PublicSubnetOneRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetOne
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetTwoRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetTwo
      RouteTableId: !Ref PublicRouteTable

  PublicLoadBalancerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the public facing load balancer
      VpcId: !Ref 'VPC'
      SecurityGroupIngress:
        - CidrIp: 0.0.0.0/0
          IpProtocol: -1
  PublicLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Ref 'LoadBalancerName'
      Scheme: internet-facing
      LoadBalancerAttributes:
        - Key: idle_timeout.timeout_seconds
          Value: "30"
      Subnets:
        - !Ref PublicSubnetOne
        - !Ref PublicSubnetTwo
      SecurityGroups: [!Ref "PublicLoadBalancerSG"]

  TargetGroupStaging:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 6
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      Port: 80
      Protocol: HTTP
      TargetType: ip
      UnhealthyThresholdCount: 2
      VpcId: !Ref 'VPC'
  TargetGroupProduction:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 6
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      Port: 80
      Protocol: HTTP
      TargetType: ip
      UnhealthyThresholdCount: 2
      VpcId: !Ref 'VPC'

  ListenerRuleProduction:
    Type: "AWS::ElasticLoadBalancingV2::ListenerRule"
    Properties:
      Actions:
        - Type: forward
          TargetGroupArn: !Ref "TargetGroupProduction"
      Conditions:
        - Field: path-pattern
          PathPatternConfig:
            Values:
              - /production/*
      ListenerArn: !Ref PublicLoadBalancerListener
      Priority: 100
  ListenerRuleStaging:
    Type: "AWS::ElasticLoadBalancingV2::ListenerRule"
    Properties:
      Actions:
        - Type: forward
          TargetGroupArn: !Ref "TargetGroupStaging"
      Conditions:
        - Field: path-pattern
          PathPatternConfig:
            Values:
              - /staging/*
      ListenerArn: !Ref PublicLoadBalancerListener
      Priority: 50

  PublicLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: "redirect"
          RedirectConfig:
            Protocol: "#{protocol}"
            Port: "#{port}"
            Host: "#{host}"
            Path: "/production/"
            StatusCode: "HTTP_301"
      LoadBalancerArn: !Ref "PublicLoadBalancer"
      Port: 80
      Protocol: HTTP

  ClusterECS:
    Type: AWS::ECS::Cluster
    DependsOn: PublicLoadBalancerListener
    Properties:
      ClusterName: !Ref 'ClusterName'
      CapacityProviders:
        - FARGATE

  ServicesSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for cluster services
      VpcId: !Ref 'VPC'
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          SourceSecurityGroupId: !Ref "PublicLoadBalancerSG"

  ServiceStaging:
    Type: AWS::ECS::Service
    Properties:
      ServiceName: pouch-svc-staging
      TaskDefinition: pouch-td-staging:4
      Cluster: !Ref 'ClusterECS'
      DesiredCount: 2
      SchedulingStrategy: REPLICA
      LaunchType: FARGATE
      EnableECSManagedTags: true
      DeploymentConfiguration:
        MinimumHealthyPercent: 100
        MaximumPercent: 200
        DeploymentCircuitBreaker:
          Enable: false
          Rollback: false
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          Subnets:
            - !Ref PublicSubnetOne
            - !Ref PublicSubnetTwo
          SecurityGroups:
            - !Ref ServicesSG
      LoadBalancers:
        - ContainerName: pouch-image-staging
          TargetGroupArn: !Ref 'TargetGroupStaging'
          ContainerPort: 3100
  ServiceProduction:
    Type: AWS::ECS::Service
    Properties:
      ServiceName: pouch-svc-production
      TaskDefinition: pouch-td-production:4
      Cluster: !Ref 'ClusterECS'
      DesiredCount: 2
      SchedulingStrategy: REPLICA
      LaunchType: FARGATE
      EnableECSManagedTags: true
      DeploymentConfiguration:
        MinimumHealthyPercent: 100
        MaximumPercent: 200
        DeploymentCircuitBreaker:
          Enable: false
          Rollback: false
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          Subnets:
            - !Ref PublicSubnetOne
            - !Ref PublicSubnetTwo
          SecurityGroups:
            - !Ref ServicesSG
      LoadBalancers:
        - ContainerName: pouch-image-production
          TargetGroupArn: !Ref 'TargetGroupProduction'
          ContainerPort: 3100

Outputs:
  VpcId:
    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'
  PublicSubnetOne:
    Description: Public subnet one
    Value: !Ref 'PublicSubnetOne'
  PublicSubnetTwo:
    Description: Public subnet two
    Value: !Ref 'PublicSubnetTwo'
  ExternalUrl:
    Description: The url of the external load balancer
    Value: !Sub http://${PublicLoadBalancer.DNSName}

现在我收到“带有 targetGroupArn arn:aws:elasticloadbalancing 的目标组:...:targetgroup/pouch-Targe-XFJ4AI7HCF6G/f2a665925da27326 没有关联的负载均衡器”

我还不能添加评论。我认为以下 link 可以帮助解决问题 Fargate 不支持 Classic Load Balancer

AWS Load Balancing multiple ports for an ECS Service with Fargate

来自官方AWS documentation:

负载均衡器名称 与 Amazon ECS 服务或任务集关联的负载均衡器的名称。

负载均衡器名称仅在使用 Classic Load Balancer 时指定。如果您使用的是应用程序负载均衡器或网络负载均衡器,则应省略负载均衡器名称参数。

这意味着您不应在 CloudFormation 模板中指定负载均衡器的名称,因为您使用的是 Fargate,因此,请勿使用经典负载均衡器。

此外,在您的位置,我会考虑使用 Former2 之类的东西。这是一个很棒的工具,可以为您生成 CloudFormation 模板。您可以扫描您的帐户,选择要为其创建模板的服务。不过,为了使用它,您需要一个访问密钥和一个秘密密钥,因此请考虑创建一个具有只读权限的 IAM 用户。

编辑以涵盖有关目标组的第二个错误:

The Amazon ECS service requires an explicit dependency on the Application Load Balancer listener rule and the Application Load Balancer listener. This prevents the service from starting before the listener is ready.

可能 AWS::ECS::Service 在将目标组添加到负载均衡器之前尝试附加到目标组。为了解决这个问题,您应该在您的服务中添加一个依赖项,如下所示:

Type: AWS::ECS::Service
DependsOn: Listener       # Add exact listener name, depending on the service
Properties:

这应该有助于解决问题。