I am creating a cloudformation nestedDeployment(CodeBuild Project and CodeDeploy Application) with a Blue/Green Deployment, for an ECS (Fargate Managed) Deployment. The Deployment fails in the creation of the CodeDeployment Group with this error:
"The list of target group pairs must have exactly one pair (Service: AmazonCodeDeploy; Status Code: 400; Error Code: InvalidTargetGroupPairException; Request ID: xxxxxx)"
My nested Deployment has an alb and the ouputs are seen in this deployment as importvalues, the output values are - ECSTargetGroup1Name, ECSTargetGroup1Name (With the export from the alb as - Value: !GetAtt ECSTargetGroup1.TargetGroupName and Value: !GetAtt ECSTargetGroup2.TargetGroupName). Same applies for the ECS ClusterName with its output-export in it's yaml file.
My two cents in understanding this error is suggesting i may have declared wrongly the target groups in the TargetGroupPairInfoList.
Any help with this will be appreciated.
ALB Code is as follows:
# 4. ECS Target Group
ECSTargetGroup1:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 20
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Name: !Sub ${EnvironmentName}-${ServiceName1}-1
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-${ServiceName1}-1
TargetType: ip
UnhealthyThresholdCount: 4
VpcId: !ImportValue VpcId
ECSTargetGroup2:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 20
HealthCheckPath: /healtchcheck
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 4
Name: !Sub ${EnvironmentName}-${ServiceName1}-2
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${EnvironmentName}-${ServiceName1}-2
TargetType: ip
UnhealthyThresholdCount: 4
VpcId: !ImportValue VpcId
# 1. Load Balancer
PublicLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub ${EnvironmentName}
Scheme: internet-facing
SecurityGroups: [!ImportValue PublicLoadBalancerSG]
Subnets:
# The load balancer is placed into the public subnets, so that traffic
# from the internet can reach the load balancer directly via the internet gateway
- !ImportValue PublicSubnet1a
- !ImportValue PublicSubnet1b
- !ImportValue PublicSubnet1c
Tags:
- Key: Name
Value: !Sub ${EnvironmentName} PublicLoadBalancer
# 3. Load Balancer Listener
80Listener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions: # Required
- Type: redirect
RedirectConfig:
Host: "#{host}"
Path: "/#{path}"
Port: "443"
Protocol: HTTPS
Query: "#{query}"
StatusCode: HTTP_301
LoadBalancerArn: !Ref PublicLoadBalancer # Required
Port: 80
Protocol: HTTP
ProductionListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
# Certificates:
# - CertificateArn: !Ref Certificate
DefaultActions: # Required
- TargetGroupArn: !Ref ECSTargetGroup2
Type: forward
LoadBalancerArn: !Ref PublicLoadBalancer # Required
Port: 443
Protocol: HTTP
TestListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
# Certificates:
# - CertificateArn: !Ref Certificate
DefaultActions: # Required
- TargetGroupArn: !Ref ECSTargetGroup1
Type: forward
LoadBalancerArn: !Ref PublicLoadBalancer # Required
Port: 8443
Protocol: HTTP
# 5. Load Balancer Listener Rule
80ListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions: # Required
- Type: redirect
RedirectConfig:
Host: "#{host}"
Path: "/#{path}"
Port: "443"
Protocol: HTTPS
Query: "#{query}"
StatusCode: HTTP_301
Conditions: # Required
- Field: path-pattern
Values: [!Ref 'Path']
ListenerArn: !Ref 80Listener # Required
Priority: 1 # Required
ProductionListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions: # Required
- TargetGroupArn: !Ref ECSTargetGroup2
Type: forward
Conditions: # Required
- Field: path-pattern
Values: [!Ref 'Path']
ListenerArn: !Ref ProductionListener # Required
Priority: 1 # Required
TestListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions: # Required
- TargetGroupArn: !Ref ECSTargetGroup1
Type: forward
Conditions: # Required
- Field: path-pattern
Values: [!Ref 'Path']
ListenerArn: !Ref TestListener # Required
Priority: 1 # Required
An excerpt of my code is this,
Resources:
CodeBuildApplication1:
Type: AWS::CodeBuild::Project
Properties:
Artifacts:
Type: CODEPIPELINE
BadgeEnabled: false
Description: !Sub "Build image for ${EnvironmentName} ${ServiceName1}"
Environment:
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/amazonlinux2-x86_64-standard:4.0
ImagePullCredentialsType: CODEBUILD
PrivilegedMode: true
Type: LINUX_CONTAINER
Name: !Sub "${EnvironmentName}-${ServiceName1}-build-image"
QueuedTimeoutInMinutes: 480
ServiceRole: !ImportValue CodeBuildService1RoleArn # Required
Source:
BuildSpec: codePipeline/ecs-image.yml
Type: CODEPIPELINE
TimeoutInMinutes: 60
CodeDeployApplication1:
Type: AWS::CodeDeploy::Application
Properties:
ApplicationName: !Sub "AppECS-${EnvironmentName}-${ServiceName1}svc"
ComputePlatform: ECS
CodeDeployGroup1:
Type: AWS::CodeDeploy::DeploymentGroup
Properties:
ApplicationName: !Ref CodeDeployApplication1 # Required
AutoRollbackConfiguration:
Enabled: true
Events:
- DEPLOYMENT_FAILURE
- DEPLOYMENT_STOP_ON_REQUEST
# AutoScalingGroups:
# AutoScalingGroups
BlueGreenDeploymentConfiguration:
DeploymentReadyOption:
ActionOnTimeout: CONTINUE_DEPLOYMENT
WaitTimeInMinutes: 0
# GreenFleetProvisioningOption:
# Action: DISCOVER_EXISTING
TerminateBlueInstancesOnDeploymentSuccess:
Action: TERMINATE
TerminationWaitTimeInMinutes: 60
# Deployment:
# Description: "String"
# IgnoreApplicationStopFailures: false
DeploymentConfigName: CodeDeployDefault.AllAtOnce
DeploymentGroupName: !Sub "DgpECS-${EnvironmentName}-${ServiceName1}svc"
DeploymentStyle:
DeploymentOption: WITH_TRAFFIC_CONTROL
DeploymentType: BLUE_GREEN
ECSServices:
- ClusterName: !ImportValue ECSCluster1Name
ServiceName: !ImportValue ECSService1Cluster1Name
LoadBalancerInfo:
# ElbInfoList:
# - Name: !ImportValue PublicLoadBalancer
# TargetGroupInfoList:
TargetGroupPairInfoList:
- ProdTrafficRoute:
ListenerArns:
- !ImportValue ProductionListener
- TestTrafficRoute:
ListenerArns:
- !ImportValue TestListener
- TargetGroups:
- Name: !ImportValue ECSTargetGroup1Name
- Name: !ImportValue ECSTargetGroup2Name
ServiceRoleArn: !ImportValue CodeDeployServiceRoleArn # Required
I have tried to comment out one target group and use the TargetGroupInfoList, but AWS requires a pair of Target Groups so need to use the TargetGroupPairInfoList.
Checked my alb infrastructure to confirm the targetgroup relationship to the listeners and that section looks good, with my ECS Cluster being created and tasks running.
CodePudding user response:
I think you have too many -
characters in the TargetGroupPairInfoList
section. You are creating a new list item with each -
when you should really only have a single -
indicating a single TargetGroupPairInfo
item, like this:
TargetGroupPairInfoList:
- ProdTrafficRoute:
ListenerArns:
- !ImportValue ProductionListener
TestTrafficRoute:
ListenerArns:
- !ImportValue TestListener
TargetGroups:
- Name: !ImportValue ECSTargetGroup1Name
- Name: !ImportValue ECSTargetGroup2Name