Reusing AWS::CloudFormation::Init (and userdata?) for multiple instances - amazon-web-services

Is it possible to reuse the same bootstrapping config from AWS::CloudFormation::Init (and/or userdata) for multiple EC2::Instances in a template?
I need to set the content of 3 files and then run 3 commands to bootstrap all servers, but the Metadata block is about 30 lines long (and is likely to grow).
Each server instance has a different set of Tags, some have more tags than others.
Ideally, I think that you should be able to declare the AWS::CloudFormation::Init as a resource, and refer to it from multiple EC2::Instances, but I don't think that this is possible.
I initially thought (as a newbie) that AWS::CloudFormation::CustomResource might be appropriate, but I don't think that it is.
I'm currently thinking of using a AWS::CloudFormation::Stack to import a shared instance template, but I would need to somehow pass the Tags parameter for each resource in the stack template into the instance template. The question is - if this is the best approach, what do I enter in the 3 locations that currently have ?????
(Bonus credit - what's the difference between userdata and this init block?)
stack.template
...
"Resources" : {
"Server1" : {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"Parameters": {
"InstanceType": "m1.medium",
...
"Tags": { ???? }
},
"TemplateURL": "https://s3.amazonaws.com/mybucket/instance.template"
}
instance.template
...
"Parameters" : {
"InstanceType" : {...}
"KeyName": {...}
...
"Tags": {
????
}
},
"Resources" : {
"Instance" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"files" : {
"/etc/apt/apt.conf.d/99auth" : {
"content" : "APT::Get::AllowUnauthenticated yes;"
},
"/etc/apt/sources.list.d/my-repo.list" : {
"content" : "deb http://my-repo/repo apt/"
},
},
"commands" : {
"01-apt-get update" : {
"command" : "apt-get update"
},
"02-apt-get install puppet" : {
"command" : "apt-get install puppet my-puppet-config"
},
"03-puppet apply" : {
"command" : "puppet apply"
}
}
}
}
},
"Properties" : {
"InstanceType" : {"Ref" : "InstanceType"},
"ImageId" : "ami-84a333be",
"KeyName" : {"Ref" : "KeyName"},
"SubnetId" : {"Ref" : "SubnetId"},
"SecurityGroupIds" : [ { "Ref" : "SecurityGroupId"] } ],
"Tags" : [
????
]
}
}
}

