How to build a highly available AWS EC2 application infrastructure
This how-to assumes:
- Basic familiarity with System Initiative
- You have completed the build an AWS VPC with System Initiative tutorial (and not deleted the resulting resources)
It will teach you how to create a highly available application architecture and manage it with System Initiative.
We will cover:
- The creation an EC2 Launch Template and AutoScaling group, with a simple Python application
- An AWS Application Load Balancer
- The networking required to allow the application instances to serve traffic to the application
Setup
All activities in this how-to happen within a configured VPC, AWS Region and AWS Credential.
Start in a Change Set named EC2 HA How-to.
Walkthrough
What it will look like
When you are through with this guide, you should have Components that look like this in your Diagram:

Create a Loadbalancer Component

Add a AWS::ElasticLoadBalancingV2::LoadBalancer to your VPC How-to vpc frame.
Set the Component type to Down Frame.
Set the Component name to application-alb.
Set the IpAddressType to ipv4.
Set the Name to application-alb.
Set the Scheme to internet-facing.
Set the Type to application.
Connect the Subnet Id Output Socket of each of the public subnet Components to the Subnets Input Socket of the application-alb Component.
Create an EC2 security group Component for the Loadbalancer

Add a AWS::EC2::SecurityGroup to your VPC How-to vpc frame.
Set the Component name to alb-sg.
Set the GroupDescription to be ALB to the world
Set the GroupName to alb-sg.
Connect the Group Id Output Socket of alb-sg Component to the Security Groups Input Socket of the application-alb frame.
Create an EC2 Ingress Rule Component

Add a AWS::EC2::SecurityGroupIngress Component to your application-alb loadbalancer frame.
Set the Component name to alb-80-ingress.
Set the IpProtocol to TCP.
Set CidrIp to be 0.0.0.0/0.
Set the Description to Public traffic to HTTP 8080.
Set FromPort to be 80.
Set ToPort to be 80.
Connect the Group Id Output Socket of alb-sg Component to the Group Id Input Socket of this alb-8080-ingress Component.
Create a Listener Component

Add a AWS::ElasticLoadBalancingV2::Listener Component to your application-alb loadbalancer frame.
Set the Component type to Down Frame.
Set the Component name to HTTP:80.
Set the Port to be 80.
Set the Protocol to be HTTP.
Resize the frame to be large enough to fit another Component.
Create a Target Group

Add a AWS::ElasticLoadBalancingV2::TargetGroup Component to your Listener frame.
Set the Component name to app-tg.
Set HealthCheckEnabled to TRUE.
Set HealthCheckIntervalSeconds to 30 seconds.
Set HealthCheckPath to /.
Set HealthCheckPort to 8080.
Set HealthCheckProtocol to HTTP.
Set HealthCheckTimeoutSeconds to 5.
Set HealthyThresholdCount to 5.
Set IpAddressType to ipv4
Set Name to be app-tg.
Set Port to 8080.
Set Protocol to HTTP.
Set ProtocolVersion to HTTP1
Set TargetType to instance.
Set UnhealthyThresholdCount to be 2.
Set HttpCode to 200.
Create a Listener Default Action

Add a Listener DefaultActions Component to your Listener frame.
Set the Component name to listener-actions.
Set Type to forward.
Connect the Target Group Arn Output Socket of the app-tg Component to the Target Group Arn Input Socket of the listener-actions Component.
Connect the Default Actions Output Socket of the listener-actions Component to the Default Actions Input Socket of the HTTP:8080 Listener Component.
Create a Generic Frame

Add a Generic Frame Component to your VPC frame.
Set the Component name to be Application.
Resize the frame to hold many Components.
Create an IAM Role

Add an AWS::IAM::Role Component to your Generic Application frame.
Set the Component name to application-role.
Set the RoleName to application-role.
Set the Path to /si-tutorial/.
Set the Description to EC2 Application Role.
Create an AWS IAM Policy Statement

Add an AWS::IAM::PolicyStatement Component within the application-role AWS IAM Role frame.
Set the Component name to allow-ec2.
Add an array item to the Action array.
Set the [0] value for the Action array to sts:AssumeRole.
Set the Effect to Allow.
Create an AWS IAM AWS Service Principal

Add an AWS::IAM::ServicePrincipal Component within the application-role AWS IAM Role frame.
Set the Component name to ec2-service.
Set the Service to ec2.amazonaws.com.
Connect the Principal Output Socket of the ec2-service Service Principal to the Principal Input Socket of your allow-ec2 AWS Policy Statement.
Create an IAM Instance Profile

Add an AWS::IAM::InstanceProfile to your Generic Application frame.
Set the Component name to application-instance-profile-how-to.
Set the InstanceProfileName to application-instance-profile-how-to.
Set the Path to /si-tutorial/.
Connect the RoleName Output Socket of application-role IAM Role Component to the RoleName Input Socket of the application-instance-profile Instance Profile Component.
Create a Security Group Component for the Application

