In the previous post, we've used AWS console to create a VPC, and deployment of a sample web server on a new EC2 instance.
However, if there is a need to deploy this automatically, we can use AWS CloudFormation.
The CloudFormation uses a template YAML or JSON file (aka stack) to create AWS entities.
Unlike AWS CLI, the CloudFormation support add, update, and delete of the AWS entities as a transaction, so if one of the entities creation had failed, the entire entities in the stack will be rolledback. Also, update of the AWS entities in the template file, will update only the required items in the stack.
Stack Install and Update
To use the CloudFormation, I've found the best method is to use a CLI, which installs or updates the stack, based of if it exists or not.
deploy.sh
#!/bin/bash
set -e
cd "$(dirname "$0")"
deployFolder=${PWD}
export AWS_SHARED_CREDENTIALS_FILE=${deployFolder}/aws-config/credentials
export AWS_CONFIG_FILE=${deployFolder}/aws-config/config
export AWS_PAGER=""
stackName=mystack
stackExists=$(aws cloudformation describe-stacks | jq -r ".Stacks[].StackName" | grep ${stackName} | wc -l)
if [[ "${stackExists}" = "0" ]]; then
echo "install stack"
aws cloudformation create-stack --stack-name ${stackName} --template-body file://po.yaml
aws cloudformation wait stack-create-complete --stack-name ${stackName}
else
echo "update stack"
aws cloudformation update-stack --stack-name ${stackName} --template-body file://po.yaml
aws cloudformation wait stack-update-complete --stack-name ${stackName}
fi
The Template File
Parameters:
LatestAmiId:
Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: sample-vpc
Now we present the resources that we want to configure, starting with the VPC configuration. Next we want to configure the subnet.
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: us-east-1a
Tags:
- Key: Name
Value: sample-subnet1
Notice that the subnet configuration requires the VPC ID. Here we use the CloudFront template function !Ref to fill this information. Next we add the internet gateway, and assign it to the VPC.
InternetGateway:
Type: AWS::EC2::InternetGateway
DependsOn: VPC
Properties:
Tags:
- Key: Name
Value: sample-route-table
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
Using the AWS console handles these two resources in one dialog, but in the template file, we are exposed to the real AWS implementation, hence we are required to make some more configuration.
Let's add the route table, and add the internet gateway route:
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: sample-route-table
RouteTableAssociate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: Subnet1
RouteTableId:
Ref: RouteTable
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
And lastly, add the EC2 instance, and assign an elastic IP to it.
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VPC
GroupDescription: the ec2 security group
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: sample-ec2-security-group
EC2:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: !Ref LatestAmiId
SubnetId: !Ref Subnet1
KeyName: PO
SecurityGroupIds:
- !Ref SecurityGroup
Tags:
- Key: Name
Value: sample-web
ElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
InstanceId: !Ref EC2
Tags:
- Key: Name
Value: sample-elastic-ip
Final Note
Parameters:
LatestAmiId:
Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: sample-vpc
Subnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.1.0/24
AvailabilityZone: us-east-1a
Tags:
- Key: Name
Value: sample-subnet1
Subnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: 10.0.2.0/24
AvailabilityZone: us-east-1b
Tags:
- Key: Name
Value: sample-subnet1
InternetGateway:
Type: AWS::EC2::InternetGateway
DependsOn: VPC
Properties:
Tags:
- Key: Name
Value: sample-route-table
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: sample-route-table
RouteTableAssociate:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId:
Ref: Subnet1
RouteTableId:
Ref: RouteTable
PublicRoute:
Type: AWS::EC2::Route
DependsOn: AttachGateway
Properties:
RouteTableId: !Ref RouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref VPC
GroupDescription: the ec2 security group
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: sample-ec2-security-group
EC2:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: !Ref LatestAmiId
SubnetId: !Ref Subnet1
KeyName: PO
SecurityGroupIds:
- !Ref SecurityGroup
Tags:
- Key: Name
Value: sample-web
ElasticIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
InstanceId: !Ref EC2
Tags:
- Key: Name
Value: sample-elastic-ip
No comments:
Post a Comment