AWS ECS cluster Capacity Provider - amazon-web-services

I'm using this cloudformation template to create capacity providers for ECS cluster with the autoscaling group specified in the ecs capacity provider:
"ECSCapacityProvider": {
"Type": "AWS::ECS::CapacityProvider",
"Properties": {
"AutoScalingGroupProvider": {
"AutoScalingGroupArn": { "Ref" : "AutoScalingGroup" }
}
},
"DependsOn" : "AutoScalingGroup"
},
"DRCluster": {
"Type": "AWS::ECS::Cluster",
"Properties": {
"ClusterName": { "Ref" : "WindowsECSCluster" },
"CapacityProviders" : "ECSCapacityProvider",
"Tags": [
{
"Key": "environment",
"Value": "dr"
}
]
},
"DependsOn" : "ECSCapacityProvider"
}
But while creating the stack it resulted in the following error:
Model validation failed (#/CapacityProviders: expected type: JSONArray, found: String)
I could not find proper documentation for the capacity providers. I'm using it to attach the Auto Scaling group to the cluster, which i hope is the correct way to do so. I'm new to cloudformation, any help is much appreciated.

CapacityProviders is a List of String, not a String like you have now:
"CapacityProviders" : "ECSCapacityProvider",
Therefore, in you DRCluster you can use the following instead:
"CapacityProviders" : [ {"Ref": "ECSCapacityProvider"} ],

Related

AWS Cloudformation: ImageId cannot be empty

I am using cloud formation to create:
load balancer + target-group w/ instance(from custom AMI)
I used create template in designer and edited their default configs:
I chose Elastic Loadbalancer V2 >> target group
{
"Resources": {
"ELBV3LB29NC1": {
"Type": "AWS::ElasticLoadBalancingV2::LoadBalancer",
"Properties": {
"IpAddressType" : "ipv4",
"Name" : "quest-loadbalancer2",
"SecurityGroups" : [ "sg-036a1a54caee05af5"],
"Subnets" : [ "subnet-795d4435", "subnet-7d5a5a07" ],
}
}
}
}
// **********************
{
"Resources": {
"ELBTV1G4J8KH": {
"Type": "AWS::ElasticLoadBalancingV2::TargetGroup",
"Properties": {
"Name": "quest-target-group-2",
"Port": 80,
"Protocol": "HTTP",
"Targets": [
{
"Id" : "i-0f5c5714bed60786b",
"Port" : 80
}
],
"TargetType": "i-0f5c5714bed60786b",
"VpcId": "vpc-a28dece9"
}
}
}
}
An EC2 Instance
{
"Resources": {
"EC2I5QYZC": {
"Type": "AWS::EC2::Instance",
"Properties": {
"AvailabilityZone" : "us-east-2",
"InstanceType" : "t2.micro",
"ImageId" :"ami-034e6c68f4dy6d449", // <------------ AMI ID
"SecurityGroups" : [ "sg-036a1a54caee05af5" ],
}
}
}
}
ERROR : (after clicking create stack) ImageId cannot be empty and it stops right there.
The target Instance id is an Instance Id. It should be an AMI ID instead.
You're trying to connect to an already existing instance instead of creating a new one.

How to create AWS Elasticbeanstalk application with integrated RDS using CloudFormation?

I am trying to setup the AWS environment for my SpringBoot application which uses Postgres.
I decided to use CloudFormation to configure all the AWS components needed for my application.
Following is the cloud formation template app.json:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"S3BucketName": {
"Description": "S3 BucketName",
"Type": "String"
},
"S3FileName": {
"Description": "Name of the jar/war file",
"Type": "String"
},
"DBName":{
"Default":"mytododb",
"Description":"The database name",
"Type":"String",
"MinLength":"1",
"MaxLength":"64",
"AllowedPattern":"[a-zA-Z][a-zA-Z0-9]*",
"ConstraintDescription":"must begin with a letter and contain only alphanumeric characters."
},
"DBUser":{
"Description":"The database admin account username",
"Type":"String",
"MinLength":"1",
"MaxLength":"16",
"AllowedPattern":"[a-zA-Z][a-zA-Z0-9]*",
"ConstraintDescription":"must begin with a letter and contain only alphanumeric characters."
},
"DBPassword":{
"NoEcho":"true",
"Description":"The database admin account password",
"Type":"String",
"MinLength":"8",
"MaxLength":"41",
"AllowedPattern":"[a-zA-Z0-9]*",
"ConstraintDescription":"must contain only alphanumeric characters."
},
"DBAllocatedStorage":{
"Default":"5",
"Description":"The size of the database (Gb)",
"Type":"Number",
"MinValue":"5",
"MaxValue":"1024",
"ConstraintDescription":"must be between 5 and 1024Gb."
},
"DBInstanceClass":{
"Default":"db.t2.micro",
"Description":"The database instance type",
"Type":"String",
"ConstraintDescription":"must select a valid database instance type."
},
"MultiAZDatabase":{
"Default":"false",
"Description":"Create a multi-AZ RDS database instance",
"Type":"String",
"AllowedValues":[
"true",
"false"
],
"ConstraintDescription":"must be either true or false."
}
},
"Resources": {
"SpringBootApplication": {
"Type": "AWS::ElasticBeanstalk::Application",
"Properties": {
"Description":"Spring boot and elastic beanstalk"
}
},
"SpringBootApplicationVersion": {
"Type": "AWS::ElasticBeanstalk::ApplicationVersion",
"Properties": {
"ApplicationName":{"Ref":"SpringBootApplication"},
"SourceBundle": {
"S3Bucket": {
"Ref": "S3BucketName"
},
"S3Key": {
"Ref": "S3FileName"
}
}
}
},
"SpringBootBeanStalkConfigurationTemplate": {
"Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
"Properties": {
"ApplicationName": {"Ref":"SpringBootApplication"},
"Description":"A display of speed boot application",
"OptionSettings": [
{
"Namespace": "aws:rds:dbinstance",
"OptionName": "DBAllocatedStorage",
"Value": {
"Ref": "DBAllocatedStorage"
}
},
{
"Namespace": "aws:rds:dbinstance",
"OptionName": "DBDeletionPolicy",
"Value": "Delete"
},
{
"Namespace": "aws:rds:dbinstance",
"OptionName": "DBEngine",
"Value": "postgres"
},
{
"Namespace": "aws:rds:dbinstance",
"OptionName": "DBEngineVersion",
"Value": "10.4"
},
{
"Namespace": "aws:rds:dbinstance",
"OptionName": "DBInstanceClass",
"Value": { "Ref": "DBInstanceClass" }
},
{
"OptionName": "DBPassword",
"Namespace": "aws:rds:dbinstance",
"Value": { "Ref": "DBPassword" }
},
{
"Namespace": "aws:rds:dbinstance",
"OptionName": "DBUser",
"Value": { "Ref": "DBUser" }
},
{
"Namespace": "aws:rds:dbinstance",
"OptionName": "MultiAZDatabase",
"Value": { "Ref": "MultiAZDatabase" }
}
],
"SolutionStackName": "64bit Amazon Linux 2018.03 v2.9.2 running Java 8"
}
},
"SpringBootBeanstalkEnvironment": {
"Type": "AWS::ElasticBeanstalk::Environment",
"Properties": {
"ApplicationName": {"Ref":"SpringBootApplication"},
"EnvironmentName":"TodoAppEnvironment",
"TemplateName": {"Ref":"SpringBootBeanStalkConfigurationTemplate"},
"VersionLabel": {"Ref": "SpringBootApplicationVersion"}
}
}
},
"Outputs": {
"DevURL": {
"Description": "The URL of the DEV Elastic Beanstalk environment",
"Value": {
"Fn::Join": [
"",
[
{
"Fn::GetAtt": [
"SpringBootBeanstalkEnvironment",
"EndpointURL"
]
}
]
]
},
"Export": {
"Name": {
"Fn::Sub": "${AWS::StackName}-EndpointURL"
}
}
}
}
}
And the parameters file parameters.json is:
[
{
"ParameterKey": "DBUser",
"ParameterValue": "myuser"
},
{
"ParameterKey": "DBPassword",
"ParameterValue": "secret"
},
{
"ParameterKey": "S3BucketName",
"ParameterValue": "todoapp"
},
{
"ParameterKey": "S3FileName",
"ParameterValue": "todo-api-spring-boot-0.0.1.jar"
}
]
I am creating the CloudFormation stack using
aws cloudformation create-stack --template-body file://app.json --parameters file://parameters.json --stack-name=todo-stack
Problem:
The stack is getting created, however the database (RDS) instance is not getting created and when I see in ElasticBeanstalk configuration for the app in Management Console there is no Database configuration associated with the application.
My expectation/assumption is by configuring various aws:rds:dbinstance properties in OptionSettings an RDS instance will be provisioned and associates with ElasticBeanstalk application.
Is my understanding wrong or am I missing any other setting?
PS:
The idea is to use integrated RDS so that I can use RDS_HOST, RDS_PORT etc properties in my application to connect to database.
I am able to configure a separate RDS Resource and connect to it by specifying the connection parameters. But I am expecting aws:rds:dbinstance properties in OptionSettings would create the RDS and associate it to Elasticbeanstalk application. If that is not the case then what is the purpose of configuring those parameters in OptionSettings?
Ref:
https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-rdsdbinstance
https://github.com/metabase/metabase/blob/master/bin/aws-eb-docker/cloudformation-elasticbeanstalk.json.template
RDS creation is not done due to the Namespace Approach. Basically Namespace is used to override the default properties of the resources which you have created.
So the solution is to include the RDS creation template before your "SpringBootBeanStalkConfigurationTemplate"
"Resources": {
"RDS Creation": {
{
"Type" : "AWS::RDS::DBInstance",
"Properties" : {
"AllocatedStorage" : String,
"AllowMajorVersionUpgrade" : Boolean,
"AssociatedRoles" : [ DBInstanceRole, ... ],
"AutoMinorVersionUpgrade" : Boolean,
"AvailabilityZone" : String,
"BackupRetentionPeriod" : Integer,
"CharacterSetName" : String,
"CopyTagsToSnapshot" : Boolean,
"DBClusterIdentifier" : String,
"DBInstanceClass" : String,
"DBInstanceIdentifier" : String,
"DBName" : String,
"DBParameterGroupName" : String,
"DBSecurityGroups" : [ String, ... ],
"DBSnapshotIdentifier" : String,
"DBSubnetGroupName" : String,
"DeleteAutomatedBackups" : Boolean,
"DeletionProtection" : Boolean,
"Domain" : String,
"DomainIAMRoleName" : String,
"EnableCloudwatchLogsExports" : [ String, ... ],
"EnableIAMDatabaseAuthentication" : Boolean,
"EnablePerformanceInsights" : Boolean,
"Engine" : String,
"EngineVersion" : String,
"Iops" : Integer,
"KmsKeyId" : String,
"LicenseModel" : String,
"MasterUsername" : String,
"MasterUserPassword" : String,
"MonitoringInterval" : Integer,
"MonitoringRoleArn" : String,
"MultiAZ" : Boolean,
"OptionGroupName" : String,
"PerformanceInsightsKMSKeyId" : String,
"PerformanceInsightsRetentionPeriod" : Integer,
"Port" : String,
"PreferredBackupWindow" : String,
"PreferredMaintenanceWindow" : String,
"ProcessorFeatures" : [ ProcessorFeature, ... ],
"PromotionTier" : Integer,
"PubliclyAccessible" : Boolean,
"SourceDBInstanceIdentifier" : String,
"SourceRegion" : String,
"StorageEncrypted" : Boolean,
"StorageType" : String,
"Tags" : [ Tag, ... ],
"Timezone" : String,
"UseDefaultProcessorFeatures" : Boolean,
"VPCSecurityGroups" : [ String, ... ]
}
}
}
}
After this, you can include the RDS parameters in your other Resources as it will be created first.
I was stumbling across the same question and found some sort of an answer here: https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.db.html
In that document they say:
You can configure your environment's database instance using configuration files. Use the options in the aws:rds:dbinstance namespace. The following example modifies the allocated database storage size to 100 GB.
So the aws:rds:dbinstance properties in OptionSettings are only meant to modify an existing database instance, not to create one in the first place.

