How To Use Amazon EC2 Auto Scaling

John MacLean
15 min readFeb 26, 2023

--

My first AWS architecture diagram! Next one will be smaller…

Introduction

In this article I am going to walk through creating a basic AWS infrastructure to demonstrate Auto Scaling.

Auto scaling is a useful tool in AWS that allows you to automatically adjust the number of EC2 instances running your application based on demand.

In this particular scenario, setting up auto scaling is beneficial because it ensures that your application can handle increased traffic without requiring manual intervention.

By setting a threshold of 50% CPU utilization, auto scaling will spin up additional EC2 instances as needed to meet demand, and then scale down when demand decreases. This helps to maintain consistent performance for your application while also minimizing costs by only running the resources that are needed at any given time.

Additionally, auto scaling allows for high availability by ensuring that your application is always running on a sufficient number of instances.

Pre-requisites

  1. A non-root IAM account with enough rights to perform the required actions. It is considered bad practise (and a security risk) to use your root account for daily administrative tasks.
  2. We’re at the stage now where some knowledge of AWS services and basic networking knowledge is useful. Of course, you can pick those skills up by reading my previous articles! 😉

The Challenge!

Foundational steps

  1. Create a VPC with a CIDR block of 10.10.0.0/16.
  2. Create three public subnets with the following IP ranges: 10.10.1.0/24 & 10.10.2.0/24 & 10.10.3.0/24.
  3. Create an autoscaling group using t2.micro instances. All instances should have Apache installed, with the ability to check any random IP address and be able to produce a test page. Ensure the autoscaling group is using the public subnets from step 2.
  4. The autoscaling min and max should be 2 and 5.
  5. Create an Application Load Balancer to distribute traffic to the autoscaling group.
  6. Create web server security group that allows inbound traffic from HTTP from your Application Load Balancer.
  7. Create a load balancer security group that allows inbound traffic from HTTP from 0.0.0.0/0.

Advanced steps

  1. Add a target policy for the ASG to scale after CPU utilization is above 50%.
  2. After the autoscaling group has been created, find a stress tool to be able to stress an instance above 50% to see if your scaling policy works!

Foundational Steps

First thing’s first — create a VPC.

Log into the AWS console, type vpc in the search bar and click VPC under the Services that are returned.

You’ll be taken to the VPC dashboard. Check you’re in the region you want. Here, mine defaulted to N. Virginia, but I want to change that as I’m based in Europe.

I can just click on N. Virginia to get a drop down list of available regions and select one closer to home. This should mean I get access to my resources slightly more quickly.

Now, click the orange Create VPC button.

Select VPC only, add a tag if you like — I like to do this for consistency and clarity across projects — and add our IPv4 CIDR block.

All other settings are default, so click the orange Create VPC button at the bottom of the page.

All being well, you will be notified accordingly.

Next we’ll create our subnets.

On the left hand menu of the VPC dashboard, click Subnets.

Now you may see other subnets listed — these could be from your default VPC or other resources you have created, but we are going to create subnets specifically for this task, so just press the orange Create subnet button on the right of the screen.

Press the small down arrow in the VPC ID field and select the new VPC you just created. This is where setting tags is handy as we can clearly see the johnnymac-luit-proj6 VPC highlighted.

Once you select your VPC, the Subnet settings will open up.

I created my VPC in the eu-west-2 region, so my each of my 3 subnets will be in one of that regions Availability Zones.

As shown, I have chosen my Subnet name to reflect the AZ it’s in. I selected the Availability Zone and set the IPv4 CIDR block.

Now, I need to create the next subnet, so click Add new subnet.

Once the details are correct, click Add new subnet again.

Finally, we have also added subnet 3’s information, so click the orange Create subnet button.

Everything looks good, so next we need to create an internet gateway. As the name suggests, this is a VPC component that allows communication between your VPC and the internet.

From the VPC dashboard, click Internet gateways from the left hand menu.

Click the orange Create internet gateway button on the resulting screen.

I’m going to enter a Name tag and maintain naming consistency with the other task resources. Then click the orange Create internet gateway button.

Again, we get a green banner to indicate success, but note the Attach to a VPC button in the top right of the screen.

