Select Page

CloudFormation: Reduce, Reuse, Recycle – Part 3

CloudFormation: Reduce, Reuse, Recycle – Part 3

This is part of a multi-part blog post in which I’ll break down a basic CloudFormation template that I wrote to make it reusable, regardless of what client/project you’re working with or what region in which you’re creating a stack to run. In this post, I’ll be discussing how to use another Intrinsic Function (specifically Fn::FindInMap) to allow the stack to properly select the correct AMI within a list depending on the region to which you are deploying.

The first two parts of this multi-part blog post can found here and here.

As we continue to modify the original code discovered in the first post, I want to now add the deployment of an EC2 instance to the mix. After all, what’s the purpose of deploying all this infrastructure if we can’t use it to run workloads? Take a look at the initial modified code below and see where I’ve declared a new resource called “Webserver.” Because AWS needs to know the properties of this instance, I’ve added them manually below.

So what’s wrong with the above code? Nothing, per say, but it’s not very efficient in regards to reusability. For starters, this code can only create a t2.micro instance size, regardless of what type of environment you’re provisioning. Does production need something bigger for performance? Does dev need something smaller to control costs? Am I asking too many questions? 🙂

In addition to limiting the size of the instance, the code can ONLY run in us-east-1. I know what you’re thinking… “I thought we added those intrinsic functions to get past that in the last post.” We did but, if you recall, imageIDs are unique among regions for images. In other words, the Amazon Linux AMI for us-east-1 is ami-a4c7edb2 but for us-east-2 the imageID is ami-8a7859ef. If you try and run this code in any other region besides us-east-1, it’ll fail as that imageID wouldn’t be available.

So let’s fix it.

To make this code reusable again, while adding additional functionality, we’re going to use the “FindinMap” intrinsic function. This function allows you to grab a value matching corresponding keys from the Mapping section of the template. In other words, we can list a variety of options in the Mappings section and choose based upon another value or an input parameter.

Below are the mappings I’ve created specifically for the use cases above.

The first mapping, named “RegiontoAMI,” lists each region and then the corresponding AMI for the Amazon Linux image. When we run the stack, we’ll have it reference the region that the stack will be provisioned in, that way it selects the correct AMI for the proper region. You can also include multiple AMIs within the same region in which you’re able to select. For example, you could add a 32-bit option and a 64-bit option if you needed that flexibility during the provisioning process.

The second mapping, named “InstanceSize,” allows us to map an environment to a particular instance size. As shown above, the dev environment will be provisioned on the t2.micro size, test to a t1.micro, and prod to a t2.small instance size. The environment will be passed in as a parameter so the user creating the stack can select the environment in which they are deploying.

So…using what we’ve learned above, let’s take a look at the new code snippet for the instance resource we’re deploying as part of this stack.

We now have a new parameter for the environment selection, the mappings we discussed above, and the new code for the “webserver” resource. Notice that instead of specifying the instance size and type, we’re now telling it to find the value from the corresponding mapping. To determine the ImageID value, we’re using the !FindinMap function. We’re telling it to look at the mapping called “RegiontoAMI,” match the first value (the current region) by referencing the “AWS::Region,” and matching the second value of “ami.” To find the instance type, we’re using the !FindinMap function to look at the “InstanceSize” mapping. It then matches the first value by referencing the Environment parameter (dev, test, prod) and then matches the second value of “instancetype”.

Phew…we’re done. Below is the code in its entirety.  Now our code is back to being regionally agnostic, along with giving us additional options to pass information to determine the size (instance type) of the EC2 instance.

Next, we’ll start breaking down the template to make each piece of them template reusable by taking advantage of nested stacks.


About The Author

Bryan Krausen

Bryan Krausen is currently working as a Technical Architect with experience in a vast number of platforms.

Bryan has been active within the VMware vExpert community for several years and is the leader of the Louisville VMware User Group (VMUG) and Louisville AWS User Group.

Leave a reply

Your email address will not be published.