Deploy a highly available application in a scalable VPC architecture on AWS.
10 min read
Table of contents
- Preparation for the deployment
- VPCs Deployment
- VPC traffics observability
- The application deployment
- Troubleshooting tips
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:
stop the ec2 instance.
Click on action>images and templates> create an image**.
Once the necessary fields are filled in, click on create an image.
Wait for the image creation to finish
Deleting (terminating) the instance.
Bastion Host VPC
To create the VPC:
Navigate to VPC dashboard
Click on the button create VPC
In the VPC settings, choose only VPC
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.
In the VPC menu, click on internet gateway on the left,
Then click on the create internet gateway button, enter the gateway name and click on create internet gateway to validate.
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
In the VPC menu click left on the subnet
Click the create subnet button
In the VPC section choose the VPC in which the subnet must be located
In the subnet parameters, define a name, then define the IPv4 CIDR block.
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,
Navigate to the VPC menu
Click on route tables on the left then the create route table button
Choose the VPC to which it should belong, give it a name then validate.
Once the route table is available, select it then in the routes section click on edit routes
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.
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.
In the VPC menu, click on Nat gateway on the left
Click on the create NAT gateway button, give it a name
Choose the public subnet in which it must be located at the connection type level
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.
Using the transit gateway here will enable private communication between the Bastion Host VPC and the Production VPC, to create the transit gateway,
Still, in the VPC menu, click on the left on the transit gateway
Click on the create transit gateway button, give it a name
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
Click on it then click on the create transit gateway attachment button,
Give it a name
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.
In the CloudWatch menu, click on "Logs" and then click on the "Create log group" button.
In the Create log group dialog, enter a name for the log group and click "Create".
Once the log group has been created, click on the log group and then click on the "Create log stream" button.
In the "Create log stream" dialog, enter a name for the log stream and click "Create".
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,
Navigate to the VPC service in the AWS Management Console
Select one of the VPCs.
In the VPC menu, click on "Flow Logs" and then click on the "Create flow log" button.
In the "Create flow log" dialog, select the log group that you created previously as the destination for the flow logs.
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
Go to the Amazon EC2 console and select "Launch Templates" from the navigation pane.
Click the "Create launch template" button.
On the "Create launch template" section, enter a name and choose the required VPC.
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
Under Launch template contents, fill 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.
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
Navigate to the Amazon EC2 dashboard.
In the left-hand menu, under "Load Balancing," select "Load Balancers."
Click the "Create Load Balancer" button and select "Network Load Balancer."
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.
Click the "Create Auto Scaling group" button.
Follow the prompts to configure the Auto Scaling group, including the group name, network, and subnet.
In the "Load Balancer" section, select the NLB that you just created
Configure the other settings for the Auto Scaling group as desired, including the minimum and a maximum number of instances and the scaling policies.
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.
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.