Building a 3-Tier Architecture for a Web App in AWS
Goal: Set up a highly scalable, highly available, and fault tolerant infrastructure for a web app running in AWS.
Inventory
- VPC provides the virtual network in AWS
- Two Availability Zones (AZ) for high availability and fault tolerance
- Public Subnet in each availability zone for resources that need to access the internet
- Private Subnet in each availability zone for resources that won’t connect to the internet
- Internet Gateway to enable 2-way communication between resources in the public subnets and resources on the internet
- NAT Gateway to allow resources in private subnet to initiate outbound connection to the internet
- Route Table contains routes for directing network traffic
- Security Groups to control traffic for the load balancer, EC2 instance and database
- Auto Scaling Group dynamically increases and decreases capacity and provides better fault tolerance for your application servers
- EC2 Instances to host the web application
- Application Load Balancer to distribute traffic to the EC2 instances
- RDS Subnet Group to group subnets for DB instance use
- MySQL database in multiple AZs for high availability and to store app data
First of all, what is a 3-tier architecture?
A three-tier architecture consists of three separate tiers: the web tier, the application tier, and the database tier. This is the most common architecture for web-based applications like e-commerce websites.
The web tier, also known as presentation tier, is responsible for displaying the information in the form of a graphical user interface (GUI). This is the layer with which end users typically interact with the app. The load balancer on the web tier is responsible for even distribution and forwarding of http requests to the application tier.
The application tier consists of the application servers responsible for all of the business logic processing. Here the app’s core functionality is controlled within this tier. It also contains an auto scaling group to scale in or out servers as needed. This is the only tier that talks to the web and database tier because of it’s unique location in the “stack.”
Finally, the database layer will consist of data resources. These databases are connected to the application layer, and only the application layer. The databases are not publicly accessible.
Prerequisites:
- An AWS account created after January, 2006
- An IAM user with admin privileges
- Commitment to terminate resources provisioned at the end to avoid an unexpected bill
NOTE: Almost all the services used in this tutorial are within the AWS free tier, but there are a few services that cost very little to use. Keep that in mind, but consider it your tuition.
Tip: After you sign in to your AWS account, you should see a Search bar somewhere near the top left of your screen. There are many ways to get to a service. Use the search bar to find AWS services quickly by typing the name of the service (for example, VPC) and hit Enter. A drop down should appear with results, click on the matching result.
Create VPC — Virtual Private Cloud: Your virtual network in AWS
- Go to VPC (hint: use the Search bar) and click the Create VPC button
- Choose Create VPC
- Resources to create: VPC only
- Name tag: Project-VPC
- IPv4 CIDR: 10.0.0.0/16
- Choose Create VPC
Create Subnets — 2 public subnets, 4 private subnets
- Go to VPC, on the left navigation panel, select Subnets
- Click Create subnet
Let’s configure Subnet 1
- Select the Project-VPC from the VPC ID dropdown
- Subnet name: PublicSubnet1
- Availability zone: us-east-1a
- IPv4 CIDR block: 10.0.1.0/24
- Choose Add new subnet (DO NOT CLICK Create Subnet yet)
Heads up! We will be creating 5 more subnets… Recall, we are out to create 6 subnets in total.
Repeat steps 2 through 5 above for each of the 5 additional subnets using the configurations below:
Let’s configure Subnet 2
- Subnet name: PublicSubnet2
- Availability zone: us-east-1b
- IPv4 CIDR block: 10.0.2.0/24
- Choose Add new subnet
Let’s configure Subnet 3
- Subnet name: PrivateSubnet1
- Availability zone: us-east-1a
- IPv4 CIDR block: 10.0.11.0/24
- Choose Add new subnet
Let’s configure Subnet 4
- Subnet name: PrivateSubnet2
- Availability zone: us-east-1b
- IPv4 CIDR block: 10.0.12.0/24
- Choose Add new subnet
Let’s configure Subnet 5
- Subnet name: PrivateSubnet3
- Availability zone: us-east-1a
- IPv4 CIDR block: 10.0.13.0/24
- Choose Add new subnet
Let’s configure Subnet 6 (this is the step where we will create all 6 subnets)
- Subnet name: PrivateSubnet4
- Availability zone: us-east-1b
- IPv4 CIDR block: 10.0.14.0/24
- Choose Create subnet
At this point you should have configured and created 6 subnets in one swoop!
Create Internet gateway (IGW)
- Go to VPC, on the left navigation panel, select Internet gateways
- Choose Create internet gateway
- Name tag: Project-IGW
- Choose Create internet gateway
After Internet gateway is created, we need to attach it to the VPC
- Click on Attach to a VPC button on the green banner
- Select the Project-VPC from the Available VPCs dropdown
- Choose Attach internet gateway
Create NAT (Network Address Translation) Gateways
Let’s create NAT gateway for Availability Zone 1
- Go to VPC, on the left navigation panel, select NAT gateways
- Choose Create NAT Gateway
- Name: Project-NATGateway1
- Subnet: PublicSubnet1 (select Subnet dropdown to choose the matching subnet)
- Elastic IP allocation ID: select Allocate Elastic IP
- Choose Create NAT gateway
Let’s create NAT gateway for Availability Zone 2
- Go to VPC, on the left navigation panel, select NAT gateways
- Choose Create NAT Gateway
- Name: Project-NATGateway2
- Subnet: PublicSubnet2 (select Subnet dropdown to choose the matching subnet)
- Elastic IP allocation ID: select Allocate Elastic IP
- Choose Create NAT gateway
Create Route tables
Let’s create Public Route table
- Go to VPC, on the left navigation panel, select Route tables
- Choose Create route table
- Name: PublicRouteTable
- VPC: Project-VPC (select VPC dropdown to choose matching VPC)
- Choose Create route table
- On Routes tab, choose Edit routes to add route to direct internet-bound traffic to the internet gateway
- Select Add route
- Destination: 0.0.0.0/0
- Target: Internet Gateway, then choose Project-IGW from the dropdown
- Choose Save changes
- Choose the Subnet associations tab for the PublicRouteTable
- Select Edit subnet associations
- Check the box for PublicSubnet1 and PublicSubnet2
- Select Save associations
Let’s create Private Route table 1
- Go back to Route tables on the left navigation panel
- Click Create route tables
- Name: PrivateRouteTable1
- VPC: Project-VPC (select VPC dropdown to choose matching VPC)
- Choose Create route table
- On Routes tab for PrivateRouteTable1, choose Edit routes to add route to direct internet-bound traffic to the NAT gateway in Availability Zone 1 (us-east-1a)
- Select Add route
- Destination: 0.0.0.0/0
- Target: NAT Gateway, then choose Project-NATGateway1 from the dropdown
- Choose Save changes
- Choose the Subnet associations tab for PrivateRouteTable1
- Select Edit subnet associations
- Check the box for PrivateSubnet1 and PrivateSubnet3
- Select Save associations
Let’s create Private Route table 2
- Go back to Route tables on the left navigation panel
- Click Create route tables
- Name: PrivateRouteTable2
- VPC: Project-VPC (select VPC dropdown to choose matching VPC)
- Choose Create route table
- On Routes tab for PrivateRouteTable2, choose Edit routes to add route to direct internet-bound traffic to the NAT gateway in Availability Zone 2 (us-east-1b)
- Select Add route
- Destination: 0.0.0.0/0
- Target: NAT Gateway, then choose Project-NATGateway2 from the dropdown
- Choose Save changes
- Choose the Subnet associations tab for PrivateRouteTable2
- Select Edit subnet associations
- Check the box for PrivateSubnet2 and PrivateSubnet4
- Select Save associations
Create Security Groups
First, let’s create the security group for the ALB (Application Load Balancer)
- Go to VPC, on the left navigation panel, select Security groups
- Choose Create security group
- Security group name: Project-ALB-SG
- Description: Allow web access to the load balancer
- VPC: Project-VPC (Watch out: this sometimes defaults to the Default VPC, be sure to change it to match your VPC)
- For Inbound rules, choose Add rule
- Type: All traffic
- Source: Anywhere IPv4
- For Tags, choose Add new tag
- Key: Name
- Value: Project-ALB-SG
- Choose Create security group
Next, let’s create the security group for the EC2 (Elastic Compute Cloud) instances
- On the left navigation panel, choose Create security group
- Security group name: Project-EC2-SG
- Description: Allows load balancer to access the EC2 instances
- VPC: Project-VPC (Watch out: this sometimes defaults to the Default VPC, be sure to change it to match your VPC)
- For Inbound rules, choose Add rule
- Type: HTTP
- Source: Project-ALB-SG (choose from Source dropdown)
- Choose Add rule to add another rule
- Type: Custom TCP
- Port: 8443
- Source: Project-ALB-SG (choose from Source dropdown)
- For Tags, choose Add new tag
- Key: Name
- Value: Project-EC2-SG
- Choose Create security group
Finally, let’s create the security group for the RDS (Relational Database Service) instances
- Choose Create security group
- Security group name: Project-RDS-SG
- Description: Allows application to access the RDS instances
- VPC: Project-VPC (Watch out: this sometimes defaults to the Default VPC, be sure to change it to match your VPC)
- For Inbound rules, choose Add rule
- Type: MYSQL/Aurora
- Source: Project-EC2-SG (choose from Source dropdown)
- For Tags, choose Add new tag
- Key: Name
- Value: Project-RDS-SG
- Choose Create security group
We are officially done with configuring our VPC… Let’s move on. Shall we?
Create Subnet group
- Go to RDS, on the left navigation panel choose Subnet groups
- Choose Create DB subnet group
- Name: Project-RDS-Subnet-group
- Description: Subnet group for RDS
- VPC: Project-VPC (choose from the VPC drop down)
- Availability Zones: select us-east-1a and us-east-1b from dropdown
- Subnets: select 10.0.13.0/24 and 10.0.14.0/24
- Choose Create
Let’s create database in private subnets
- On the left navigation panel, choose Databases
- Choose Create database
- Choose a database creation method: Standard Create
- Engine type: Amazon Aurora
- Available versions: Aurora(MYSQL 5.7) 2.07.2
- Templates: Dev/Test
- For Settings
- DB Cluster identifier: Project-Cluster
- Master username: admin
- Master password: testingrdscluster
- Confirm password: testingrdscluster DB instance class: Burstable classes and db.t3.small
- Multi-AZ deployment: Create an Aurora Replica or Reader node in a different AZ
- Virtual private cloud (VPC): Project-VPC (it defaults to the Default VPC, be sure to change it to match your VPC)
- Subnet group: project-rds-subnet-group
- Public access: No
- Existing VPC security group: Choose existing Project-RDS-SG and remove the default
- For Monitoring
- Uncheck Enable Enhanced monitoring
- Expand Additional configuration
- Initial database name: Population
- Choose Create database
To save your database connection details, select View connection details. You’ll not have access to your password after you leave this page
It takes a while to create the databases. Wait to be sure status of the Writer Instance is Available.
Choose project-cluster-instance-1 and copy the Endpoint name for the Writer instance
Your RDS Cluster endpoint should look similar to this: project-cluster-instance-1.cgfxcdec7czq.us-east-1.rds.amazonaws.com
Create Launch Template
- Go to EC2, on the left navigation panel, select Launch Templates
- Choose Create launch template
- Launch Template name: Project-EC2-LaunchTemplate
- Template version description: Template to launch EC2 instance and deploy the application
- For Launch template contents
- Choose Amazon Linux AWS AMI under Quick Start
- Choose Amazon Linux 2 AMI(HVM), SSD Volume Type (Free tier eligible)
- Instance type: t2.micro (Free tier eligible)
- Expand Network settings
- Security groups: Project-EC2-SG
- Expand Advanced details
- For IAM instance profile
- Choose Create new IAM profile role to go to a new browser tab to create a role
- Choose Create role
- Choose AWS service
- Choose EC2 under Common use cases
- Choose Next
- In the Permission policies search box, search for and add these 2 policies, one at a time.
AmazonS3FullAccess
AmazonRDSReadOnlyAccess
- Choose Next
- Role name: IAMInstanceProfile
- Choose Create role
- Return to EC2 Launch template page after creating the role
- Refresh the dropdown by clicking the refresh icon on the rightChoose IAM Instance profile: IAMInstanceProfile
- Copy the below script in the user data section (located at the very bottom) of your template
Replace the value of DATABASE_HOST with RDSClusterEndPoint copied earlier
#!/bin/bash
yum update -y
yum install -y python3
aws s3 cp s3://us-west-2-aws-training/awsu-spl/SPL-TF-200-NWCDVW-1/1.0.6.prod/scripts/vpcapp.zip .
unzip vpcapp.zip
cd vpcapp
pip3 install -r requirements.txt
export DATABASE_HOST=labvpcdbcluster-0.cpf3cewlmrdk.us-east-1.rds.amazonaws.com
export DATABASE_USER=admin
export DATABASE_PASSWORD=testingrdscluster
export DATABASE_DB_NAME=Population
cd loaddatabase
python3 database_populate.py
cd ..
python3 application.py
- Choose Create launch template
Create Auto Scaling Group
- Go to EC2, on the left navigation panel, select Auto Scaling Groups
- Choose Create Auto Scaling group
- Auto Scaling group name: Project-ASG
- Launch template: choose Project-ASG-Launchtemplate from dropdown
- Choose Next
- For Network
- VPC: choose Project-VPC from dropdown
- Availability Zones and subnets: choose PrivateSubnet1 and PrivateSubnet2
- Choose Next
- For Health checks
- Health check type: check ELB
- Choose Next
- For Group size
- Desired capacity: 2
- Minimum capacity: 1
- Maximum capacity: 3
- Choose Next
- Choose Next
- Select Add tags
- Key: Name
- Value: App server
- Choose Next
- Choose Create Auto Scaling group
Create Application Load Balancer
- Go to EC2, on the left navigation panel, select Load Balancers
- Select Create Load Balancer
- Choose Create (Application Load Balancer)
- Load balancer name: Project-ALBFor Network mapping
- VPC: Project-VPC
- Mappings:
check us-east-1a box and choose PublicSubnet1
check us-east-1b box and choose PublicSubnet2
- Security groups: choose Project-ALB-SG from the dropdown and remove the default security group
- For Listeners and routing
- Click Create target group (This takes you to a new browser tab to configure your target group)
- Target group name: Project-Targetgroup
- Protocol: HTTP
- Port: 8443
- Choose Next
- For Available instances
- Check the boxes only for the available instances with App server name
- Port for the selected instances: 8443
- Click Include as pending below
- Choose Create target group
Return to the browser tab with the Create Application Load Balancer
- For Listeners and routing
- Default action: choose Project-Targetgroup from dropdown (you may need to refresh the dropdown — click the refresh icon to the right)
- Choose Create load balancer
- Choose View load balancer
Wait a few minutes for the load balancer to be in Active state
Copy the the DNS name for the Project-ALB load balancer and paste it into your browser to view the running application
If everything works well, you should be greeted with a webpage…
One more thing…
In order to take advantage of autoscaling, we need to connect our Load balancer to the Auto scaling group. This is important so that if any of our EC2 instances goes down for whatever reason, Autoscaling kicks in to bring the number of instances to our desired capacity of 2, but more importantly, the load balancer is notified of this activity and can begin sending HTTP traffic to this new instance(s).
Let’s attach the load balancer to auto scaling group
- Go to EC2, on the left navigation panel, select Auto Scaling Groups
- Click Project-ASG
- On Details tab, scroll down to Load balancing section
- Select Edit
- For Load balancing
- Check Application, Network or Gateway Load Balancer target groups box
- Choose Project-Targetgroup from the dropdown
- Choose Update
Let’s Test our Infrastructure:
High availability: The load balancer distributes traffic to the EC2 instances and you can confirm that by inspecting the availability zone (AZ) displayed at the bottom of the app in your browser. If you refresh the page multiple times, you’ll notice the availability zone (AZ) switches between us-east-1a and us-east-1b in a round robin manner, indicating the load balancer is distributing traffic to the instances in different AZs.
Fault tolerance: Go ahead and terminate one of the EC2 instances and watch auto scaling kick in by provisioning an additional instance to maintain the desired capacity of 2 and ensure the app is always available. Momentarily, only one instance is serving the app, but as soon as the another instance is up and running both servers will be serving the app.
Remember your commitment! DO NOT FORGET to terminate all resources created at the end to avoid an unexpected bill.