We must associate the internet gateway with our VPC otherwise our infrastructure will not work as required. Press the Attach to a VPC button.

Click in the Available VPCs field and select your VPC. Then click the orange Attach internet gateway button.

Success once again — and the tags highlight clearly that we have chosen the correct resources associated with this task.

The next step is to create a route table. This is essentially a set of rules that direct incoming traffic within our network.

Back at the VPC dashboard once more, click Route tables from the left hand menu, then click the orange Create route table button on the resulting page.

Similar to a number of previous steps, enter a Name and select your VPC from the drop down menu. Click the orange Create route table button.

So our route table has been created, but we need to verify the configuration to ensure everything is correct.

Note that you’re offered the Reachability Analyser to automatically check your network connectivity, but beware! This is not free to run. Albeit, it only costs $0.10, but we can do our checks manually instead.

If we click the Subnet associations tab, we can see our subnets are not explicitly associated with our route table.

Click the Edit subnet associations button in the Explicit subnet associations box.

Check all the new subnets you created and click the orange Save associations button.

Now if we check the Subnet associations tab, we can see our subnets are explicitly associated with our route table.

Finally we need to create a default route for 0.0.0.0/0. Creating a route for 0.0.0.0/0 in an AWS route table is like creating a default route that sends all incoming traffic to a specific destination, such as a gateway or a next-hop router. This is useful for routing traffic to the internet or to another network beyond your own.

Still on our Route tables page in the AWS Console, click the Edit routes button.

Click Add route.

Enter 0.0.0.0/0 in the Destination field, then select Internet Gateway from the drop down Target list.

You’ll get the option to select your required internet gateway, so do that, then press the orange Save changes button.

We’ve now set up our basic network infrastructure.

Let’s go to the EC2 Dashboard now. I have a shortcut button saved to my console navigation bar. If you do not, you can just enter ec2 in the search bar.

Click Launch Templates from the left hand menu.

Click Create launch template button.

Enter Launch template name, a Template version description and check Auto Scaling guidance.

For the AMI, I am using an AMI that I created previously — see this article for reference.

This AMI is a t2.micro instance with Apache Web Server installed and configured, as well as a simple web page defined.

I’m using an existing Key pair for convenience sake.

Under Network settings, select Create security group and fill in the fields as shown.

Be careful to double check the VPC — my default VPC was selected initially and I had to change it manually to the one created for this exercise.

Click the Add security group rule button and we’ll enable HTTP access from the internet so our web page on our EC2 instance is accessible.

Open Advanced network configuration and change Auto-assign public IP to Enable.

This change ensures that instances launched from the template are automatically assigned a public IP address, allowing them to communicate with the internet and other public networks. This is useful when you want to create instances that are accessible from the internet, such as web servers or VPN gateways.

As we are using a custom AMI with Apache Web Server already set up, our template configuration is complete. Click the Create launch template button.

Success! Click the View launch templates button.

That takes us back to the EC2 Dashboard. Scroll down to the bottom of the menu on the left hand side and click Auto Scaling Groups.

Click Create Auto Scaling group.

Enter an Auto Scaling group name and select the Launch template you created earlier from the drop down menu.

Click the orange Next button.

Select the correct VPC from the drop down list and check all the subnets created under Availability Zones and subnets.

Click the orange Next button.

Click Attach to a new load balancer.

Make sure Application Load Balancer is selected. This load balancer works at the application level and is best suited to routing web traffic which is what we require.

Enter a Load balancer name.

Under Listeners and routing, select the Create a target group option from the drop down menu under Default routing.

Input a New target group name. Note that the field was pre-populated with the name of my ALB, so be sure to change it if this happens to you.

Scroll down to the bottom and check Monitoring in the Additional settings box.

Click the orange Next button.

The task requires us to set a minimum capacity of 2 and a maximum of 5, so define that in the Group size box.

On Scaling policies, select Target tracking scaling policy, set the Metric type to Average CPU utilization and ensure the Target value is set to 50. We will use this policy in our stress tests to check that auto scaling works as expected.

Click Next.

Click Next.

Click Next.

