Automate application deployment with AWS CloudFormation Part 1 - Parameters

Deploying applications/services to Amazon Web Services (AWS) via the management console is manually intensive, time consuming, and not repeatable.

AWS CloudFormation provides a configuration driven approach to automate AWS resource creation. CloudFormation can be used to provision the software stack (think EC2 instances, RDS database instances, load balancers, etc) for an entire application. Once the CloudFormation template is created mirrored copies of the application stack can be created in a cookie cutter fashion.

In CloudFormation parlance, a "stack" is a collection of related resources where the resource creation, update, and deletion is managed as a single unit.

I recently  migrated my person website www.robhughes.net into the AWS cloud. The website uses Ruby on Rails, Apache httpd, and Passenger backed by a MySQL database. The static image content for the photo gallery was moved into an S3 bucket. While I don't anticipate a heavy load on the website I took care to architect the AWS application to take advantage of EC2 autoscaling for performance and availability zones for high availability.

CloudFormation is particularly good at provisioning all the "one time" infrastructure resources driven by configuration parameters supplied at the time the stack is created. Examples of "one time" resources are things like RDS instances, autoscaling groups, autoscaling policies, CloudWatch alarms, and load balancers. The "one time" resources tend to come into existence and live for the lifetime of the stack. CloudFormation also provides the hooks to configure and install software on "dynamically created" resources, like EC2 instances, that are created and destroyed as part of an autoscaling group.

At the heart of CloudFormation is the CloudFormation template. The template is a json-formatted document that contains all the configuration information needed to create all the AWS resources and link them together at the time the stack is created.

A barebones CloudFormation template looks like:

{
  "AWSTemplateFormatVersion" : "version date",
  "Description" : "JSON string",
  "Parameters" : {
    set of parameters
  },
  "Mappings" : {
    set of mappings
  },
  "Conditions" : {
    set of conditions
  },
  "Resources" : {
    set of resources
  },
  "Outputs" : {
    set of outputs
  }
}

For brevity I'll focus on the "Parameters" section in this blog and the "Resources" section in part 2. For additional detail regarding the purpose of each template section see this link.

CloudFormation templates can can get large pretty quickly. Click here to download the entire CloudFormation template for the www.robhughes.net (RHDN for short) website. I recommend opening up the RHDN CloudFormation template in a separate window/tab so you can quickly refer to the contents throughout this series of blogs. 

Most CloudFormation templates I have viewed come with an embedded warning which I will dutifully repeat here:

WARNING: This template creates one or more Amazon EC2 instances, an Elastic Load Balancer and an Amazon RDS DB instance. You will be billed for the AWS resources used if you create a stack from this template.

If you use the RHDN template to create a CloudFormation stack you could incur charges! See the What is the AWS Free Usage Tier regarding how you can get started using AWS for free.

Parameters

The parameters section of the template is used to query for information at the time the stack is created. Each parameter contained in the template must have a value entered at stack creation time. Instead of having all values fixed, parameters allow for each each resource stack to be customized. Some properties, like the "Description" and "ConstraintDescription" properties, within a parameter aid understanding regarding what the parameter is used for and how to select acceptable values respectively. Many properties constrain the format or selection of values that are entered. For example the "Type", "AllowedValues", and "AllowedPattern" properties constrain the values that will be accepted. The aptly named "Default" property is used to specify a default value. Another important property is the "NoEcho" property which is used for sensitive fields to indicate the parameter value should be obscured when the parameter is displayed.

Here is an example of a parameter named "InstanceType" which allows the EC2 instance type to be selected from a list of available AWS instance types for EC2 instances created by the stack.

"InstanceType" : {
  "Description" : "WebServer EC2 instance type",
  "Type" : "String",
  "Default" : "t1.micro",
  "AllowedValues" : [     
    "t1.micro",
    "m1.small",
    "m1.medium",
    "m1.large",
    "m1.xlarge",
    "m2.xlarge",
    "m2.2xlarge",
    "m2.4xlarge",
    "m3.xlarge",
    "m3.2xlarge",
    "c1.medium",
    "c1.xlarge",
    "cc1.4xlarge",
    "cc2.8xlarge",
    "cg1.4xlarge"
  ],
  "ConstraintDescription" : "must be a valid EC2 instance type."
},

Here is another parameter which allows the password for the database to be specified at stack creation time:

``` "DBPassword": { "NoEcho": "true", "Description" : "Password for MySQL database access", "Type": "String", "MinLength": "8", "MaxLength": "41", "AllowedPattern" : "[a-zA-Z0-9]*", "ConstraintDescription" : "must contain only alphanumeric characters." },

The AWS Management Console provides a simple CloudFormation workflow to graphically walk you through stack creation. The workflow queries for the location of the CloudFormation template then reads the template, discovers the parameters specified within the template, then displays a page allowing the user to enter or modify values for each parameter.

Figure 1. AWS Web Console CloudFormation Parameter Entry Page

Cloudformation Specify Parameters Page

A command line interface (CLI) is also available to allow stack creation to be scripted. The CLI provides a mechanism to enter parameters by specifying key/value pairs where the key is the associated parameter name. Another CLI approach is to capture parameter key/value pairs in a separate file and then specify the location of the file via a CLI option.

Notice on the "Specify Parameters" page above an invalid instance type was entered. The constraints for the parameters are not validated until you click the "Create" button on the last page of the CloudFormation workflow. The following error message would be displayed due to the invalid instance type:

Figure 2. AWS Web Console CloudFormation Review Page With Constraint Violation

Cloudformation Parameter Constraint Violation Message

CloudFormation will not continue on and create the resource stack until all constraint violations are resolved. This does provide a rudimentary way to prevent invalid parameters values from being entered that could later cause stack resources from being created.

Notice the "KeyName" parameter in Figure 1. If the stack to be created contains EC2 resources you will likely want to log into EC2 instances via ssh at some point to perform maintenance or troubleshooting. The KeyName parameter in this template is used to specify the name of the ssh key pair that will be allowed to ssh into EC2 instances created as part of the stack. When you create an AWS account you will create at least one key pair that can be used for such purposes.

That's it for this blog. See Part 2 in this blog series for a discussion of the CloudFormation template "Resources" section.