Is it possible to reuse the same bootstrapping config from
AWS::CloudFormation::Init (and/or userdata) for multiple
EC2::Instances in a template?
No, this is not possible with the AWS::EC2::Instance resource in a single template. However, there is a resource type AWS::AutoScaling::LaunchConfiguration, but today this resource is only applicable to Auto Scaling groups. Ideally, AWS would provide a similar resource type that can be applied to multiple AWS::EC2::Instance resources. That being said, there is a lot of value in using Auto Scaling groups.
Here is a simple example that would allow you to do this with a single Launch Configuration and multiple Auto Scaling group resources in a single template. Auto scaling is typically configured with more than one instance, but I am using a MinSize and MaxSize of 1 to mirror the configuration you were going after with the AWS::EC2::Instance resource type. Even though we are using a single instance with an Auto Scaling group, we still gain the benefits of Auto Scaling with single instance resiliency. If the instance becomes unhealthy, Auto Scaling will automatically replace the instance.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources" : {
"LaunchConfig" : {
"Type" : "AWS::AutoScaling::LaunchConfiguration",
"Properties" : {
"InstanceType" : { "Ref" : "InstanceType" },
"ImageId" : "ami-84a333be",
"KeyName" : { "Ref" : "KeyName" },
"SecurityGroupIds" : [{"Ref" : "SecurityGroupId"}],
"UserData" : { "Fn::Base64" : { "Fn::Join" : [ "", [
"#!/bin/bash -v\n",
"# Run cfn-init\n",
"/opt/aws/bin/cfn-init -v ",
" -stack ", { "Ref": "AWS::StackName" },
" -resource LaunchConfig ",
" --region ", { "Ref" : "AWS::Region" }, "\n",
"# Signal success\n",
"/opt/aws/bin/cfn-signal -e $? '", { "Ref" : "WaitConditionHandle" }, "'\n"
]]}}
},
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"files" : {
"/etc/apt/apt.conf.d/99auth" : {
"content" : "APT::Get::AllowUnauthenticated yes;"
},
"/etc/apt/sources.list.d/my-repo.list" : {
"content" : "deb http://my-repo/repo apt/"
}
},
"commands" : {
"01-apt-get update" : {
"command" : "apt-get update"
},
"02-apt-get install puppet" : {
"command" : "apt-get install puppet my-puppet-config"
},
"03-puppet apply" : {
"command" : "puppet apply"
}
}
}
}
}
},
"ASG1" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : [ { "Ref" : "AZ" } ],
"VPCZoneIdentifier" : [ { "Ref" : "SubnetId" } ],
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MaxSize" : "1",
"MinSize" : "1",
"Tags" : [
{ "Key" : "Name", "Value": "Server1", "PropagateAtLaunch" : "true" },
{ "Key" : "Version", "Value": "1.0", "PropagateAtLaunch" : "true" }
]
}
},
"ASG2" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : [ { "Ref" : "AZ" } ],
"VPCZoneIdentifier" : [ { "Ref" : "SubnetId" } ],
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MaxSize" : "1",
"MinSize" : "1",
"Tags" : [
{ "Key" : "Name", "Value": "Server2", "PropagateAtLaunch" : "true" },
{ "Key" : "Version", "Value": "1.0", "PropagateAtLaunch" : "true" }
]
}
},
"WaitConditionHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
},
"WaitCondition" : {
"Type" : "AWS::CloudFormation::WaitCondition",
"Properties" : {
"Handle" : { "Ref" : "WaitConditionHandle" },
"Timeout" : "300"
}
}
}
}
This is an incomplete example and there is much more you can do with Auto Scaling, but I just wanted to give you a simple example sharing a Launch Configuration with multiple instances. Each Auto Scaling group does define its own set of tags.
I'm currently thinking of using a AWS::CloudFormation::Stack to import
a shared instance template, but I would need to somehow pass the Tags
parameter for each resource in the stack template into the instance
template. The question is - if this is the best approach, what do I
enter in the 3 locations that currently have ?????
I would recommend the solution I described above, but I would also like to answer your questions on how use tags with the nested stack approach.
stack.template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources" : {
"Server1" : {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/mybucket/instance.template",
"Parameters": {
"InstanceType": "m1.medium",
"TagName": "Server1"
"TagVersion": "1.0"
}
}
},
"Server2" : {
"Type": "AWS::CloudFormation::Stack",
"Properties": {
"TemplateURL": "https://s3.amazonaws.com/mybucket/instance.template",
"Parameters": {
"InstanceType": "m1.medium",
"TagName": "Server2"
"TagVersion": "1.0"
}
}
}
}
}
instance.template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters" : {
"InstanceType" : {...},
"KeyName": {...}
"TagName": {
"Description" : "The name tag to be applied to each instance",
"Type" : "String"
},
"TagVersion": {
"Description" : "The version tag to be applied to each instance",
"Type" : "String"
}
},
"Resources" : {
"Instance" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"AWS::CloudFormation::Init" : {
...
}
},
"Properties" : {
"InstanceType" : { "Ref" : "InstanceType" },
"ImageId" : "ami-84a333be",
"KeyName" : { "Ref" : "KeyName" },
"SubnetId" : { "Ref" : "SubnetId" },
"SecurityGroupIds" : [ { "Ref" : "SecurityGroupId"] } ],
"Tags" : [
{ "Key" : "Name", "Value": { "Ref" : "TagName" } },
{ "Key" : "Version", "Value": { "Ref" : "TagVersion" } },
]
}
}
}
}
There is not a standard for passing an entire array of tags as a parameter, so you can see I simply broke each tag out into its own parameter and passed these on to the nested stacks.
(Bonus credit - what's the difference between userdata and this init
block?)
UserData allows you to pass arbitrary data to the instance at first boot. Often this is a shell script that can automate tasks when the instance starts. For example, you could simply run a yum update.
"UserData" : { "Fn::Base64" : { "Fn::Join" : [ "", [
"#!/bin/bash\n"
"yum update -y", "\n"
]]}}
UserData becomes even more useful when combined with the AWS::CloudFormation::Init metadata which allows you to structure your bootstrapping configuration. In this case, UserData is simply used to invoke the cfn-init script that executes the AWS::CloudFormation::Init metadata. I've included this pattern in my first example above using a Launch Configuration. It is important to note that the UserData section is executed only once during the first boot of the instance. This is important to keep in mind when thinking about how you want to handle updates to your instances.

