The target group with targetGroupArn does not have associated load balancer error - amazon-ecs
I'm running two scripts, one that creates a cluster with the required resources, and then another script to create the tasks and service. The first script creates everything correctly, but when I run the second script to create the service and task, it gives the following error:
The target group with targetGroupArn arn:aws:elasticloadbalancing:ca-central-1:XXXXXXXXX:targetgroup/XXXXXXXXXXXXXXXXXXXXX does not have an associated load balancer. (Service: AmazonECS; Status Code: 400; Error Code: InvalidParameterException; Request ID: 3899fd23-3eee-473f-9914-453a8d669f14)
What am I doing wrong?
Script 1 to create cluster:
AWSTemplateFormatVersion: '2010-09-09'
Description: A stack for deploying containerized applications onto a cluster of EC2
hosts using Elastic Container Service. This stack runs containers on
hosts that are in a public VPC subnet, and includes a public facing load
balancer to register the services in.
Parameters:
DesiredCapacity:
Type: Number
Default: '3'
Description: Number of EC2 instances to launch in your ECS cluster.
MaxSize:
Type: Number
Default: '6'
Description: Maximum number of EC2 instances that can be launched in your ECS cluster.
ECSAMI:
Description: AMI ID
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id
InstanceType:
Description: EC2 instance type
Type: String
Default: t2.micro
AllowedValues: [t2.micro, t2.small, t2.medium, t2.large, m3.medium, m3.large,
m3.xlarge, m3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge,
c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge, c3.large, c3.xlarge,
c3.2xlarge, c3.4xlarge, c3.8xlarge, r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge,
r3.8xlarge, i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge]
ConstraintDescription: Please choose a valid instance type.
Mappings:
# Hard values for the subnet masks. These masks define
# the range of internal IP addresses that can be assigned.
# The VPC can have all IP's from 10.0.0.0 to 10.0.255.255
# There are two subnets which cover the ranges:
#
# 10.0.0.0 - 10.0.0.255
# 10.0.1.0 - 10.0.1.255
#
# If you need more IP addresses (perhaps you have so many
# instances that you run out) then you can customize these
# ranges to add more
SubnetConfig:
VPC:
CIDR: '10.0.0.0/16'
PublicOne:
CIDR: '10.0.0.0/24'
PublicTwo:
CIDR: '10.0.1.0/24'
Resources:
# VPC in which containers will be networked.
# It has two public subnets
# We distribute the subnets across the first two available subnets
# for the region, for high availability.
VPC:
Type: AWS::EC2::VPC
Properties:
EnableDnsSupport: true
EnableDnsHostnames: true
CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']
# Two public subnets, where containers can have public IP addresses
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
# Setup networking resources for the public subnets. Containers
# in the public subnets have public IP addresses and the routing table
# sends network traffic via the internet gateway.
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
# ECS Resources
ECSCluster:
Type: AWS::ECS::Cluster
# A security group for the EC2 hosts that will run the containers.
# Two rules, allowing network traffic from a public facing load
# balancer and from other hosts in the security group.
#
# Remove any of the following ingress rules that are not needed.
# If you want to make direct requests to a container using its
# public IP address you'll need to add a security group rule
# to allow traffic from all IP addresses.
EcsHostSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the ECS hosts that run containers
VpcId: !Ref 'VPC'
EcsSecurityGroupIngressFromPublicALB:
Type: AWS::EC2::SecurityGroupIngress
Properties:
Description: Ingress from the public ALB
GroupId: !Ref 'EcsHostSecurityGroup'
IpProtocol: -1
SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'
EcsSecurityGroupIngressFromSelf:
Type: AWS::EC2::SecurityGroupIngress
Properties:
Description: Ingress from other hosts in the same security group
GroupId: !Ref 'EcsHostSecurityGroup'
IpProtocol: -1
SourceSecurityGroupId: !Ref 'EcsHostSecurityGroup'
# Autoscaling group. This launches the actual EC2 instances that will register
# themselves as members of the cluster, and run the docker containers.
ECSAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier:
- !Ref PublicSubnetOne
- !Ref PublicSubnetTwo
LaunchConfigurationName: !Ref 'ContainerInstances'
MinSize: '1'
MaxSize: !Ref 'MaxSize'
DesiredCapacity: !Ref 'DesiredCapacity'
CreationPolicy:
ResourceSignal:
Timeout: PT15M
UpdatePolicy:
AutoScalingReplacingUpdate:
WillReplace: 'true'
ContainerInstances:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
ImageId: !Ref 'ECSAMI'
SecurityGroups: [!Ref 'EcsHostSecurityGroup']
InstanceType: !Ref 'InstanceType'
IamInstanceProfile: !Ref 'EC2InstanceProfile'
UserData:
Fn::Base64: !Sub |
#!/bin/bash -xe
echo ECS_CLUSTER=${ECSCluster} >> /etc/ecs/ecs.config
yum install -y aws-cfn-bootstrap
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region}
AutoscalingRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [application-autoscaling.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: service-autoscaling
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'application-autoscaling:*'
- 'cloudwatch:DescribeAlarms'
- 'cloudwatch:PutMetricAlarm'
- 'ecs:DescribeServices'
- 'ecs:UpdateService'
Resource: '*'
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles: [!Ref 'EC2Role']
# Role for the EC2 hosts. This allows the ECS agent on the EC2 hosts
# to communciate with the ECS control plane, as well as download the docker
# images from ECR to run on your host.
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ec2.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action:
- 'ecs:CreateCluster'
- 'ecs:DeregisterContainerInstance'
- 'ecs:DiscoverPollEndpoint'
- 'ecs:Poll'
- 'ecs:RegisterContainerInstance'
- 'ecs:StartTelemetrySession'
- 'ecs:Submit*'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
- 'ecr:GetAuthorizationToken'
- 'ecr:BatchGetImage'
- 'ecr:GetDownloadUrlForLayer'
Resource: '*'
# Load balancers for getting traffic to containers.
# This sample template creates one load balancer:
#
# - One public load balancer, hosted in public subnets that is accessible
# to the public, and is intended to route traffic to one or more public
# facing services.
# A public facing load balancer, this is used for accepting traffic from the public
# internet and directing it to public facing microservices
PublicLoadBalancerSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Access to the public facing load balancer
VpcId: !Ref 'VPC'
SecurityGroupIngress:
# Allow access to ALB from anywhere on the internet
- CidrIp: 0.0.0.0/0
IpProtocol: -1
PublicLoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
#LoadBalancerAttributes:
# - Key: idle_timeout.timeout_seconds
# Value: '30'
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
- !Ref PublicSubnetOne
- !Ref PublicSubnetTwo
#SecurityGroups: [!Ref 'PublicLoadBalancerSG']
Type: network
# A dummy target group is used to setup the ALB to just drop traffic
# initially, before any real service target groups have been added.
DummyTargetGroupPublic:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckIntervalSeconds: 10
#HealthCheckPath: /
HealthCheckProtocol: TCP
#HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
Name: !Join ['-', [!Ref 'AWS::StackName', 'drop-1']]
Port: 80
Protocol: TCP
UnhealthyThresholdCount: 2
VpcId: !Ref 'VPC'
PublicLoadBalancerListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn:
- PublicLoadBalancer
Properties:
DefaultActions:
- TargetGroupArn: !Ref 'DummyTargetGroupPublic'
Type: 'forward'
LoadBalancerArn: !Ref 'PublicLoadBalancer'
Port: 80
Protocol: TCP
# This is an IAM role which authorizes ECS to manage resources on your
# account on your behalf, such as updating your load balancer with the
# details of where your containers are, so that traffic can reach your
# containers.
ECSRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: [ecs.amazonaws.com]
Action: ['sts:AssumeRole']
Path: /
Policies:
- PolicyName: ecs-service
PolicyDocument:
Statement:
- Effect: Allow
Action:
# Rules which allow ECS to attach network interfaces to instances
# on your behalf in order for awsvpc networking mode to work right
- 'ec2:AttachNetworkInterface'
- 'ec2:CreateNetworkInterface'
- 'ec2:CreateNetworkInterfacePermission'
- 'ec2:DeleteNetworkInterface'
- 'ec2:DeleteNetworkInterfacePermission'
- 'ec2:Describe*'
- 'ec2:DetachNetworkInterface'
# Rules which allow ECS to update load balancers on your behalf
# with the information sabout how to send traffic to your containers
- 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'
- 'elasticloadbalancing:DeregisterTargets'
- 'elasticloadbalancing:Describe*'
- 'elasticloadbalancing:RegisterInstancesWithLoadBalancer'
- 'elasticloadbalancing:RegisterTargets'
Resource: '*'
These are the values output by the CloudFormation template. Be careful
about changing any of them, because of them are exported with specific
names so that the other task related CF templates can use them.
Outputs:
ClusterName:
Description: The name of the ECS cluster
Value: !Ref 'ECSCluster'
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ClusterName' ] ]
ExternalUrl:
Description: The url of the external load balancer
Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']]
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ExternalUrl' ] ]
ECSRole:
Description: The ARN of the ECS role
Value: !GetAtt 'ECSRole.Arn'
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSRole' ] ]
PublicListener:
Description: The ARN of the public load balancer's Listener
Value: !Ref PublicLoadBalancerListener
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicListener' ] ]
VPCId:
Description: The ID of the VPC that this stack is deployed in
Value: !Ref 'VPC'
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'VPCId' ] ]
PublicSubnetOne:
Description: Public subnet one
Value: !Ref 'PublicSubnetOne'
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetOne' ] ]
PublicSubnetTwo:
Description: Public subnet two
Value: !Ref 'PublicSubnetTwo'
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetTwo' ] ]
EcsHostSecurityGroup:
Description: A security group used to allow containers to receive traffic
Value: !Ref 'EcsHostSecurityGroup'
Export:
Name: !Join [ ':', [ !Ref 'AWS::StackName', 'EcsHostSecurityGroup' ] ]
Script 2 to create service and task:
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy a service into an ECS cluster behind a public load balancer.
Parameters:
StackName:
Type: String
Default: PublicNLBCluster2
Description: The name of the parent cluster stack that you created. Necessary
to locate and reference resources created by that stack.
ServiceName:
Type: String
Default: nginx
Description: A name for the service
ImageUrl:
Type: String
Default: nginx
Description: The url of a docker image that contains the application process that
will handle the traffic for this service
ContainerPort:
Type: Number
Default: 80
Description: What port number the application inside the docker container is binding to
ContainerCpu:
Type: Number
Default: 256
Description: How much CPU to give the container. 1024 is 1 CPU
ContainerMemory:
Type: Number
Default: 512
Description: How much memory in megabytes to give the container
Path:
Type: String
Default: "*"
Description: A path on the public load balancer that this service
should be connected to. Use * to send all load balancer
traffic to this service.
Priority:
Type: Number
Default: 1
Description: The priority for the routing rule added to the load balancer.
This only applies if your have multiple services which have been
assigned to different paths on the load balancer.
DesiredCount:
Type: Number
Default: 2
Description: How many copies of the service task to run
Role:
Type: String
Default: ""
Description: (Optional) An IAM role to give the service's containers if the code within needs to
access other AWS resources like S3 buckets, DynamoDB tables, etc
Conditions:
HasCustomRole: !Not [ !Equals [!Ref 'Role', ''] ]
Resources:
# The task definition. This is a simple metadata description of what
# container to run, and what resource requirements it has.
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Ref 'ServiceName'
Cpu: !Ref 'ContainerCpu'
Memory: !Ref 'ContainerMemory'
TaskRoleArn:
Fn::If:
- 'HasCustomRole'
- !Ref 'Role'
- !Ref "AWS::NoValue"
ContainerDefinitions:
- Name: !Ref 'ServiceName'
Cpu: !Ref 'ContainerCpu'
Memory: !Ref 'ContainerMemory'
Image: !Ref 'ImageUrl'
PortMappings:
- ContainerPort: !Ref 'ContainerPort'
# The service. The service is a resource which allows you to run multiple
# copies of a type of task, and gather up their logs and metrics, as well
# as monitor the number of running tasks and replace any that have crashed
Service:
Type: AWS::ECS::Service
DependsOn: PublicLoadBalancerListener
Properties:
ServiceName: !Ref 'ServiceName'
Cluster:
Fn::ImportValue:
!Join [':', [!Ref 'StackName', 'ClusterName']]
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 75
DesiredCount: !Ref 'DesiredCount'
TaskDefinition: !Ref 'TaskDefinition'
LoadBalancers:
- ContainerName: !Ref 'ServiceName'
ContainerPort: !Ref 'ContainerPort'
TargetGroupArn: !Ref 'TargetGroup'
# A target group. This is used for keeping track of all the tasks, and
# what IP addresses / port numbers they have. You can query it yourself,
# to use the addresses yourself, but most often this target group is just
# connected to an application load balancer, or network load balancer, so
# it can automatically distribute traffic across all the targets.
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Ref 'ServiceName'
Port: 80
Protocol: TCP
VpcId:
Fn::ImportValue:
!Join [':', [!Ref 'StackName', 'VPCId']]
Related
Creating blue green deployment in Cloud Formation (One Load Balancer 2 target groups
I am trying to create a cloudformation IaC for an app to do blue green deployment. It keep giving me The target group with targetGroupArn arn:aws:elasticloadbalancing:ap-xxx-9:000:targetgroup/master-tg-2 does not have an associated load balancer. I wonder where did I go wrong. I add a DependsOn the masterLB listener just as stated in this question. I also link up both target groups in the MasterECSServices The following is the cloudformation template MasterLBSG: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Access to the public facing load balancer VpcId: Fn::ImportValue: # TAS-dev:VPCId !Sub "${TasStackName}:VPCId" SecurityGroupIngress: - CidrIp: 0.0.0.0/0 IpProtocol: tcp FromPort: 8000 ToPort: 8000 MasterLB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: Master-Dev-LB Scheme: internet-facing LoadBalancerAttributes: - Key: idle_timeout.timeout_seconds Value: '30' Subnets: - !Sub "${StackName}:PublicSubnetOne" - !Sub "${StackName}:PublicSubnetTwo" SecurityGroups: [!Ref 'MasterLBSG'] MasterLBListener: Type: AWS::ElasticLoadBalancingV2::Listener DependsOn: - MasterLB Properties: DefaultActions: - TargetGroupArn: !Ref 'MasterTGOne' Type: 'forward' LoadBalancerArn: !Ref 'MasterLB' Port: 8000 Protocol: HTTP MasterTGOne: # Means MasterTargetGroupOne Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: master-tg-1 Port: 8000 Protocol: HTTP VpcId:"${TasStackName}:VPCId" TargetType: ip ## to be used as a spare TargetGroup for blue green deployment MasterTGTwo: # Means MasterTargetGroupOne Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: master-tg-2 Port: 8000 Protocol: HTTP VpcId:"${TasStackName}:VPCId" TargetType: ip MasterECSServices: Type: AWS::ECS::Service DependsOn: - MasterLBListener Properties: Cluster:"${TasStackName}:ClusterName" DeploymentController: Type: CODE_DEPLOY DesiredCount: 1 LaunchType: FARGATE LoadBalancers: - ContainerName: master-app ContainerPort: '8000' TargetGroupArn: !Ref 'MasterTGOne' - ContainerName: master-app ContainerPort: '8000' TargetGroupArn: !Ref 'MasterTGTwo' NetworkConfiguration: AwsvpcConfiguration: SecurityGroups: - !Ref MasterAppSG Subnets: - "${TasStackName}:PrivateSubnetOne" - "${TasStackName}:PrivateSubnetTwo" Role:"${TasStackName}:ECSRole" TaskDefinition: !Ref 'MasterTaskDef'
Update: Since May 19, 2020 AWS CloudFormation now supports blue/green deployments for Amazon ECS Before An example of a custom resource in CloudFormation which makes blue/green deployment for ECS. It uses crhelper: Lambda which creates blue/green deployment group for ECS (i.e. logic of your custom resource) import logging import json import boto3 from time import sleep from crhelper import CfnResource logger = logging.getLogger(__name__) # Initialise the helper, all inputs are optional, # this example shows the defaults helper = CfnResource(json_logging=False, log_level='DEBUG', boto_level='CRITICAL', sleep_on_delete=120) try: ## Init code goes here cd = boto3.client('codedeploy') pass except Exception as e: helper.init_failure(e) #helper.create def create(event, context): logger.info("Got Create") print(json.dumps(event)) application_name = event['ResourceProperties']['ApplicationName'] service_role_arn = event['ResourceProperties']['ServiceRoleArn'] cluster_name = event['ResourceProperties']['ClusterName'] service_name = event['ResourceProperties']['ServiceName'] elb_name = event['ResourceProperties']['ELBName'] tg1_name = event['ResourceProperties']['TG1Name'] tg2_name = event['ResourceProperties']['TG2Name'] listener_arn = event['ResourceProperties']['ListenerArn'] deployment_group_name = event['ResourceProperties']['GroupName'] deployment_style=event['ResourceProperties'].get( 'DeploymentStyle', 'BLUE_GREEN') response = cd.create_deployment_group( applicationName=application_name, deploymentGroupName=deployment_group_name, serviceRoleArn=service_role_arn, autoRollbackConfiguration={ 'enabled': True, 'events': ['DEPLOYMENT_FAILURE'] }, deploymentStyle={ 'deploymentType': deployment_style, 'deploymentOption': 'WITH_TRAFFIC_CONTROL' }, blueGreenDeploymentConfiguration={ "terminateBlueInstancesOnDeploymentSuccess": { "action": "TERMINATE", "terminationWaitTimeInMinutes": 0 }, "deploymentReadyOption": { "actionOnTimeout": "CONTINUE_DEPLOYMENT", "waitTimeInMinutes": 0 } }, loadBalancerInfo={ "targetGroupPairInfoList": [ { "targetGroups": [ {"name": tg1_name}, {"name": tg2_name} ], "prodTrafficRoute": { "listenerArns": [listener_arn] } } ] }, ecsServices=[ { "serviceName": service_name, "clusterName": cluster_name } ] ) print(response) helper.Data.update({"Name": deployment_group_name}) cd_group_id = response['deploymentGroupId'] return cd_group_id #helper.delete def delete(event, context): # Delete never returns anything. Should not fail if the # underlying resources are already deleted. # Desired state. logger.info("Got Delete") print(json.dumps(event)) try: application_name = event['ResourceProperties']['ApplicationName'] deployment_group_name = event['ResourceProperties']['GroupName'] response = cd.delete_deployment_group( applicationName=application_name, deploymentGroupName=deployment_group_name ) print(response) except Exception as e: print(str(e)) def handler(event, context): helper(event, context) Execute the lambda from CloudFomration Once you set up your lambda, then in CloudFormation you can use it as any other "normal" resource: MyUseCustomLambda: Type: Custom::CodeDeployCustomGroup Version: "1.0" Properties: Name: UseCustomLambda ServiceToken: !Ref CustomLambdaArn ApplicationName: !Ref ApplicationName ServiceRoleArn: !Ref ServiceRoleArn ELBName: !Ref ELBName TG1Name: !Ref TG1Name TG2Name: !Ref TG2Name GroupName: !Ref GroupName ClusterName: !Ref ClusterName ServiceName: !Ref ServiceName ListenerArn: !Ref ListenerArn DeploymentStyle: !Ref DeploymentStyle
CloudFormation doesn't receive signal from cfn-signal in non-default VPC
I have CloudFormation template with LaunchTemplate & ASG, When cfn-init completes deploy cfn-signal should send signal to CloudFormation with result. From /var/log/cfn-init.log I see that signal has been sent: ..and from /var/log/cfn-wire.log I see that it's been received successfully: ..but CloudFormation doesn't receive it and fails stack on timeout: Relevant piece of CloudFormation code: AWSTemplateFormatVersion: "2010-09-09" Parameters: VPC: Type: AWS::EC2::VPC::Id Default: "vpc-f98e0683" Subnet1: Type: String Default: "subnet-da88f186" KeyName: Type: String Default: "test-aws6-virginia" AMI: Type: AWS::EC2::Image::Id Default: "ami-07b4156579ea1d7ba" #Ubuntu 16.04 InstanceType: Type: String Default: "t2.micro" Az1: Type: AWS::EC2::AvailabilityZone::Name Default: "us-east-1a" Resources: SecurityGroup: Type: "AWS::EC2::SecurityGroup" Properties: GroupName: "SecurityGroup" GroupDescription: "Security Group" VpcId: !Ref VPC SecurityGroupEgress: - CidrIp: 0.0.0.0/0 IpProtocol: "-1" SecurityGroupIngress: - CidrIp: 0.0.0.0/0 IpProtocol: "-1" InstanceRole: Type: "AWS::IAM::Role" Properties: RoleName: "InstanceRole" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: - "ec2.amazonaws.com" Action: - "sts:AssumeRole" ManagedPolicyArns: - "arn:aws:iam::aws:policy/AdministratorAccess" InstanceProfile: Type: "AWS::IAM::InstanceProfile" Properties: Path: "/" Roles: - !Ref InstanceRole NetworkInterface: Type: "AWS::EC2::NetworkInterface" Properties: GroupSet: - !Ref SecurityGroup SubnetId: !Ref Subnet1 Tags: - Key: Name Value: "NetworkInterface" ZabbixLaunchTemplate: Type: "AWS::EC2::LaunchTemplate" Metadata: AWS::CloudFormation::Init: configSets: Zabbix: - 00-ZabbixInstall 00-ZabbixInstall: commands: download: command: "wget https://repo.zabbix.com/zabbix/4.0/ubuntu/pool/main/z/zabbix-release/zabbix-release_4.0-2+xenial_all.deb && dpkg -i zabbix-release_4.0-2+xenial_all.deb" update: command: "apt update" install: command: "apt -y install zabbix-server-pgsql zabbix-frontend-php php-pgsql zabbix-agent" services: sysvinit: zabbix-server: enabled: "true" ensureRunning: "true" zabbix-agent: enabled: "true" ensureRunning: "true" apache2: enabled: "true" ensureRunning: "true" Properties: LaunchTemplateName: "ZabbixLaunchTemplate" LaunchTemplateData: TagSpecifications: - ResourceType: "instance" Tags: - Key: Name Value: "Instance" - ResourceType: volume Tags: - Key: Name Value: "Instance" DisableApiTermination: false KeyName: !Ref KeyName ImageId: !Ref AMI InstanceType: !Ref InstanceType IamInstanceProfile: Name: !Ref InstanceProfile NetworkInterfaces: - NetworkInterfaceId: !Ref NetworkInterface DeviceIndex: 0 UserData: Fn::Base64: !Join - '' - - | #!/bin/bash - | - apt-get update -y && apt-get install python-pip -y && pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz - |+ - | - "cfn-init --verbose" - " --stack " - !Ref "AWS::StackName" - " --resource ZabbixLaunchTemplate" - " --configsets Zabbix" - " --region " - !Ref "AWS::Region" - |+ - | - "cfn-signal --exit-code $?" - " --stack " - !Ref "AWS::StackName" - " --resource ZabbixASG" - " --region " - !Ref "AWS::Region" - |+ ZabbixASG: Type: "AWS::AutoScaling::AutoScalingGroup" Properties: AutoScalingGroupName: "ZabbixASG" DesiredCapacity: "1" MaxSize: "1" MinSize: "1" HealthCheckType: "EC2" LaunchTemplate: LaunchTemplateId: !Ref ZabbixLaunchTemplate Version: !GetAtt ZabbixLaunchTemplate.LatestVersionNumber AvailabilityZones: - !Ref Az1 CreationPolicy: ResourceSignal: Timeout: PT15M It doesn't work only if it's deployed in non-default VPC, e.g. it doesn't work if VPC is created from this template: AWSTemplateFormatVersion: "2010-09-09" Parameters: VpcCIDR: Type: String Default: "172.29.0.0/16" Subnet1CIDR: Type: String Default: "172.29.1.0/24" Subnet2CIDR: Type: String Default: "172.29.2.0/24" Az1: Type: String Default: "us-west-2a" Az2: Type: String Default: "us-west-2c" Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCIDR EnableDnsHostnames: true EnableDnsSupport: true InstanceTenancy: default 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 Subnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Ref Subnet1CIDR AvailabilityZone: !Ref Az1 MapPublicIpOnLaunch: true Subnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC CidrBlock: !Ref Subnet2CIDR AvailabilityZone: !Ref Az2 MapPublicIpOnLaunch: true Subnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTable SubnetId: !Ref Subnet1 Subnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref RouteTable SubnetId: !Ref Subnet2 Route: Type: AWS::EC2::Route Properties: DestinationCidrBlock: "0.0.0.0/0" GatewayId: !Ref InternetGateway RouteTableId: !Ref RouteTable Outputs: VpcId: Value: !Ref VPC Subnet1Id: Value: !Ref Subnet1 Subnet2Id: Value: !Ref Subnet2 It is the same on both Ubuntu 16.04 and AWS Linux 2 Any ideas why and how to fix?
This one has me stumped! I have managed to reproduce your results both in a VPC created with your supplied template, and also in a VPC created by the VPC wizard. In such cases, CloudFormation does not recognize the completion of the ASG. When I tried sending the cfn-signal manually, it responded with: $ cfn-signal --exit-code 0 --stack s7 --resource ZabbixASG --region us-west-2 2019-06-20 23:13:24,571 [DEBUG] CloudFormation client initialized with endpoint https://cloudformation.us-west-2.amazonaws.com 2019-06-20 23:13:24,571 [DEBUG] Signaling resource ZabbixASG in stack s7 with unique ID i-07d2be90dc51c509a and status SUCCESS ValidationError: Signal with ID i-07d2be90dc51c509a for resource ZabbixASG already exists. Signals may only be updated with a FAILURE status. This indicates that the service has already received the signal, so it was sent correctly. However, the status of the ASG remains in Resource creation Initiated. Why the result would vary when using a Default VPC, I have no idea! There is no communication difference that would impact such a signal. The only thing I can suggest is contacting AWS Support and asking them to help debug.
Fargate error: cannot pull container hosted in ECR from a private subnet
I am trying to create a following architecture: a vpc with two subnets (one is public containing a NatGateway and an InternetGateway, and another one is private. I start a fargate service in a private subnet and it fails with this error: CannotPullContainerError: API error (500): Get https://XYZ.dkr.ecr.us-east-1.amazonaws.com/v2/: net/http: request cancelled while waiting for connection (Client.Timeout exceeded while awaiting headers) Here's my CloudFormation template (the service is intentionally commented out, and the ECR image url is scrambled): Resources: #Network resources: VPC WorkflowVpc: Type: AWS::EC2::VPC Properties: CidrBlock: "10.0.0.0/16" EnableDnsSupport: false Tags: - Key: Project Value: Workflow #PublicSubnet WorkflowPublicSubnet: Type: AWS::EC2::Subnet Properties: CidrBlock: "10.0.0.0/24" VpcId: Ref: WorkflowVpc WorkflowInternetGateway: Type: AWS::EC2::InternetGateway WorkflowVCPGatewayAttachment: DependsOn: - WorkflowInternetGateway - WorkflowVpc Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: Ref: WorkflowInternetGateway VpcId: Ref: WorkflowVpc WorkflowElasticIp: Type: AWS::EC2::EIP Properties: Domain: vpc WorkflowPublicSubnetRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: Ref: WorkflowVpc PublicSubnetToRouteTable: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: Ref: WorkflowPublicSubnetRouteTable SubnetId: Ref: WorkflowPublicSubnet WorkflowInternetRoute: Type: AWS::EC2::Route Properties: RouteTableId: Ref: WorkflowPublicSubnetRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: Ref: WorkflowInternetGateway WorkflowNat: DependsOn: - WorkflowVCPGatewayAttachment - WorkflowElasticIp Type: AWS::EC2::NatGateway Properties: AllocationId: Fn::GetAtt: - WorkflowElasticIp - AllocationId SubnetId: Ref: WorkflowPublicSubnet #Private subnet WorkflowPrivateSubnet: Type: AWS::EC2::Subnet Properties: CidrBlock: "10.0.1.0/24" VpcId: Ref: WorkflowVpc WorkflowPrivateSubnetRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: Ref: WorkflowVpc PrivateSubnetToRouteTable: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: Ref: WorkflowPrivateSubnetRouteTable SubnetId: Ref: WorkflowPrivateSubnet WorkflowNatRoute: Type: AWS::EC2::Route Properties: RouteTableId: Ref: WorkflowPrivateSubnetRouteTable DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: Ref: WorkflowNat #Fargate: WorkflowFargateTask: Type: AWS::ECS::TaskDefinition Properties: RequiresCompatibilities: - "FARGATE" Cpu: "256" Memory: "0.5GB" ContainerDefinitions: - Name: WorkflowFargateContainer Image: "XYZ.dkr.ecr.us-east-1.amazonaws.com/workflow:latest" NetworkMode: awsvpc ExecutionRoleArn: "arn:aws:iam::XXX:role/ecsTaskExecutionRole" WorkflowCluster: Type: AWS::ECS::Cluster Properties: ClusterName: WorkflowServiceCluster # WorkflowService: # DependsOn: # - WorkflowNatRoute # Type: AWS::ECS::Service # Properties: # Cluster: # Ref: WorkflowCluster # DesiredCount: 1 # TaskDefinition: # Ref: WorkflowFargateTask # NetworkConfiguration: # AwsvpcConfiguration: # AssignPublicIp: DISABLED # Subnets: # - Ref: WorkflowPrivateSubnet # LaunchType: FARGATE I also tried to set AssignPublicIp: ENABLED within the public subnet, and it works just fine, but it is not what I'm aiming for. So, the questions that I have: is my template ok and is it the problem of Fargate/ECR? Also, what would be the best way to debug such a behaviour? It seems that CloudWatch has no logs concerning this error...
Following Steve E's hints I've figured out that the internet access is present, the only problem is in this parameter for the VPC: EnableDnsSupport: false Naturally, when I tried to update linux packages, or ping google.com, it couldn't resolve the host names. Switching it to "true" resolved the problem.
AWS CloudFormation - AWS::ElasticLoadBalancingV2::LoadBalancer - SecurityGroups
Is there a possibility in CFN templates to add some specific Security Groups to ALB depending on the parameter? I have a situation where two security groups are adding to the ALB: ALB Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: ... SecurityGroups: - !Ref 'SecurityGroup1' - !Ref 'SecurityGroup2' Now there is a SecurityGroup3 that I would like to eventually add only if some parameter has a specific value. Let's say if parameter add_sg3 equals yes then the third SG is added to ALB. I always use "!If in similar situations but there are more than 2 SGs. Any advice would be welcome. Thanks!
You can achieve that using a Condition and the AWS::NoValue pseudo-parameter. Follow below a complete example: Parameters: Environment: Type: String Default: dev AllowedValues: ["dev", "prod"] VpcId: Type: 'AWS::EC2::VPC::Id' Subnet1: Type: 'AWS::EC2::Subnet::Id' Subnet2: Type: 'AWS::EC2::Subnet::Id' Conditions: MyTest: !Equals ["dev", !Ref Environment] Resources: ALB: Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer' Properties: SecurityGroups: - !Ref SecurityGroup1 - !If [ MyTest, !Ref SecurityGroup2, !Ref 'AWS::NoValue' ] Subnets: - !Ref Subnet1 - !Ref Subnet2 SecurityGroup1: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'Group 1' VpcId: !Ref VpcId SecurityGroup2: Type: 'AWS::EC2::SecurityGroup' Properties: GroupDescription: 'Group 2' VpcId: !Ref VpcId
create service using cloudformation in aws ecs fargate "did not stabilize"
AWSTemplateFormatVersion: "2010-09-09" Description: Not Have Any Idea Parameters: Service: Description: Service Name Type: String Cluster: Description: Cluster Name Type: String TaskDefinition: Description: TaskDefinition Name Type: String securitygroup: Description: securitygroup Type: AWS::EC2::SecurityGroup::Id SubnetId: Type: List<AWS::EC2::Subnet::Id> Description: Select at two subnets in your selected VPC. Resources: sernginx: Type: "AWS::ECS::Service" Properties: ServiceName: Ref: Service LaunchType: "FARGATE" DesiredCount: 1 Cluster: Ref: Cluster TaskDefinition: Ref: TaskDefinition DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 70 NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - Ref: securitygroup Subnets: Ref: SubnetId I am using this code to create aws ecs service fargate I am getting ROLLBACK_COMPLETE status with an error message saying Service arn:aws:ecs:us-east-1:439138162442:service/yuiyiuyiu did not stabilize
I've used this kind of template for creating fargate task. AWSTemplateFormatVersion: '2010-09-09' Description: Docker Core App service Parameters: EnvironmentName: Type: String Default: coreapp Description: A name for the environment that this cloudformation will be part of. ServiceName: Type: String Default: coreapi Description: A name for the service ImageUrl: Type: String Default: your_image_URI Description: The url of a docker image ContainerPort: Type: Number Default: 5000 Description: What port number the application inside the docker container ContainerCpu: Type: Number Default: 256 Description: How much CPU to give the container. ContainerMemory: Type: Number Default: 512 Description: How much memory in megabytes to give the container DesiredCount: Type: Number Default: 2 Description: How many copies of the service task to run Role: Type: String Default: "" Description: (Optional) An IAM role to give the service's containers Resources: Service: Type: AWS::ECS::Service Properties: ServiceName: !Ref 'ServiceName' Cluster: - coreapp LaunchType: FARGATE DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 75 DesiredCount: !Ref 'DesiredCount' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: ENABLED SecurityGroups: - sg-483aa03e Subnets: - subnet-2ce41866 - subnet-ceefe5aa TaskDefinition: !Ref 'TaskDefinition'