Add a AWS::EC2::SecurityGroup Component to your Generic Application frame.
Set the Component name to application-sg
Set the GroupDescription to be Application Security Group
Set the GroupName to application-sg.
Create an EC2 Ingress Rule Component

Add a AWS::EC2::SecurityGroupIngress to your Generic Application frame.
Set the Component name to be application-8080-ingress.
Set the IpProtocol to TCP.
Set the Description to be 8080 inbound to the node.
Set the FromPort to 8080.
Set the ToPort to 8080.
Connect the Group Id Output Socket of application-sg Component to the Group Id Input Socket of this application-8080-ingress Component.
Connect the Group Id Output Socket of alb-sg Component to the SourceSecurityGroupId Input Socket of this application-8080-ingress Component.
Create a Key Pair Component

Add a AWS::EC2::KeyPair Component to your Generic Application frame.
Set the Component name to application-key-pair.
Set the KeyName to application-key-pair.
Create an AMI Component

Add an AWS::EC2::AMI to your Generic Application frame.
Set the Component name to be Amazon Linux 2023 AMI.
Set the ImageId to be ami-08b5b3a93ed654d19.
Create a Launch Template Component

Add a AWS::EC2::LaunchTemplate Component to your Generic Application frame.
Set the Component name to application-launch-template-how-to.
Set the LaunchTemplateName to application-launch-template-how-to.
Set the InstanceType to be t3.small
Set the UserData to be a base64 encoded version of the following code snippet:
#!/bin/bash
# Update the system
yum update -y
# Install Python 3 and pip
yum install -y python3 python3-pip
# Install Git
yum install -y git
# Create a directory for the application
mkdir -p /opt/flask-app
cd /opt/flask-app
# Create the application file
cat <<EOT > app.py
from flask import Flask
import requests
import os
app = Flask(__name__)
def get_instance_id():
try:
instance_id = requests.get("http://169.254.169.254/latest/meta-data/instance-id", timeout=2).text
except requests.exceptions.RequestException:
instance_id = "Unknown (not running on EC2)"
return instance_id
@app.route('/')
def hello():
instance_id = get_instance_id()
return f"""
<h1>Hello from EC2!</h1>
<p>This response is served by instance: {instance_id}</p>
<p>Refresh the page to see load balancing in action.</p>
"""
@app.route('/health')
def health_check():
return "OK", 200
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
EOT
# Install the Python dependencies
pip3 install --ignore-installed requests Flask
# Create a systemd service file for the Flask app
cat <<EOT > /etc/systemd/system/flask-app.service
[Unit]
Description=Flask App
After=network.target
[Service]
User=root
WorkingDirectory=/opt/flask-app
ExecStart=/usr/bin/python3 /opt/flask-app/app.py
Restart=always
[Install]
WantedBy=multi-user.target
EOT
# Reload systemd, enable and start the Flask app service
systemctl daemon-reload
systemctl enable flask-app
systemctl start flask-appConnect the Group ID Output Socket of application-sg Component to the Launch Template Data Security Group Ids Input Socket of this application-launch-template Component.
Connect the Key Name Output Socket of application-key-pair-how-to Component to the LaunchTemplateDataKeyName Input Socket of this application-launch-template Component.
Connect the ARN Output Socket of application-instance-profile Component to the Launch Template Data Iam Instance Profile Arn Input Socket of this application-launch-template Component.
Connect the Image ID Output Socket of Amazon Linux 2023 AMI Component to the LaunchTemplateDataImageId Input Socket of this application-launch-template Component.
Create an AutoScaling Group Component

Add an AWS::AutoScaling::AutoScalingGroup Component to the Generic Application frame.
Set the Component name to application-asg.
Set MaxSize to be 1.
Set MinSize to be 0.
Set AutoScalingGroupName to be application-asg.
Set DesiredCapacity to be 1.
Set LaunchTemplate Version to 1.
Connect the Launch Template Id Output Socket of application-launch-template Component to the Launch Template Id Input Socket of this application-asg Component.
Connect the Subnet Id Output Socket of each of the Public subnet Components to the VPC Zone Identifier Input Socket of this application-asg Component.
Connect the Target Group Arn Output Socket of the app-tg Target Group to the Target Group ARN Input Socket of this application-asg Component.
Apply your Change Set

Press Escape or click anywhere on the canvas background to select the Workspace.
Click the Apply Change Set button to:
- Create a Key Pair
- Create 2 Security Groups and associated ingress rules
- Create an application load balancer, a listener and a target group
- Create an IAM Role and IAM Instance Profile
- Create a Launch Template and an AutoScaling Group (that will create an instance)
Explore your resources
Review the completed AWS resources by clicking the Resource sub-panel for each of your new resources.
Clean Up
Create a new Change Set called Clean up How-to
Delete your VPC How-to VPC frame. All of the Components inside will be marked for deletion.
Click Apply Change Set.
All your new resources should be deleted from your AWS account.
Vocabulary
In this guide bits of System Initiative Vocabulary will be shown with a capital letter. All definitions for these can be found here: System Initative - Vocabulary