Deploy a highly available application in a scalable VPC architecture on AWS.
Tags: aws, vpc, cloud, architecture
Published: 2023-04-19 02:04:09

In this article, we are going to deploy a VPC architecture in a scalable way. It is mainly about deploying two VPCs, one for a bastion host in a public subnet, and the second one for the main resources of the architecture, namely two private subnets that will be used to host the different instances of an autoscaling group that will be distributed across the two availability zones to ensure the high availability of the application. Since these instances will be in private subnets they will not be able to have public IPs so no internet access. So to allow them to have internet access, a NAT gateway will be set up in a public subnet, and the route tables will be updated to route the outgoing traffic by default to the NAT gateway to allow the resources in the private subnets to have internet access. To serve the requests coming from the internet to the application, a Network Load Balancer will be set up in front of the auto-scaling group. And finally to allow private communication between the two VPCs a transit gateway will be set up.

# Preparation for the deployment

This application will be based on an ec2 instance with all the prerequisites and dependencies for the proper functioning of the application. So to do this we will create an ec2 instance on which to install and make all the necessary configurations for the web application to be ready to use. Of course, feel free to set up your web application, so everything it will need to be ready to use (web server, DB, etc.)

Once everything is ready, we will create a golden AMI based on the EC2 instance.

> An Amazon Machine Image (AMI) is **a supported and maintained image provided by AWS that provides the information required to launch an instance**. You can create your own AMI, customize the instance (for example, install software on the instance), and then save this updated configuration as a custom AMI. Instances launched from this new custom AMI include the customizations that you made when you created the AMI

So to create your custom AMI:

1. stop the ec2 instance.
    
2. Click on action&gt;images and templates&gt; create an image\*\*.
    
3. Once the necessary fields are filled in, click on create an image.
    
4. Wait for the image creation to finish
    
5. Deleting (terminating) the instance.
    

# VPCs Deployment

## Bastion Host VPC

To create the VPC:

1. Navigate to VPC dashboard
    
2. Click on the button **create VPC**
    
3. In the VPC settings, choose only VPC
    
4. Define IPv4 CIDR the address block and click on **create VPC** to validate the creation of the VPC.
    

As you may have seen on the architecture at the beginning, in this VPC there must be a public subnet in which the bastion host will reside. To set up a public subnet, several elements come into play, the main ones are the route tables and the internet gateway. For a subnet to be public, it must be associated with a route table that directs traffic to an internet gateway.

### Create Internet Gateway

So let's create the internet gateway first.

1. In the VPC menu, click on **internet gateway** on the left,
    
2. Then click on the **create internet gateway** button, enter the gateway name and click on **create internet gateway** to validate.
    
3. Once the internet gateway is created you will see a banner that invites you to attach it to a VPC, click on it then attach it to the previously created VPC.
    

### Create the public subnet

1. In the VPC menu click left on the subnet
    
2. Click the **create subnet** button
    
3. In the VPC section choose the VPC in which the subnet must be located
    
4. In the subnet parameters, define a name, then define the IPv4 CIDR block.
    
5. Click on create subnet to validate.
    

### Create route tables and add routing rules

When creating a VPC, a route table is created by default, you can just add to it a new route depending on what you want to get, or create a new one. Since the route we want to add here will allow public access, I will not create a new one. But in case you want to create a new one,

1. Navigate to the VPC menu
    
2. Click on route tables on the left then the **create route table** button
    
3. Choose the VPC to which it should belong, give it a name then validate.
    
4. Once the route table is available, select it then in the routes section click on **edit routes**
    
5. Click on **add route**. at the destination level, type 0.0.0.0/0 for any destination then at the target level, choose the internet gateway we just created then save changes.
    

After the routes are updated, it is necessary to associate the table to a subnet, so in the section subnet associations, click on **edit subnet associations**, then select the subnet to which we want to associate the route table then save associations.

## Production VPC

In the production VPC there are a public subnet and two private subnets. For the public subnet, proceed as done in the previous steps.

### Create NAT Gateway

Now for the private subnet, we don't want the resources to be directly accessible on the internet, but the outbound traffic by default still points to the internet. This is possible by setting up a NAT gateway and then creating a route table that routes the default traffic to NAT for an outbound internet connection.

1. In the VPC menu, click on Nat gateway on the left
    
2. Click on the create NAT gateway button, give it a name
    
3. Choose the public subnet in which it must be located at the connection type level
    
4. Choose public to allocate it an Elastic public IP then validate by clicking on create NAT Gateway.
    

After you have to create a new route table that will direct the default traffic to NAT for outbound internet connection, to do this you have to proceed as before but here you will have to change the target to redirect it to the nat gateway instead of the internet gateway and do not forget to associate the private subnet.

## Transit gateway

Using the transit gateway here will enable private communication between the Bastion Host VPC and the Production VPC, to create the transit gateway,

