Codify Your AWS Infrastructure With CloudFormation

0
40

CloudFormation is a tool for automating the creation, updating, and management of your entire resource stack. It provides a way to turn your infrastructure into code, in the form of a YAML file, which can be version controlled alongside your software.

What Is CloudFormation?

CloudFormation’s concept is pretty simple—creating resources manually can be a pain, and while it can be automated using CLI or API requests, if you need to update your stack in the future, it’s still going to be a mostly manual process. Rather than bothering with this, CloudFormation offers a way to model the structure and configuration of all of your resources.

This is done with a YAML or JSON template, which contains all the required info for your product stack, including resources that need to be created, parameters and configuration for those resources, and the outputs they return. This file can be version controlled through Git, and even used to create a continuous deployment pipeline that will automatically push changes

You don’t have to create the YAML template manually though. It’s far easier to use CloudFormation’s web based “Designer,” which will display your whole product stack visually. For example, here is one of the sample templates, for an autoscaling, load balanced WordPress deployment using an RDS instance as the database.

You can drag new components out from the provided catalogue and link components together. Updates to the visual template will update the underlying YAML template. If you click any resource in this template, it will automatically scroll to the entry in the YAML resource list. Very handy.

Once you deploy this template, all of the resources associated with it will be created in your account. When the stack needs updating, the existing resources will be updated with new configuration, old resources will be deleted if no longer used, and new resources will be spun up when added.

CloudFormation will also handle creating dependencies in the correct order, without you having to think about it yourself. For example, if you wanted to create an EC2 instance with a security group, CloudFormation will make sure to create the security group first, and then create the instance with that security group. All you have to do is link them together in the console.

The primary downside of CloudFormation is that if you’re committing to Infrastructure-as-code, you’re going to have to fully commit—making manual changes to resource configuration outside CloudFormation is unsafe, as CloudFormation updates may overwrite your manual changes to enforce what you have in your template. For example, if you deployed an elastic IP, and want to point it to a different instance, you’ll have to do so from the CloudFormation console, not from the EC2 Management Console. Technically, manual changes will persist until at least the next CloudFormation update, and if the template configuration doesn’t change in the meantime, CloudFormation won’t enforce the schema in the template. So while you may be able to get away with manual changes in the short term, it isn’t advised, and is entirely ephemeral.

Using The Online Editor

Head over to the CloudFormation Console, click “Create Stack,” and select “With new resources.”

This will open up a dialog where you’ll select your CloudFormation template. You can import an existing template from S3, but if you’re just getting started, we suggest trying out one of the sample templates. We’ll select the simple “LAMP Stack” template, which deploys a single web server. Click “View In Designer” to open the template up.

This template is pretty basic. Just an EC2 Instance, and a security group for that instance.

If you wanted to add something new to the template, the easiest way is by finding the resource in the sidebar and dragging it in. For example, if you wanted to add an Elastic IP to associate with this new instance, look in the “EC2” section to find “EIP,” and drag this in:

By default, it’s not connected to anything. You’ll need to attach it to the EC2 instance to have any effect. The purple colored dots are properties. You can drag from these properties to form links to other resources. To link the Elastic IP, drag the top corner “EIPAssociation” to the instance. Compatible resources will be highlighted in green when dragging.

If you click on a resource, you’ll be brought to the entry in the YAML template. Changes to this template will propagate to the designer, though you may have to hit the refresh button in the top right corner.

YAML Formatting

Overall, the YAML template will have a few distinct sections:

Metadata, mostly used by the CloudFormation Designer to keep track of where things are visually, but can also be used for general metadata.

Parameters, arguments that are passed to the CloudFormation console and can be passed into the template at runtime. For example, the default template includes a few parameters for specifying the MySQL database name, username, and password, such as:

DBName:
Default: MyDatabase
Description: MySQL 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.

Mappings, these are a little complicated, but they’re basically like case statements. You can use them to change parameter values depending on a key. For example, AWS uses this to change the AMI ID based on the region the template is being deployed into. You can use the Fn::FindInMap intrinsic function to look up these values elsewhere in the template. You may want to read more on this from the AWS docs.

Mappings:
RegionMap:
us-east-1:
“HVM64”: “ami-0ff8a91507f77f867”
us-west-1:
“HVM64”: “ami-0bdb828fd58c52235”
eu-west-1:
“HVM64”: “ami-047bb4163c506cd98”
ap-southeast-1:
“HVM64”: “ami-08569b978cc4dfa10”
ap-northeast-1:
“HVM64”: “ami-06cd52961ce9f0d85”

Conditions, which allow CloudFormation to only deploy resources if conditions are met. For example, you can use this to deploy specific resources in production, testing, and staging environments, but not in development ones.

Conditions:
CreateProdResources: !Equals [ !Ref EnvType, prod ]

Transforms, which allow for custom processing on your template before it is deployed. This is a bit of a niche feature, but it’s used by SAM for deploying Lambda functions. You’ll have to set this up manually, and then call it by name:

Transform: [MyMacro, AWS::Serverless]

Outputs, which allow you to link resources between stacks, or simply return a response. You can think of these like public versus private variables.

Outputs:
BackupLoadBalancerDNSName:
Description: The DNSName of the backup load balancer
Value: !GetAtt BackupLoadBalancer.DNSName
Condition: CreateProdResources
InstanceID:
Description: The Instance ID
Value: !Ref EC2Instance

And finally, Resources, which is simply an array of all of the resources in the template. This will vary wildly depending on what you’re using, as each service will have their own properties. For example, an EC2 instance with a custom AMI may look something like this:

Resources:
MyEC2Instance:
Type: “AWS::EC2::Instance”
Properties:
ImageId: “ami-0ff8a91507f77f867”

You can consult AWS’s full schema reference for more information on the particular service you’re using, or the resource and property reference.