Related

Getting "Template validation error: Invalid template resource property 'VPCID' "

I am trying to create a VPC using AWS CloudFormation.
I built a VPC on its own, then I updated the existing stack by adding more components to the JSON template (components like subnets, internet gateways, NATs, route tables, etc.) - one component at a time.
My VPC created successfully but when I tried to update the stack with an internet gateway and attach to the VPC, I started getting the error Template validation error: Invalid template resource property 'VPCID'.
My JSON template is as follows:
{
"Parameters": {
"CIDRRange": {
"Description": "VPCCIDR Range (will be a /16 block)",
"Type": "String",
"Default": "10.251.0.0",
"AllowedValues": ["10.250.0.0","10.251.0.0"]
}
},
"Resources": {
"VPCBase": {
"Type": "AWS::EC2::VPC",
"Properties": {
"CidrBlock": { "Fn::Join" : ["", [{ "Ref" : "CIDRRange" }, "/16"]] },
"EnableDnsSupport": "True",
"EnableDnsHostnames": "True",
"Tags": [{ "Key": "Name", "Value": { "Fn::Join" : ["", [{ "Ref" : "AWS::StackName" }, "-VPC"]] } }]
}
},
"IGWBase" : {
"Type" : "AWS::EC2::InternetGateway",
"Properties" : {
"Tags" : [{ "Key": "Name", "Value": { "Fn::Join" : ["", [{ "Ref" : "AWS::StackName" }, "-IGW"]] } }]
}
},
"VGAIGWBase" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"InternetGatewayId" : { "Ref" : "IGWBase" },
"VpcId" : { "Ref" : "VPCBase" }}
},
"Outputs": {
"VPCID" : { "Value" : { "Ref" : "VPCBase" } },
"DefaultSG" : { "Value" : { "Fn::GetAtt" : ["VPCBase", "DefaultSecurityGroup"] }}
}
}
}
Your formatting is a bit of a mess - I'd recommend going with yaml over json - but the problem is you're not closing the Resources: section.
You can validate a template with the cli with
aws cloudformation validate-template --template-body file://path.json
"VGAIGWBase" : {
"Type" : "AWS::EC2::VPCGatewayAttachment",
"Properties" : {
"InternetGatewayId" : { "Ref" : "IGWBase" },
"VpcId" : { "Ref" : "VPCBase" }
}
}
}, << ADD THIS
"Outputs": {
"VPCID" : { "Value" : { "Ref" : "VPCBase" } },
"DefaultSG" : { "Value" : { "Fn::GetAtt" : ["VPCBase", "DefaultSecurityGroup"] }}
}
}

Is there a way to configure the 'Stack Name' of nested stacks in AWS cloudformation ?

