AWS CloudFormation in Action: Automating EC2 and Tomcat Setup

1. CloudFormation Overview: The Big Picture
CloudFormation is AWS’s Infrastructure as Code (IaC) tool. It allows you to describe your AWS resources in a declarative way using templates. The main advantages include:
- Automation: Resources are provisioned automatically, eliminating manual effort.
- Consistency: Ensures identical configurations across environments (e.g., development, production).
- Reusability: Templates can be reused, saving time and reducing errors.
2. Parameters: Customizing Your Stack
Parameters are like variables in programming, making the template dynamic and reusable.
Key Concepts:
- Environment-Specific Configuration:
EnvironmentName:
Description: Select the environment
Type: String
Default: dev
AllowedValues:
- dev
- prod
- Scenario: You may want fewer resources in dev to save costs and more robust configurations in prod.
- ConstraintDescription: Adds clarity by showing users why only specific values are allowed.
EC2 Instance Types:
InstanceType:
Description: Select the ec2 instance type
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t2.small
- t2.medium
- Scalability: Start small (t2.micro) for development and scale up (t2.medium) as workloads grow.
- Flexibility: Parameterizing instance types lets users adapt the infrastructure to their needs.
Availability Zone (AZ) Selection:
AvailabilityZone:
Description: select the availability zone
Type: String
Default: us-east-2a
AllowedValues:
- us-east-2a
- us-east-2b
- us-east-2c
High Availability: Distribute resources across AZs to prevent single points of failure
3. Metadata: Enhancing User Experience
Grouping Parameters for Clarity
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "EC2 Instance Configuration"
Parameters:
- InstanceType
- KeyName
- AvailabilityZone
- Purpose: Makes the stack creation interface more intuitive for users.
- Example: When creating the stack in the AWS Management Console, users will see a logical grouping of options (e.g., instance type, SSH key).
Adding Descriptive Labels
ParameterLabels:
KeyName:
default: "Be aware that once keyname is selected we cannot change it unless instance replaced"
- Importance: Provides clear instructions, reducing potential errors (e.g., understanding the immutability of SSH keys).
4. Conditions: Logical Resource Creation
Conditions allow for intelligent provisioning of resources.
Example: Elastic IP for Production Only
Conditions:
CreateEIPForProd: !Equals [ !Ref EnvironmentName, prod ]
- Cost Optimization: Elastic IPs incur charges when not in use. Only provisioning them for prod saves money.
- Dynamic Infrastructure: The same template serves both development and production needs.
5. Resources: Core Infrastructure
Security Groups: Defining Network Access
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: '8080'
ToPort: '8080'
CidrIp: 0.0.0.0/0
- Purpose: Controls which IP addresses and ports can access your instance.
- Example Use Cases:Port 22: Securely SSH into the instance.Port 8080: Access the Tomcat server running the web application.
EC2 Instance: The Workhorse
MyVMInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-063d43db0594b521b
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
UserData:
Fn::Base64: |
#!/bin/bash
sudo yum update
sudo yum -y erase java-1.7.0-openjdk.x86_64
sudo yum -y install java-1.8.0-openjdk.x86_64
sudo yum -y install tomcat8
service tomcat8 start
- What’s Happening:The specified AMI is used as a base image.Bootstrapping (UserData) installs Java 1.8, removes Java 1.7, and starts Tomcat.A simple web page is created at index.html.
Elastic IP: Static IP for Production
MyProdEIP:
Type: AWS::EC2::EIP
Condition: CreateEIPForProd
- Why It Matters: A static IP ensures your app’s endpoint doesn’t change, critical for production environments.
6. Outputs: Delivering Results
Outputs provide post-deployment information, improving usability.
Example: App URL
Outputs:
AppURL:
Description: Tomcat App Access URL
Value: !Sub 'http://${MyVMInstance.PublicDnsName}:8080/index.html'
Use Case: After deployment, users can immediately access the app without searching for the instance’s public DNS name.
Why Is This Template Useful?
- Flexibility: Parameters allow users to customize deployments for different environments.
- Cost-Effectiveness: Conditional logic ensures resources like Elastic IPs are created only when necessary.
- Automation: UserData scripts automate configuration, reducing manual effort.
- Scalability: This approach can be expanded to include additional instances, load balancers, or other resources.
AWSTemplateFormatVersion: 2010-09-09
Parameters:
EnvironmentName:
Description: Select the environment
Type: String
Default: dev
AllowedValues:
- dev
- prod
ConstraintDescription: must be development or production
InstanceType:
Description: Select the ec2 instance type
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- t2.small
- t2.medium
KeyName:
Description: Key name to SSH to VM's.
Type: AWS::EC2::KeyPair::KeyName
AvailabilityZone:
Description: select the availability zone
Type: String
Default: us-east-2a
AllowedValues:
- us-east-2a
- us-east-2b
- us-east-2c
Conditions:
CreateEIPForProd: !Equals [ !Ref EnvironmentName, prod ]
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "EC2 Instance Configuration"
Parameters:
- InstanceType
- KeyName
- AvailabilityZone
- Label:
default: "Environment Configuration"
Parameters:
- EnvironmentName
ParameterLabels:
EnvironmentName:
default: "Which environment we are planning to create this instance?"
KeyName:
default: "Be aware that once keyname is selected we cannot change it unless instance replaced"
Resources:
MySecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: My SG with port 22, 8080 and 80 inbound
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: '8080'
ToPort: '8080'
CidrIp: 0.0.0.0/0
MyVMInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-063d43db0594b521b
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
AvailabilityZone: !Ref AvailabilityZone
SecurityGroups:
- !Ref MySecurityGroup
UserData:
Fn::Base64: |
#!/bin/bash
sudo yum update
sudo yum -y erase java-1.7.0-openjdk.x86_64
sudo yum -y install java-1.8.0-openjdk.x86_64
sudo yum -y install java-1.8.0-openjdk-devel
sudo yum -y install tomcat8
service tomcat8 start
mkdir /usr/share/tomcat8/webapps/ROOT
touch /usr/share/tomcat8/webapps/ROOT/index.html
echo "Cloud Formation Tomcat8" > /usr/share/tomcat8/webapps/ROOT/index.html
MyProdEIP:
Type: AWS::EC2::EIP
Condition: CreateEIPForProd
Properties:
InstanceId: !Ref MyVMInstance
Outputs:
AppURL:
Description: Tomcat App Access URL
Value: !Sub 'http://${MyVMInstance.PublicDnsName}:8080/index.html'