This will take you to the Review page. Scroll to the bottom and click the orange Create Auto Scaling group button.

Arg!

I checked back in step 2 of my Create Auto Scaling group configuration.

As per the message on screen, my launch template didn’t specify an instance type. That may be something I need to go back and look at.

For the moment, let’s try manually setting my instances to t2.micro.

Once set, I skip back to the Review screen and click the orange Create Auto Scaling group button again.

Oh for goodness sake!

Skip back to step 2, change the Additional instance type to t2.small.

Again, I skip back to the Review screen and click the orange Create Auto Scaling group button.

Oh dear.

I went back to my launch instance template, set Instance type to t2.micro and clicked Create template version button.

A new version of my template is created — version 2.

Back to my Auto Scaling group configuration — I set the launch template to be the updated version 2.

I have to click through all the previous steps inputting the required configuration.

For the umpteenth time, I get to the Review screen and click the orange Create Auto Scaling group button. Success this time thankfully.

Checking the EC2 Dashboard, there are 2 new instances running. Let’s check one of the IP addresses in another browser — 18.169.240.163.

Great — the instance is working and the defined web page is too. Perhaps I should have updated the html though since it references a previous project! I guess that’s a useful lesson in AMI image management.

Advanced Steps

Well, we already completed step 1 in the previous section.

We created our target tracking scaling policy to trigger the Application Load Balancer to spin up another EC2 instance if CPU usage exceeds 50%.

To test this works, we need a utility to create CPU load on our instances.

Unfortunately I didn’t create a rule to allow SSH traffic to my instances, so I need to go to the EC2 Dashboard, then scroll down the left hand menu and click Security Groups.

Click the johnnymac-luit-proj6-serversg group we created earlier.

Click Edit inbound rules.

Click Add rule.

Select SSH from the Type drop down menu and Anywhere-IPv4 from the Source drop down. Add a Description if required and then click the orange Save rules button.

Success. Let’s try to SSH to one of our instances via PowerShell.

Yup, that’s also good.

I found this article which details a utility for generating load on an EC2 instance, so I am just going to follow that: https://www.wellarchitectedlabs.com/performance-efficiency/100_labs/100_monitoring_linux_ec2_cloudwatch/5_generating_load/

sudo amazon-linux-extras install epel -y
sudo yum install stress -y

These two commands install the utility.

sudo stress --cpu 8 --vm-bytes $(awk '/MemAvailable/{printf "%d\n", $2 * 0.9;}' < /proc/meminfo)k --vm-keep -m 1

This command initiates the stress test and you can refer to the article above to see how the command is structured.

As we can see, we initially have 2 EC2 instances running.

If we go to the CloudWatch EC2 Dashboard, we can check the CPU usage among other metrics.

CPU usage on our test instance is above 75%, but unfortunately no additional instances have been spun up.

There must be an issue with our Application Load Balancer.

I check through all the tabs on my ALB and I notice that under Security, the custom target group I created when setting up the Application Load Balancer is not assigned. Perhaps I missed a step when I had to re-enter all the information?

Let’s press the Edit button in the Security groups box.

So my Load balancer is associated with my default VPC and not the VPC we created for this task.

Select Create new security group.

Enter the required Basic details, being sure to select the correct VPC. Press Add rule button.

Choose HTTP from the drop down Type menu, Source is Anywhere-IPv4 and add a Description if desired.

Scroll to the bottom of the page and press the orange Create security group button.

Success.

Now kicking off the stress test utility on our instance again has the desired effect…

…with additional horizontal capacity being spun up automatically.

We can check CloudWatch to see the results of our stress testing on CPU load.

Conclusion

Wow. This was Project 6 with Level Up In Tech and the most in depth and complex one yet.

Three takeaways from this are:

  1. Think about updates to your custom AMIs if you maintain them.
  2. Check all the options in your Launch Templates.
  3. Check all your infrastructure items are configured correctly. Especially where there are network related rules!

Even though most production environments would spin up resources via code, exercises like this are still useful to learn how various infrastructure items are configured and how they link together.

I hope you enjoyed this article. As ever, thank you for reading and please feel free to reach out with any questions or any suggestions for improvement.

--

--