AWS Best Practices: 3-Tier Infrastructure
As part of the AWS Best Practices series of posts we will talk about various topics from migration to tagging to security. Today we will discuss the 3 tier architecture pattern.
One of the most common infrastructure patterns is the 3-tier infrastructure. This pattern divides the infrastructure into 3 separate layers: one public and 2 private layers. The idea is that the public layer acts as a shield to the private layers. Anything in the public layers is publicly accessible but stuff in the private layers is only accessible from inside the network.
In addition to dividing the network into 3 separate layers we also want to implement some kind of high availability. AWS allows you to achieve high availability by distributing your application across multiple Availability Zones. Each Availability Zone is a physical data center in a different geographic location.
For this AWS best practices post we have chosen to split up our network across 3 availability zones. This gives us high availability and redundancy. If one of the availability zones is unavailable for whatever reason our application would not be affected as traffic would flow to the other 2 availability zones.
In order to split our network into 3 tiers and across 3 availability zones we have created the following subnets (see image 1 below):
- Public Layer: This layer consists of 3 public subnets. One on each Availability Zone.
- Application Layer: This layer consists of 3 private subnets. one on each Availability Zone.
- Database Layer: This layer consists of 3 private subnets. one on each Availability Zone.
What is the difference between a public subnet and a private subnet?
The main feature that makes a subnet "public" or "private" is how instances in that subnet access the internet. A public subnet is a subnet that allow its instances to access the internet via an Internet Gateway. A private subnet, on the other hand, allows its instances to access the internet via either a Network Address Translation server (NAT) or via Amazon's managed NAT service (NAT Gateway). We have chosen to use amazon's NAT gateway as it is managed by AWS and it scales out as needed.
In order to make a subnet allow access to the internet via an Internet Gateway or a NAT Gateway you have to make sure that the route tables for the subnet are set up in a way to direct traffic to the correct gateway. In our example we have set the following route tables:
10.0.0.0/24 -> local
0.0.0.0/0 -> internet-gateway-id
10.0.0.0/24 -> local
0.0.0.0/0 -> NAT-gateway-id
Image 2 below shows the route tables for both the public and the private subnets.
What goes in each of the layers?
The public (top) layer will host an internet-facing Elastic Load Balancer (ELB) and a Bastion host.
The ELB is the entry point for your application and it directs traffic to your application servers.
Note that the ELB needs to be available in all 3 availability zones. This will allow for high availability and redundancy, in case something happens to an entire availability zone. Our diagram only shows one instance of the ELB and you will only see one instance in the AWS console. However, behind the scenes AWS provisions multiple instances of the ELB based on what availability zones have EC2 instances behind that load balancer.
The Bastion host (also known as Jump host) is the server that will allow you to connect to your application servers (or any other servers in the private subnets) via SSH.
The second layer is the application layer, this is where your application servers live. In our case we have wrapped our application server with an AutoScale Group. This will allow our application to scale up if more servers are needed or to recover in the case one of the availability zones is out of service. In the case where an entire availability zone is out of service the load balancer is smart enough to know that and it will scale up in a different availability zone.
The third and last layer is the database layer. This is where the databases live. The only way to access these databases is by connecting to them from the application layer.
In our case we have decided to use Amazon's Relational Database Service (RDS) which is a managed database service provided by Amazon. One advantage of using RDS is that we can have a failover database instance in a separate availability zone. In addition, we can also have one or more read-only RDS instances to take some of the load of the main database.
At Stratus10 we always use AWS best practices when designing our client's infrastructure, including this 3-tier infrastructure pattern, because it gives you multiple levels of security, scalability, high availability, and redundancy.