Scaling Laravel Using AWS Elastic Beanstalk Part 2: Setting up VPC, RDS and ElastiCache
In my last article we decoupled Laravel and got it ready for deployment to the Elastic Beanstalk architecture. However, before we race ahead to actually deploying our code to Elastic Beanstalk we need to do some preparation first. Specifically we need to set up some other AWS services that will be used by our Laravel app. These include:
- Virtual Private Cloud (VPC) to keep our infrastructure secure
- Relational Database Service (RDS) for our MySQL database
- ElastiCache for our Redis cache
With these “supporting” services up and running we can finally move on to deploying our Laravel app to Elastic Beanstalk.
Creating a VPC
The first thing we need to do is create a VPC for our infrastructure. By creating a VPC we can control every aspect of our network including which servers are available to the public internet and which servers should remain private. All of our EC2 servers (controlled by Elastic Beanstalk) should be on a private subnet (not accessible on the public internet) and all public traffic should be routed through either our load balancer (controlled by Elastic Beanstalk) for inbound traffic or our NAT for outbound traffic.
As a side note, we are going to be creating these services using the AWS Console and not the AWS CLI as it’s easier to visualize what we are doing. However these tasks can just as easily be completed (and automated) using the AWS CLI.
So let’s get started by heading over to the VPC console and clicking Start VPC Wizard:
- Step 1: Select VPC with Public and Private Subnets.
- Step 2: Give your VPC a name. You can leave most of these settings as the default, however you can change the IP CIDR block if you want. As we want to use a NAT gateway (instead of creating our own instance) we will need to create an Elastic IP first. You can do this by going to the EC2 console and under “Network & Security > Elastic IPs” click Allocate New Address. Back in the VPC wizard select your new Elastic IP and when you are ready click Create VPC.
Congratulations! We now have a VPC that we can use when creating the rest of our AWS services. There is one extra step we need to take here before we can create our RDS database below. RDS production databases require at least two availability zones, so we’re going to need to create a second public subnet for our VPC in a different availability zone (when we set up our RDS database we’re going to make it publically accessible so we need an extra public subnet).
In the VPC console, under “Subnets” click Create Subnet. Fill in the details making sure you are creating it in the correct VPC, the availability zone is different from the availability zone of the public subnet created by the wizard and the CIDR block in unique. When you’re ready click Yes, Create.
To make this subnet a public subnet you need to update the route table to use the public one created by the wizard. With the subnet selected, in the “Route Table” tab click Edit and change the route table to the one used by your other public subnet.
Setting up RDS
The next thing we want to do is to set up an RDS instance to host our MySQL database. If you read the AWS docs Deploying a Laravel Application to Elastic Beanstalk you will have noticed that they encourage you to set up the RDS database as part of the Elastic Beanstalk environment. While at first glance this might look like the obvious route, you should be aware that if you ever delete the Elastic Beanstalk environment the RDS database will also be deleted. So we’re going to mitigate that mistake-waiting-to-happen by setting up our own RDS instance separate from Elastic Beanstalk.
So let’s head on over to the RDS console and click Launch a DB Instance:
- Step 1: Select the database engine you would like to use. Amazon Aurora is probably overkill for small applications so let’s just select MySQL and continue.
- Step 2: Assuming this is a production app select “MySQL” under “Production” and continue to the Next Step.
- Step 3: Again most of these settings are sensible defaults and can be left as is. Depending on the size of your application you can select a smaller/larger DB Instance Class to suit your needs. Fill in your database details under “Settings” and when you are ready continue to the Next Step.
- Step 4: The “Network & Security” settings here are important. First we want to select the VPC we created above. If you want to be able to access your database from outside the VPC (using an app like Sequel Pro) you will want to set Publicly Accessible to “Yes”. If you choose “No” only your EC2 instances from inside the VPC private subnet will be able to access the database, which is more secure but harder to manage. While you can let RDS create a new security group specifically for the database, I think it’s fine to simply select “default (VPC)” for VPC Security Group(s). Fill in the Database Name and when you are ready click Launch DB Instance.
Great, our MySQL database is up and running on an RDS instance! Now to be able to connect to our database we’re going to have to do a bit of fiddling to allow your IP address to access the database instance. If you enter the database details into an app like Sequel Pro you’ll notice that you get a timeout error. That’s because the security group being used by the RDS instance is blocking your connection.
To resolve this expand your database instance in the RDS console. In the “Details” tab you will see the security group being used by the instance. Click it and it should take you to the EC2 console Security Groups page.
With the security group selected click the “Inbound” tab. This table shows the rules describing what traffic is allowed to access instances managed by this security group. Currently only traffic from this security group can access our instances (basically any servers in our VPC).
Click Edit and add a rule with a “MySQL/Aurora” type. If you select “My IP” under Source it will autofill your current IP address. Click Save. If you try to connect again now you should be able to connect successfully and see the database created by RDS. Remember if your IP address changes you will need to repeat this process to add the new IP.
Setting up ElastiCache
In the last article we configured Laravel to use a Redis cache. If you remember this is because we decoupled Laravel so that distinct pieces of the infrastructure can be scaled out. Due to Elastic Beanstalk’s autoscaling you could have many servers being created and destroyed at different times based on the traffic load. However, all of these instances need to be able to read/write from the same cache (similar to the database). So we need to set up a Redis cache cluster that can be accessed by our Elastic Beanstalk autoscaling group.
To get started, head over to the ElastiCache console and under “Create Cluster” click Create:
Make sure “Redis” is selected as our cluster engine. As above, most of the default settings will be fine here. For bigger applications you may want to enable Cluster Mode and tweak the size of the Node type and Number of replicas you want.
Under “Advanced Redis Settings” we will need to create a new subnet group for our cache cluster. Give the subnet group a name and description, select our VPC, select the private subnets from our VPC (unless you want the ElastiCache instance to be publically accessible, in which case select our public subnets) and leave the rest of the settings as default. When you are ready click Create.
So we now have Laravel fully decoupled with all of our “supporting” services in place and ready to go. In the next article we’ll finally get round to setting up our Laravel app in Elastic Beanstalk which will include configuring our load balancer and auto scaling groups, and setting up our
ebextensions files for automatically provisioning our EC2 servers.
Have you ever used a VPC in AWS? Have any experience with RDS or Elasticache with some helpful tips you want to share? Let us know in the comments.