I am trying to create a nested stack using AWS CloudFormation.
I need to specify the 'Stack Name' of the nested stack.
I tried using the 'Tags' property with Key: 'Stack Name'. But that didn't help.
Is there any way to provide the Stack Name as an input while creating nested stack?
In a given template, you have access to the pseudo-parameters stackId and stackName. Those can be marked for export, then referenced in another stack. Joined, they give you the child stack's name.
I found the following video quite useful despite its age: https://youtu.be/6R44BADNJA8
This sample template may also be helpful in understanding how these work: https://s3.amazonaws.com/cloudformation-examples/user-guide/cross-stack/SampleNetworkCrossStack.template
{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "AWS CloudFormation Sample Template VPC_with_PublicIPs_And_DNS: Sample template that creates a VPC with DNS and public IPs enabled. Note that you are billed for the AWS resources that you use when you create a stack from this template.", "Resources" : { "VPC" : { "Type" : "AWS::EC2::VPC", "Properties" : { "EnableDnsSupport" : "true", "EnableDnsHostnames" : "true", "CidrBlock" : "10.0.0.0/16" } }, "PublicSubnet" : { "Type" : "AWS::EC2::Subnet", "Properties" : { "VpcId" : { "Ref" : "VPC" }, "CidrBlock" : "10.0.0.0/24" } }, "InternetGateway" : { "Type" : "AWS::EC2::InternetGateway" }, "VPCGatewayAttachment" : { "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" : "VPCGatewayAttachment", "Properties" : { "RouteTableId" : { "Ref" : "PublicRouteTable" }, "DestinationCidrBlock" : "0.0.0.0/0", "GatewayId" : { "Ref" : "InternetGateway" } } }, "PublicSubnetRouteTableAssociation" : { "Type" : "AWS::EC2::SubnetRouteTableAssociation", "Properties" : { "SubnetId" : { "Ref" : "PublicSubnet" }, "RouteTableId" : { "Ref" : "PublicRouteTable" } } }, "PublicSubnetNetworkAclAssociation" : { "Type" : "AWS::EC2::SubnetNetworkAclAssociation", "Properties" : { "SubnetId" : { "Ref" : "PublicSubnet" }, "NetworkAclId" : { "Fn::GetAtt" : ["VPC", "DefaultNetworkAcl"] } } }, "WebServerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP ingress", "VpcId" : { "Ref" : "VPC" }, "SecurityGroupIngress" : [ { "IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0" } ] } } }, "Outputs" : { "VPCId" : { "Description" : "VPC ID", "Value" : { "Ref" : "VPC" }, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-VPCID" }} }, "PublicSubnet" : { "Description" : "The subnet ID to use for public web servers", "Value" : { "Ref" : "PublicSubnet" }, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SubnetID" }} }, "WebServerSecurityGroup" : { "Description" : "The security group ID to use for public web servers", "Value" : { "Fn::GetAtt" : ["WebServerSecurityGroup", "GroupId"] }, "Export" : { "Name" : {"Fn::Sub": "${AWS::StackName}-SecurityGroupID" }} } } }
As commented below, the answer is no for now.
Original:Yes, it's the resource name that gets taken as the stack name. Below you'd get a stack called myStackName
YAML
AWSTemplateFormatVersion: "2010-09-09"
Resources:
myStackName:
Type: "AWS::CloudFormation::Stack"
Properties:
TemplateURL: "https://s3.amazonaws.com/cloudformation-templates-us-east-1/EC2ChooseAMI.template"
Parameters:
InstanceType: "t1.micro"
KeyName: "mykey"
JSON
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Resources" : {
"myStackName" : {
"Type" : "AWS::CloudFormation::Stack",
"Properties" : {
"TemplateURL" : "https://s3.amazonaws.com/cloudformation-templates-us-east-1/EC2ChooseAMI.template",
"Parameters" : {
"InstanceType" : "t1.micro",
"KeyName" : "mykey"
}
}
}
}
}

Tagging Beanstalk environments created with cloudformation