How do I specify subnet and VPC IDs in AWS CloudFormation?

I want my CloudFormation template to use existing subnets and VPCs. I don't want to create new ones.
How do I parameterize these?
When I look at the docs for AWS::EC2::VPC and AWS::EC2::Subnet, it seems these resources are only for creating new VPCs and subnets. Is that correct?
Should I just point the instance resource directly to the existing VPC and subnets I want it to use?
For example - if I have an instance resource in my template and I point it directly to an existing subnet, like this:
{
"Resources": {
"MyServer": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": {
"Ref": "InstanceType"
},
"SubnetId": {
"Ref": "subnet-abc123"
},
...
I get this error when validating the template:
Template contains errors.: Template format error: Unresolved resource dependencies [subnet-abc123] in the Resources block of the template
I tried to do this with mappings but still getting an error:
"Mappings": {
"SubnetID": {
"TopKey": {
"Default": "subnet-abc123"
}
}
And with this in the instance resource:
"SubnetId": {
"Fn::FindInMap": [
"SubnetID",
{
"Ref": "TopKey"
},
"Default"
]
}
I get this error when trying to validate:
Template contains errors.: Template format error: Unresolved resource dependencies [TopKey] in the Resources block of the template
If you wish to use a specific VPC and subnet, just insert their values:
{
"Resources": {
"MyServer": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": "t2.micro",
"SubnetId": "subnet-abc123",
"ImageId": "ami-abcd1234"
}
}
}
A subnet always belongs to a VPC, so specifying the subnet will automatically select the matching VPC.
Specify them in the Parameters section, and refer them in Resources section. CF will let you select the VPC first and then the Subnet.
"Parameters" : {
"VpcId" : {
"Type" : "AWS::EC2::VPC::Id",
"Description" : "VPCId of Virtual Private Cloud (VPC).",
"Default" : ""
},
"VpcSubnet": {
"Description" : "SubnetId in VPC",
"Type" : "AWS::EC2::Subnet::Id",
"Default" : ""
},
"Resources" : {
...
"Ec2Instance" : {
"Properties" : {
"SubnetId" : { "Ref" : "VpcSubnet" },

How to get resource logical id cloudformation template?

Is it possible to get a resource's logical ID inside itself like we do with "Ref" : "logicalName". I just want to get the resource logical id (here Instance1) in its own properties section dynamically. Till now i have to hard code resource name.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Mappings": {
"Para" : {
"Layer" : { "Instance1" : "Testing", "Instance2" : "Staging", "Instance3" : "Production" }
}
},
"Resources": {
"Instance1": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": "ami-5fb8c835",
"Tags": [
{ "Key": "Name", "Value": { "Fn::FindInMap" : [ "Para", "Name", "Instance1" ]} }
]
}
},
"Instance2": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": "ami-5fb8c835",
"Tags": [
{ "Key": "Name", "Value": { "Fn::FindInMap" : [ "Para", "Name", "Instance2" ]} }
]
}
}
}
I just want to get resource name (eg Instance1 or instance 2) in key, value tag lines.
It is not possible to retrieve the logical name itself within a custom tag, but CloudFormation does automatically tag every Instance with an aws:cloudformation:logical-id tag.
In addition to any tags you define, AWS CloudFormation automatically
creates the following stack-level tags with the prefix aws::
aws:cloudformation:logical-id
aws:cloudformation:stack-id
aws:cloudformation:stack-name
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-resource-tags.html