1. Still, in the VPC menu, click on the left on the transit gateway
    
2. Click on the **create transit gateway** button, give it a name
    
3. Validate by clicking on create transit gateway.
    

After its creation, you must add the attachments for the VPCs, so on the left just below the transit gateway is transit gateway attachments

1. Click on it then click on the **create transit gateway attachment** button,
    
2. Give it a name
    
3. Choose the required transit gateway ID, for the attachment type choose VPC, then at the VPC id level choose the required VPC then validate the creation of the attachment, and then it's good.
    

# VPC traffics observability

Here we're going to create a CloudWatch Log Group with two Log Streams to store the VPC Flow Logs of both VPCs and enable Flow Logs for both VPCs and push the Flow Logs to Cloudwatch Log Groups and store the logs in the respective Log Stream for each VPC.

1. In the CloudWatch menu, click on "Logs" and then click on the "Create log group" button.
    
2. In the **Create log group** dialog, enter a name for the log group and click "Create".
    
3. Once the log group has been created, click on the log group and then click on the "Create log stream" button.
    
4. In the "Create log stream" dialog, enter a name for the log stream and click "Create".
    
5. Repeat this step to create a second log stream.
    

Next, you will need to enable VPC Flow Logs for the two VPCs. To do this,

1. Navigate to the VPC service in the AWS Management Console
    
2. Select one of the VPCs.
    
3. In the VPC menu, click on "Flow Logs" and then click on the "Create flow log" button.
    
4. In the "Create flow log" dialog, select the log group that you created previously as the destination for the flow logs.
    
5. Repeat these steps for the second VPC to enable VPC Flow Logs.
    

# The application deployment

We will deploy the application by setting up an Auto Scaling group based on the Golden AMI we created above

## Create launch template

To create an Auto Scaling group based on the golden AMI, you must use a launch template. To create a launch template

1. Go to the Amazon EC2 console and select "Launch Templates" from the navigation pane.
    
2. Click the "Create launch template" button.
    
3. On the "Create launch template" section, enter a name and choose the required VPC.
    
4. Under **Auto Scaling guidance**, select the check box to have Amazon EC2 provide guidance to help create a template to use with Amazon EC2 Auto Scaling
    
5. Under **Launch template contents, f**ill out each required field and any optional fields as needed, select the Golden AMI created above, instance type, key pair, network settings, security group, and other instance details for the instances in the Auto Scaling group.
    
6. Click the "Create launch template" button to create your launch template.
    

## Create Auto Scaling group

Once your launch template has been created, you can use it to create an Auto Scaling group.

But first, let's create the load balancer that will be in front of the auto-scaling group

1. Navigate to the Amazon EC2 dashboard.
    
2. In the left-hand menu, under "Load Balancing," select "Load Balancers."
    
3. Click the "Create Load Balancer" button and select "Network Load Balancer."
    
4. Follow the prompts to configure the NLB, including the name, listeners, and target groups.
    

To configure the NLB, you will need to specify the following details:

* Name: This is the name of the NLB. It should be unique within your AWS account.
    
* Listeners: These are the ports that the NLB will listen on. You can add multiple listeners with different ports and protocols. Here we use port 80
    
* Target groups: These are groups of Amazon EC2 instances that the NLB will route traffic to. You will need to create at least one target group and add instances to it.
    

Once you have configured the NLB, navigate to the EC2 dashboard and select "Auto Scaling Groups" in the left-hand menu.

1. Click the "Create Auto Scaling group" button.
    
2. Follow the prompts to configure the Auto Scaling group, including the group name, network, and subnet.
    
3. In the "Load Balancer" section, select the NLB that you just created
    
4. Configure the other settings for the Auto Scaling group as desired, including the minimum and a maximum number of instances and the scaling policies.
    
5. Click the "Create Auto Scaling group" button to create the Auto Scaling group with the NLB.
    

Once the Autoscaling group is created and the NLB becomes active. You can then test the NLB by sending traffic to it and verifying that it is routing traffic to the target groups as expected.

# Troubleshooting tips

in case of unreachability, the two main points that should be reviewed are the security groups and the route tables, make sure that the security group allows the type of traffic you want and the source. also, make sure to apply the right route table configurations. An excellent tool that can help debug in case of unreachability is the **network reachability analyzer.** it helps troubleshoot reachabilities by configuring paths and analyzing them for insightful explanations that can help solve problems.

The unreachability issue I had during my configurations was related to the transit gateway. The ec2 instances in the private subnets could not be accessed via ssh from the jump (bastion) host. To fix this I used the **network reachability analyzer** tool to get some information on to base my hypothesis, and this helped in part to solve the issue. the problem was due to the lack of a route within the VPC bastion and also at the production VPC level. I had to add a route that redirected traffic destined for the private subnet to the transit gateway by default, and also do the same at the private subnet level, ie direct by default the traffic destined for the bastion to the transit gateway.