When creating an Elastic Beanstalk environment using Cloud Formation, how do you set the Tags allocated to the environment and instances?
For example I have the following Resource definition:
"BeanstalkEnvironment" : {
"Type" : "AWS::ElasticBeanstalk::Environment",
"Properties" : {
"ApplicationName" : { "Ref" : "BeanstalkApplication" },
"Description" : "AWS Elastic Beanstalk Environment running Demo Application",
"SolutionStackName" : "64bit Windows Server 2012 R2 running IIS 8.5",
"EnvironmentName" : "Test Site",
"CNAMEPrefix" : { "Ref" : "URLPrefix" },
"OptionSettings" : [
{"Namespace" : "aws:autoscaling:launchconfiguration", "OptionName" : "EC2KeyName", "Value" : { "Ref" : "KeyName" }},
{"Namespace" : "aws:ec2:vpc", "OptionName" : "VPCId", "Value" : { "Ref" : "VPC" }},
{"Namespace" : "aws:ec2:vpc", "OptionName" : "Subnets", "Value" : { "Fn::Join" : [ ",", [ { "Ref" : "SubnetA" }, { "Ref" : "SubnetB" }, { "Ref" : "SubnetC" } ] ] } },
{"Namespace" : "aws:ec2:vpc", "OptionName" : "ELBSubnets", "Value" : { "Fn::Join" : [ ",", [ { "Ref" : "SubnetA" }, { "Ref" : "SubnetB" }, { "Ref" : "SubnetC" } ] ] } },
{"Namespace" : "aws:autoscaling:launchconfiguration", "OptionName":"InstanceType", "Value" : "t2.micro" },
{"Namespace" : "aws:ec2:vpc", "OptionName":"AssociatePublicIpAddress", "Value":"true" },
{"Namespace" : "aws:autoscaling:updatepolicy:rollingupdate", "OptionName":"MaxBatchSize", "Value": "1" },
{"Namespace" : "aws:autoscaling:updatepolicy:rollingupdate", "OptionName":"MinInstancesInService", "Value": "1" },
{"Namespace" : "aws:autoscaling:updatepolicy:rollingupdate", "OptionName":"PauseTime", "Value": "PT5M30S" },
{"Namespace" : "aws:autoscaling:updatepolicy:rollingupdate", "OptionName":"RollingUpdateEnabled", "Value": "true" },
{"Namespace" : "aws:elasticbeanstalk:command", "OptionName":"BatchSize", "Value": "30" },
{"Namespace" : "aws:elb:policies", "OptionName":"ConnectionDrainingEnabled", "Value": "true" }
],
"VersionLabel" : "Sample .NET Application"
}
}
A full working example template is in this gist.
And would like to add a set of Tags to the Beanstalk and the instances it creates e.g.:
"Tags" : [
{ "Key" : "Contact", "Value" : { "Ref" : "Contact" } },
{ "Key" : "BudgetCode", "Value" : { "Ref" : "BudgetCode" } }
]
There does not appear to be a "Tags" element for the Elastic Beanstalk Resource Type in the same way there is for other types (e.g. S3 Buckets).
Any suggestions on how to do this? Would be really good to ensure the instances created are correctly tagged so we can track what instances are used for different projects.
The example given in the OP should now work.
AWS added support for tagging Elastic Beanstalk Environments on 08/24/2015:
http://aws.amazon.com/about-aws/whats-new/2015/08/aws-cloudformation-updates-support-for-amazon-vpc-aws-lambda-aws-elastic-beanstalk-amazon-rds-and-amazon-s3/
Usage is the same as other CFN resource types that support tags - include a Tags key in the Properties mapping and assign a list of Key, Value mappings:
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-beanstalk-environment.html#cfn-beanstalk-environment-tags
I wish I had the answer, but instead I have the same problem. You can do this in the create environment cli and in the api, but there doesn't seem to be a namespace for this in the options settings for doing it in a cloudformation template. (At least it's not a documented namespace from what I can see). My google-fu doesn't show anyone else with an answer to this yet either.
I have the same problem and Amazon support has indicated that it is a gap in functionality.

how to construct a string of physical subnet ids to create db subnet group on the fly in a cloudformation script?