Elasticache replication group id in CloudFormation template

How do you set the Redis ReplicationGroup ID when using a CloudFormation template? All the options in the docs show no way to do that and the CLI you can do this easily. My end goal is to have a Redis replication group with 3 cluster members but I want to choose the name rather than AWS set a unique name for me.
Here's a snippet of my template:
"Resources": {
"mqpReplicationGroup": {
"Type": "AWS::ElastiCache::ReplicationGroup",
"Properties": {
"CacheNodeType": {
"Ref": "CacheNodeType"
},
"CacheSubnetGroupName": {
"Ref": "CacheSubnets"
},
"ReplicationGroupDescription": "Redis Replication Group",
"Engine": "redis",
"EngineVersion": {
"Ref": "RedisVersion"
},
"NumCacheClusters": {
"Ref": "NumberOfCacheNodes"
},
"AutoMinorVersionUpgrade": "true",
"AutomaticFailoverEnabled": "true",
"PreferredMaintenanceWindow": "sat:09:25-sat:22:30",
"SnapshotRetentionLimit": "4",
"SnapshotWindow": "00:05-05:30",
"NotificationTopicArn": {
"Fn::Join" :[":",["arn:aws:sns",{ "Ref" : "AWS::Region" },{ "Ref" : "AWS::AccountId" },"service-aws"]]
},
"SecurityGroupIds": [
{
"Fn::Join": [
",",
{
"Ref": "VpcSecurityGroupIds"
}
]
}
]
}
},
"CacheSubnets": {
"Type": "AWS::ElastiCache::SubnetGroup",
"Properties": {
"Description": "mqp-cache-subnet",
"SubnetIds": {
"Ref": "SubnetIds"
}
}
}
}
As of 2017, this is now possible using ReplicationGroupId property.
Since it is optional, AWS CloudFormation will still generate an unique physical ID when not specified.
Restrictions for Name Type:
Must contain from 1 to 20 alphanumeric characters or hyphens.
First character must be a letter.
Cannot end with a hyphen or contain two consecutive hyphens.
This cannot currently be done with CloudFormation.