I have a Cloudformation that creates a AWS Fargate on ECS Cluster, in this way:
TaskDefinition:
Type: 'AWS::ECS::TaskDefinition'
Properties:
RequiresCompatibilities:
- FARGATE
Cpu: !Ref ContainerCpu
Memory: !Ref ContainerMemory
ExecutionRoleArn: !Ref ExecutionRole
TaskRoleArn: !Ref ExecutionRole
ContainerDefinitions:
- Name: !Sub ${ContainerName}
Image: 'image-url-here'
Essential: true
HealthCheck:
Command: ["CMD-SHELL", "test -f hc.log"]
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Sub '${AWS::Region}'
awslogs-group: !Sub '${FeatureName}-${MicroServiceName}'
awslogs-stream-prefix: !Ref MicroServiceName
Family: !Sub 'family-${FeatureName}-${MicroServiceName}'
NetworkMode: awsvpc
DependsOn: CloudWatchLogGroup
ExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Join ['', [!Ref MicroServiceName, ExecutionRole]]
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy'
My ECS Task Fargate need to access a API that is running in a EC2 , so I created a DNS Private Hosted Zone with the following address: api.localaccount. But when I try to access this API from my Fargate i got the following error:
System.Net.Http.HttpRequestException: Name or service not known
I know that this error is because my AWS Fargate can't resolve DNS, but I don't know why. If I access this same DNS (api.localaccount) from EC2 everything works fine, so I think my DNS Route 53 is ok.
Based on the comments.
The issue was due to the use of a wrong link in the application. Thus, it was application-level problem, not ECS Farage issue.
To use private hosted zones, you must set the following Amazon VPC settings to true:
enableDnsHostnames
enableDnsSupport
ECS Service by default can't resolve DNS. You have to explicitly enable it during service creation part. Once you enable it, you have option to select the Namespace and record type.
*All of this should be done after setting up Route53 and VPC config. In this case you've already done those.
Related
so I am tring to create Fargate instances into subnets using cloudformation.
I would like the user to be able to choose which vpc id, subnet ids to launch their Fargate instances into which I use as a parameter like this:
Parameters:
VPCSubnets:
Type: List<AWS::EC2::Subnet::Id>
Description: Provide the subnets you wish to deploy into.
VPCInformation:
Type: AWS::EC2::VPC::Id
Description: Provide the VPC ID that resources will be deployed into.
this information is used for the network settings for ECS and task definitions.
If I create network resouces just below parameters like this:
for example:
MyVpc:
Type: AWS::EC2::VPC
Description: VPC for the cluster and fargate instances
Properties:
CidrBlock: 10.0.0.0/26
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: interviewchallenge-vpc
Value: !Join ['', [!Ref "AWS::Region", "conversion-challenge-VPC" ]]
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId:
Ref: myVPC
CidrBlock: 10.0.0.0/28
AvailabilityZone: "us-east-1a"
Tags:
- Key: interviewchallenge-vpc-subnet1
Value: !Join ['', [!Ref "AWS::Region", "conversion-challenge-az1" ]]
At this point in the template, these network resouces havent been created right?
Can this be done in a single stack??
Can this be done in a single stack??
No. You need two templates and the corresponding stacks. The first template creates VPC, subnets and the remaining network resources. Then in the second stack, you use them in for ECS deployment.
Only this way your user will be able to choose the VPC and subnets when creating the ECS stack.
My Cloudformation YAML for autoscaling group keeps creating EC2 instances in default VPC even after I specify a custom VPC. Here's the snippets of code:
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Port: 80
Protocol: HTTP
VpcId: !Ref VpcId
Parameters section:
VpcId:
Description: Enter the VpcId
Type: AWS::EC2::VPC::Id
Default: vpc-0ed238eeecc11b493
I keep seeing termination of EC2 instances because the launch config is for some reason creating the instances in the default VPC even through I have specified to use the custom in the parameters section. I dont know why it is not taking the custom VPC. When I check security groups, launch config in the AWS console it shows the custom VPC but when I check the EC2 instance launched by the auto scaling group, I see the default VPC.
My default VPC is vpc-6a79470d and my custom VPC is vpc-0ed238eeecc11b493
The error I see in the Autoscaling group section of the console is:
Description:DescriptionLaunching a new EC2 instance: i-041b680f6470379e3.
Status Reason: Failed to update target group arn:aws:elasticloadbalancing:us-west-1:targetgroup/ALBTe-Targe-7DMLWW46T1E6/f74a31d17bf3c4dc:
The following targets are not in the target group VPC 'vpc-0ed238eeecc11b493': 'i-041b680f6470379e3' Updating load balancer configuration failed.
Hope someone can help point out what I am doing wrong. I see in AWS documentation that ASG by default launches in default VPC but there must be a way to do it in CloudFormation if it is possible to do it through console.
=============================== After update==========================
Here's how it looks now after adding VPCZoneIdentifier, not sure what I am doing wrong and getting an issue with security group now
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
AvailabilityZones: !GetAZs
VPCZoneIdentifier: !Ref SubnetIds
LaunchConfigurationName: !Ref LaunchConfiguration
MinSize: 1
MaxSize: 3
TargetGroupARNs:
- !Ref TargetGroup
LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
Properties:
KeyName: !Ref KeyName
InstanceType: t2.micro
SecurityGroups:
- !Ref EC2SecurityGroup
ImageId:
Fn::FindInMap:
- RegionMap
- !Ref AWS::Region
- AMI
LaunchConfiguration --region ${AWS::Region}
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ALB Security Group
VpcId: VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: EC2 Instance
In your ASG you usually would define VPCZoneIdentifier:
A list of subnet IDs for a virtual private cloud (VPC). If you specify VPCZoneIdentifier with AvailabilityZones, the subnets that you specify for this property must reside in those Availability Zones.
The example is as follows:
Parameters:
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: Subnet IDs for ASG
Resources:
MyASG:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
# ... other properties
VPCZoneIdentifier: !Ref SubnetIds
The snippet you are providing is for the target group of the load balancer.
This error will occur because the subnets attached to your auto scaling group are not within the same VPC as your target group.
Use a parameter type of List<AWS::EC2::Subnet::Id> to specify the subnets for your autoscaling group.
For your autoscaling group the VPCZoneIdentifier parameter should be assigned the values of the parameter.
More information is available here for this parameter type.
I'm referencing to this documentation: https://docs.aws.amazon.com/codestar/latest/userguide/customize-ec2-multi-endpoints.html#customize-ec2-multi-endpoints-newstage
We currently have a CodeStar project created from the Beanstalk template of type "Java Spring, Web Service". The generated project that uses CloudFormation however only includes a single environment for the deployment of our API.
Question: How does one properly modify this template so that there are two different environments running simultaneously?
In terms of Beanstalk: we need a SingleInstance type for our dev instance, and we want to have a LoadBalanced type for our prod instance (using two EC2 instances for redundancy).
The referenced tutorial mentions awscodestar-<project_name>-infrastructure-prod to be used as the Stack name for the CloudFormation's Sets, but how does that work if there is no actual instance created to be deployed on? I'm confused.
And why is there not already a template file which provides a two-environment CodePipeline/Beanstalk set-up similar to the one described? It seems like a rather mainstream approach to CI/CD.
Here is our template.yml file:
AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::CodeStar
Conditions:
UseSubnet: !Not [!Equals [!Ref 'SubnetId', subnet-none]]
Parameters:
ProjectId:
Type: String
Description: AWS CodeStar project ID used to name project resources and create roles.
InstanceType:
Type: String
Description: The type of Amazon EC2 Linux instances that will be launched for this project.
KeyPairName:
Type: String
Description: The name of an existing Amazon EC2 key pair in the region where the project is created, which you can use to SSH into the new Amazon EC2 Linux instances.
VpcId:
Type: String
Description: The ID of the Amazon Virtual Private Cloud (VPC) used for the new Amazon EC2 Linux instances.
SubnetId:
Type: String
Description: The name of the VPC subnet used for the new Amazon EC2 Linux instances launched for this project.
SolutionStackName:
Type: String
Description: The software stack used to launch environments and configure instances in AWS Elastic Beanstalk.
EBTrustRole:
Type: String
Description: The service role in IAM for AWS Elastic Beanstalk to be created for this project.
EBInstanceProfile:
Type: String
Description: The IAM role that will be created for the Amazon EC2 Linux instances.
Stage:
Type: String
Description: The name for a project pipeline stage, such as Staging or Prod, for which resources are provisioned and deployed.
Default: ''
Resources:
EBApplication:
Description: The AWS Elastic Beanstalk application, which is a container used to deploy the correct application configuration.
Type: AWS::ElasticBeanstalk::Application
Properties:
ApplicationName: !Sub '${ProjectId}app${Stage}'
Description: The name of the AWS Elastic Beanstalk application to be created for this project.
EBApplicationVersion:
Description: The version of the AWS Elastic Beanstalk application to be created for this project.
Type: AWS::ElasticBeanstalk::ApplicationVersion
Properties:
ApplicationName: !Ref 'EBApplication'
Description: The application version number.
SourceBundle: 'target/ROOT'
EBConfigurationTemplate:
Description: The AWS Elastic Beanstalk configuration template to be created for this project, which defines configuration settings used to deploy different versions of an application.
Type: AWS::ElasticBeanstalk::ConfigurationTemplate
Properties:
ApplicationName: !Ref 'EBApplication'
Description: The name of the sample configuration template.
OptionSettings:
- Namespace: aws:elasticbeanstalk:environment
OptionName: EnvironmentType
Value: SingleInstance
- Namespace: aws:elasticbeanstalk:environment
OptionName: ServiceRole
Value: !Ref 'EBTrustRole'
- Namespace: aws:elasticbeanstalk:healthreporting:system
OptionName: SystemType
Value: enhanced
SolutionStackName: !Ref 'SolutionStackName'
EBEnvironment:
Description: The AWS Elastic Beanstalk deployment group where the application is deployed, which is made up of the Amazon EC2 Linux instances launched for this project.
Type: AWS::ElasticBeanstalk::Environment
Properties:
ApplicationName: !Ref 'EBApplication'
EnvironmentName: !Ref 'EBApplication'
Description: The application to be deployed to the environment.
TemplateName: !Ref 'EBConfigurationTemplate'
VersionLabel: !Ref 'EBApplicationVersion'
OptionSettings:
- Namespace: aws:autoscaling:launchconfiguration
OptionName: IamInstanceProfile
Value: !Ref 'EBInstanceProfile'
- Namespace: aws:autoscaling:launchconfiguration
OptionName: InstanceType
Value: !Ref 'InstanceType'
- Namespace: aws:autoscaling:launchconfiguration
OptionName: EC2KeyName
Value: !Ref 'KeyPairName'
- Namespace: aws:ec2:vpc
OptionName: VPCId
Value: !Ref 'VpcId'
- !If
- UseSubnet
- Namespace: 'aws:ec2:vpc'
OptionName: Subnets
Value: !Ref 'SubnetId'
- !Ref "AWS::NoValue"
You could create a master template and refer to the production and dev templates as nested stacks. In this case all you would have to do is copy the template.yaml file twice, rename the copies to something appropriate, and upload them to an S3 bucket. Then your template.yaml file would refer to those two templates. Something like this:
AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::CodeStar
Description: Master stack which creates all required nested stacks
Resources:
ProdStack:
Type: "AWS::CloudFormation::Stack"
Properties:
TemplateURL: https://your-bucket/templates/production-stack.yml"
Parameters:
InstanceType: t2.micro
EBInstanceProfile: eg
KeyPairName: eg
VpcId: eg
ProjectId: eg
SubnetId: eg
SolutionStackName: eg
EBTrustRole: eg
Tags:
- Key: Environment
Value: Production
DevStack:
Type: "AWS::CloudFormation::Stack"
Properties:
TemplateURL: https://your-bucket/templates/development-stack.yml"
Parameters:
InstanceType: t2.nano
EBInstanceProfile: eg
KeyPairName: eg
VpcId: eg
ProjectId: eg
SubnetId: eg
SolutionStackName: eg
EBTrustRole: eg
Tags:
- Key: Environment
Value: Dev
This will create both stacks and allow you to put in the appropriate parameters for each. Take a look here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stack.html
Your pipeline would likely remain in the master file, and any other parameters you need for both environments, depending on how you structure the project.
Below is the yaml template. In the NetworkConfiguration, the subnet property is required. How should I set it to be any subnet of the default VPC that was created?
Resources:
ECSService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: !Ref ECSTaskDefinition
LaunchType: FARGATE
Cluster: !Ref ECSCluster
ServiceName: !Join
- '-'
-
- !Ref Message
- !Ref Stage
- service
DesiredCount: 1
DeploymentConfiguration:
MaximumPercent: 200
MinimumHealthyPercent: 100
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets:
- ?????
There isn’t a value for “any subnet in this vpc”, you’d have to set the subnets in the template or as a parameter.
Alternatively you can create the vpc and subnets in the template and reference them when describing your ECS service.
Lastly you could use a custom resource to call a Lambda function that looks up the subnets but it’s more complicated than a native reference. See an AWS blog post on it here https://aws.amazon.com/blogs/mt/looking-up-information-on-aws-cloudformation-stack-parameters-using-aws-lambda/
If it is a default vpc, you could try hardcoding the values. Or defined an new vpc and subnets in your template and refer to them.
Btw you can try cloudkast which is an online aws cloudformation template generator. It should make your life less dreadful while dealing with cloudformation templates. ;-)
Slowly moving all of our resources over to be managed by CloudFormation which so far has been relatively painless.
I'm hitting a bit of a wall with deployments of new task definitions (staging environment only) on ECS services. There's parts which I don't think can be managed with CloudFormation because the ECS Service is referencing a parameter.
The current process:
Push to a develop branch on BitBucket
BitBucket Pipelines then handles (simplified):
creating a ECR image with the tag of latest
creating a new task definition revision via aws ecs register-task-definition --cli-input-json $TASK_JSON
update the ECS service with the new task definition using aws ecs update-service --cluster ${ECS_CLUSTER_NAME} --service ${ECS_SERVICE} --task-definition $TASK_DEFINITION
This all works well!
Move the ECS resources management to CloudFormation with something along the lines of
Parameters:
TaskDefinition:
Type: String
Description: Task Definition ARN
Resources:
HTTPService:
Type: AWS::ECS::Service
DependsOn: ListenerRule
Properties:
Cluster: !Ref ECSCluster
Role: !Ref ServiceRole
DesiredCount: 1
HealthCheckGracePeriodSeconds: 120
TaskDefinition: !Ref TaskDefinition
LoadBalancers:
- ContainerName: http
ContainerPort: 80
TargetGroupArn: !Ref TargetGroup
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VPC
Port: 80
Protocol: HTTP
Matcher:
HttpCode: 200
HealthCheckIntervalSeconds: 15
HealthCheckPath: /
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
ListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
ListenerArn: !Ref Listener
Priority: 2
Conditions:
- Field: path-pattern
Values:
- /blog
Actions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
If I were to run the aws ecs update-service command manually now the CloudFormation stack would be out of sync with the ECS service.
Had a look into maybe running a aws cloudformation update-stack instead but the IAM permissions for the BitBucket user become quite complex.
Maybe I have gone about setting this all up incorrectly here. Any pointers/suggestions here?