I'm trying to build a CLoudFormation script that launches an instance and a db into a vpc at the same time. the issue is the db requires two AZ's so i create a second subnet and now i just need to reference the two subnet physical ids in a 'MyDBSubnetGroup' var. I can get the logical IDs for the subnets i created but dont know how to ref those physical IDs. ANyone know? THanks!!
Heres my code:
"MyDBSubnetGroup" : {
"Type" : "AWS::RDS::DBSubnetGroup",
"Properties" : {
"DBSubnetGroupDescription" : "Subnets available for the RDS DB Instance",
"SubnetIds" : { "Fn::Join" : [ " ", [{"Ref" : "PublicSubnetAZ1"}, ", ", {"Ref" : "PublicSubnetAZ2"}, " " ]]}
}
},
I run into the same issue, after working with AWS support I understood that List of String does not mean what we initially thought. Also, if you want to place the DB inside a VPC you must not use AWS::RDS::DBSecurityGroup objects.
Here is a full sample, it took me a while to get it working:
"dbSubnetGroup" : {
"Type" : "AWS::RDS::DBSubnetGroup",
"Properties" : {
"DBSubnetGroupDescription" : "Availability Zones for RDS DB",
"SubnetIds" : [ { "Ref" : "subnetPrivate1" },
{ "Ref" : "subnetPrivate2" } ]
}
},
"dbInstance" : {
"Type" : "AWS::RDS::DBInstance",
"Properties" : {
"DBInstanceIdentifier" : { "Fn::Join" : [ "",
[ { "Ref" : "AWS::StackName" },
"DB" ] ] },
"DBName" : "dbname",
"DBSubnetGroupName" : { "Ref" : "dbSubnetGroup" },
"MultiAZ" : "true",
"AllocatedStorage" : "8",
"BackupRetentionPeriod" : "0",
"DBInstanceClass" : "db.m1.medium",
"Engine" : "postgres",
"MasterUserPassword" : "masteruserpassword",
"MasterUsername" : "masterusername",
"VPCSecurityGroups" : [ { "Ref" : "sgVpc" }, { "Ref" : "sgDB" } ]
}
},
If you map the subnet ids you can access them with something like this.
"AWSRegionSubnet":{
"us-east-1":{
"RDSSubnets":[
"subnet-aaaaaaaa",
"subnet-bbbbbbbb"
]
},
"us-west-2":{
"RDSSubnets":[
"subnet-cccccccc",
"subnet-dddddddd"
]
}
}
"RDSSubnet":{
"Type":"AWS::RDS::DBSubnetGroup",
"Properties":{
"DBSubnetGroupDescription":"Some cool notes here",
"SubnetIds":{
"Fn::FindInMap":[
"AWSRegionSubnet",
{
"Ref":"AWS::Region"
},
"RDSSubnets"
]
}
}
}

aws CloudFormation AWS::EC2::Instance BlockDeviceMappings and Volumes

I am sort of confused about two AWS::EC2::Instance properties:
BlockDeviceMappings and Volumes.
I have read documentation a number of times but still don't really understand the difference.
Here is my template:
{
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "kappoowTest",
"Mappings" : {
"AmazonLinuxAMI" : {
"eu-west-1" :
{ "AMI" : "ami-d8f9f1ac" },
"us-west-1" :
{ "AMI" : "ami-b63210f3" }
}
},
"Resources" : {
"SomeInstance" :{
"Type" : "AWS::EC2::Instance",
"Properties" : {
"AvailabilityZone" : "eu-west-1a",
"BlockDeviceMappings" : [
{
"DeviceName" : "/dev/sdc",
"Ebs" : { "VolumeSize" : "50" }
},
{
"DeviceName" : "/dev/sdd",
"Ebs" : { "VolumeSize" : "100" }
}
],
"DisableApiTermination" : "true",
"EbsOptimized" : "true",
"ImageId" : { "Fn::FindInMap" : [ "AmazonLinuxAMI", { "Ref" : "AWS::Region" }, "AMI" ]},
"InstanceType" : "m1.large",
"KeyName" : "mongo_test",
"Monitoring" : "true",
"SecurityGroups" : [ "default" ],
"Volumes" : [
{ "VolumeId" : { "Ref" : "NewVolume" }, "Device" : "/dev/sdk" }
]
}
},
"NewVolume" : {
"Type" : "AWS::EC2::Volume",
"Properties" : {
"Size" : "100",
"AvailabilityZone" : "eu-west-1a"
}
}
}}
Here I have created 3 volumes. 2 with
"BlockDeviceMappings" : [
{
"DeviceName" : "/dev/sdc",
"Ebs" : { "VolumeSize" : "50" }
},
{
"DeviceName" : "/dev/sdd",
"Ebs" : { "VolumeSize" : "100" }
}
]
and another one with:
"Volumes" : [
{ "VolumeId" :
{ "Ref" : "NewVolume" }, "Device" : "/dev/sdk" }
]
CloudFormation ran fine, but I fail to see the difference.
Could someone tell me what which way is better of adding EBS volumes to EC2 instance and what is the difference between these two methods ?
With BlockDeviceMappings you can mount ephemeral storage not only ebs.
Volumes is only ebs volumes, and provides better options (like choosing the AZ, or specifying the IOPs if you want to use PIOPs).
If all what you want is simple ebs volumes, then there is no difference.