
Defining a CloudFormation template
The easiest way to get started with CloudFormation is to create a CloudFormation template. This template is defined in either a JSON or YAML format, with the latter being the format I recommend given YAML is much easier for humans to work with than JSON.
The CloudFormation user guide describes the template structure in great detail, however for the purposes of this book, we only need to worry about a basic template structure which is best demonstrated with a real example, which you can save in a file called stack.yml in a convenient location on your computer:
AWSTemplateFormatVersion: "2010-09-09"
Description: Cloud9 Management Station
Parameters:
EC2InstanceType:
Type: String
Description: EC2 instance type
Default: t2.micro
SubnetId:
Type: AWS::EC2::Subnet::Id
Description: Target subnet for instance
Resources:
ManagementStation:
Type: AWS::Cloud9::EnvironmentEC2
Properties:
Name: !Sub ${AWS::StackName}-station
Description:
Fn::Sub: ${AWS::StackName} Station
AutomaticStopTimeMinutes: 15
InstanceType: !Ref EC2InstanceType
SubnetId:
Ref: SubnetId
In the preceding code, the CloudFormation defines a Cloud9 management station – Cloud9 provides a cloud-based IDE and terminal, which under the hood runs on an EC2 instance in AWS. Let's walk through this example to discuss the structure and features of the template.
The AWSTemplateFormatVersion property is required, which specifies the CloudFormation template format version that is always expressed in date terms. The Parameters property defines a set of input parameters that you can supply to your template, which is a good way to deal with multiple environments where you may have different input values between each environment. For example, the EC2InstanceType parameter specifies the EC2 instance type for the management station, while the SubnetId parameter specifies the subnet the EC2 instance should be attached to. Both of these values could be different between a non-production environment and production environment, so having them as input parameters makes it easier to change depending on the target environment. Notice that the SubnetId parameter specifies a type of AWS::EC2::Subnet::Id, which means CloudFormation can use this to lookup or validate the input value. For a list of supported parameter types, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html. You can also see that the EC2InstanceType parameter defines a default value for the parameter, which will be used if no input is provided for this parameter.
The Resources property defines all of the resources in your stack – this truly is the meat or body of the template, and may contain up to two hundred resources. In the preceding code, we only define a single resource which we call ManagementStation, and this creates Cloud9 EC2 Environment, as expressed via a Type value of AWS::Cloud9::EnvironmentEC2. All resources must specify a Type property, which defines the type of resource and determines the various configuration properties available for each type. The CloudFormation user guide includes a section that defines all supported resource types, and at last count there were 300 different types of resources.
Every resource also includes a Properties property, which holds all of the various configuration properties available for the resource. In the preceding code, you can see that we have defined five different properties—the properties available will vary depending on the resource type and are fully documented in the CloudFormation user guide:
- Name: This specifies the name of the Cloud9 EC2 environment. The value of properties can be simple scalar values like a string or number, however the value can also reference other parameters or resources in the template. Notice that the value of the Name property includes what is referred to as an intrinsic function called Sub, and can be identified by the preceding exclamation mark (!Sub). The !Sub syntax is actually a shorthand for Fn::Sub, an example of which you can see with the Description property. The Fn::Sub intrinsic function allows you to define an expression that includes interpolated references to other resources or parameters in your stack. For example, the value of the Name property is ${AWS::StackName}-station, where the ${AWS::StackName} is an interpolated reference known as a pseudo parameter that will be replaced with the name of the CloudFormation stack you deploy from the template. If the name of your stack is cloud9-management, then the value of ${AWS::StackName}-station will be expanded to cloud9-management-station when your stack is deployed.
- Description: This provides a description for the Cloud9 EC2 environment. This includes an example of the long hand version of the Fn::Sub intrinsic function, which requires you to indent a new line, whereas the shorthand !Sub format allows you to specify the value on the same line as the property.
- AutomaticStopTime: This defines the amount of idle time in minutes to wait before stopping the Cloud9 EC2 instance. This saves on costs, but only when running the EC2 instance when you are using it (Cloud9 will automatically start your instance and resume your session from where you previously were). In the preceding code, the value is a simple scalar value of 15.
- InstanceType: This is the type of EC2 instance. This references the EC2InstanceType parameter using the Ref intrinsic function (!Ref is the shorthand form), which allows you to reference other parameters or resources in the stack. This means that whatever value is provided for this parameter when you deploy the stack will be applied for the InstanceType property.
- SubnetId: This is the target subnet ID where the EC2 instance will be deployed. This property references the SubnetID parameter using the long hand version of the Ref intrinsic function, which requires to you express this reference on an indented new line.