DEV Community

Cover image for Scaling and Load Balancing Your Architecture on AWS ⚖️
Hashir Saud Khan
Hashir Saud Khan

Posted on

Scaling and Load Balancing Your Architecture on AWS ⚖️

INTRO
This lab takes a single web server and turns it into a properly scalable, load-balanced setup. You start with one EC2 instance running a web app, and by the end, you have a load balancer spreading traffic across multiple instances, an Auto Scaling group automatically adding or removing instances based on CPU load, and CloudWatch alarms watching it all in the background.

Starting Arcitecture
starting arcitecture

Final Arcitecture
Final Arcitecture

KEY TERMS YOU'LL SEE
Before jumping into steps, here's every term this lab throws at you, defined once so nothing feels unfamiliar later:

  • AMI (Amazon Machine Image) — a saved snapshot of an instance's boot disk. Once you have one, you can launch as many identical instances from it as you want.
  • Load Balancer (specifically an Application Load Balancer) — a service that sits in front of your instances and spreads incoming traffic across them, so no single instance gets overwhelmed.
  • Target Group — the list of instances a load balancer is actually allowed to send traffic to. The load balancer doesn't talk to instances directly; it talks to a target group, and the target group tracks which instances are in it and whether they're healthy.
  • Listener — a rule on the load balancer that checks for connection requests on a specific port and protocol (like HTTP on port 80) and forwards matching traffic to a target group. It's the piece that actually connects "traffic coming in" to "which target group handles it."
  • Launch Template — a saved configuration (AMI, instance type, security group, etc.) that tells AWS exactly how to launch a new instance. Auto Scaling doesn't guess what a new instance should look like — it reads this template.
  • Auto Scaling Group (ASG) — a group of instances that AWS automatically keeps within a size range you define (a minimum, a desired count, and a maximum), launching or terminating instances as needed.
  • CloudWatch Alarm — a watcher that tracks a metric (like average CPU) and flips into an "In alarm" state when a threshold is crossed, which is what actually triggers Auto Scaling to act.

Keep these seven in mind — every task below is really just building one of them.

TASK 1: CREATE AN AMI FROM THE EXISTING WEB SERVER

  1. Open the EC2 console and go to Instances
  2. Select the Web Server 1 instance (it should be in a Running state)
  3. From the Actions dropdown, choose Image and templates → Create image
  4. Set:
    • Image name: Web Server AMI
    • Image description: Lab AMI for Web Server
  5. Choose Create image

The confirmation screen gives you the new AMI's ID — you'll need this AMI later when setting up the launch template.

Why we did this: Auto Scaling needs a repeatable template for new instances, and that template starts with an AMI — a frozen copy of a working server, ready to be cloned on demand.

TASK 2: CREATE A LOAD BALANCER

  1. In the EC2 console, go to Load Balancing → Load Balancers
  2. Choose Create load balancer, then under Application Load Balancer, choose Create
  3. Under Basic configuration, set the Load balancer name: LabELB
  4. Under Network mapping:
    • VPC: Lab VPC
    • Mappings: select both Availability Zones
    • First Availability Zone: Public Subnet 1
    • Second Availability Zone: Public Subnet 2
  5. Under Security groups: remove the default security group, then attach Web Security Group (already created for you, permits HTTP)
  6. Under Listeners and routing, choose Create target group — this opens a new tab
  7. In that new tab, configure the target group:
    • Target type: Instances
    • Target group name: lab-target-group
    • Choose Next, then on the Register targets page, choose Create target group (don't register any instances yet — the Auto Scaling group will do that automatically later)
  8. Close that tab and return to the load balancer tab
  9. Next to the Forward to dropdown under Default action, choose the refresh icon, then select lab-target-group
  10. Choose Create load balancer
  11. Once created, choose View load balancer, then copy the load balancer's DNS name into a text editor — you'll need it soon to actually open the app in a browser

Why we did this: A load balancer without a target group has nowhere to send traffic — the target group is what actually tracks which instances exist and whether they're healthy enough to receive requests.

TASK 3: CREATE A LAUNCH TEMPLATE

  1. In the EC2 console, go to Instances → Launch Templates
  2. Choose Create launch template
  3. Set:
    • Launch template name: lab-app-launch-template
    • Template version description: A web server for the load test app
    • Check Provide guidance to help me set up a template that I can use with EC2 Auto Scaling
  4. Under Application and OS Images, go to the My AMIs tab — Web Server AMI (the one you created in Task 1) should already be selected
  5. Under Instance type, choose t3.micro
  6. Under Key pair (login), leave it set to Don't include in launch template — you won't need to SSH into these instances directly
  7. Under Network settings, set Security groups to Web Security Group
  8. Choose Create launch template

Why we did this: This is the recipe Auto Scaling reads every time it needs to launch a new instance — AMI, instance type, and security group all bundled together so nothing has to be configured manually per-instance.

TASK 4: CREATE AN AUTO SCALING GROUP

  1. From the launch template you just created, choose Actions → Create Auto Scaling group
  2. Auto Scaling group name: Lab Auto Scaling Group, then choose Next
  3. Under Network:
    • VPC: Lab VPC
    • Availability Zones and subnets: select Private Subnet 1 (10.0.1.0/24) and Private Subnet 2 (10.0.3.0/24)
  4. Choose Next
  5. On the advanced options page:
    • Under Load balancing, choose Attach to an existing load balancer
    • Choose Choose from your load balancer target groups, then select lab-target-group | HTTP
    • Under Health checks, set Health check type to ELB
  6. Choose Next
  7. On the group size and scaling policies page:
    • Desired capacity: 2
    • Minimum capacity: 2
    • Maximum capacity: 4
    • Under Scaling policies, choose Target tracking scaling policy
    • Metric type: Average CPU utilization
    • Target value: 50
  8. Choose Next through the notifications page (nothing to configure)
  9. On the Add tags page, add a tag:
    • Key: Name
    • Value: Lab Instance
  10. Choose Next, then Create Auto Scaling group

Note: instances launch into private subnets — they're not directly reachable from the internet, only through the load balancer sitting in the public subnets.

Why we did this: This single group definition replaces manually launching, monitoring, and terminating instances yourself — you just declare the size range and the CPU target, and AWS keeps reality matching that declaration on its own.

TASK 5: VERIFY LOAD BALANCING IS WORKING

  1. Go to EC2 → Instances — you should see two new instances named Lab Instance, launched automatically by the Auto Scaling group
  2. Go to Load Balancing → Target Groups, choose lab-target-group
  3. Under Registered targets, both Lab Instance entries should appear
  4. Wait until both show a Healthy status (refresh as needed) — this confirms each instance is passing the load balancer's health check and is eligible to receive traffic
  5. Open a new browser tab, paste the load balancer's DNS name from Task 2, and press Enter — the Load Test application should load

Why we did this: A healthy status is the load balancer's way of confirming an instance is actually ready for traffic — without this check, the load balancer might send requests to an instance that's still booting or broken, and users would see failures.

TASK 6: TEST AUTO SCALING UNDER LOAD

  1. Go to the CloudWatch console → Alarms → All alarms — you'll see two alarms, created automatically by the Auto Scaling group (a "high CPU" alarm and a "low CPU" alarm), keeping the group's average CPU near the 50% target within its 2–4 instance range
  2. Check the alarm with AlarmHigh in its name — it should currently show state OK (CPU is low, nothing to react to yet)
  3. Go back to the Load Test application tab, and choose Load Test next to the AWS logo — this deliberately spikes CPU usage across the running instances, and the page auto-refreshes to keep the load going
  4. Return to the CloudWatch console — within about 5 minutes, watch for:
    • AlarmLow flipping to OK
    • AlarmHigh flipping to In alarm, once average CPU crosses 50% for more than 3 minutes
  5. Once AlarmHigh is In alarm, go back to EC2 → Instances — you should now see more than two Lab Instance entries running, launched automatically in response to the alarm

Why we did this: This is the actual proof the whole setup works — not just that instances exist, but that real load causes CloudWatch to detect it and Auto Scaling to react to it, exactly as configured.

TASK 7: TERMINATE THE ORIGINAL WEB SERVER

  1. Go to EC2 → Instances, select only Web Server 1
  2. From Instance state, choose Terminate instance, then confirm with Terminate

Why we did this: Web Server 1 already did its one job — becoming the AMI everything else is built from. Keeping it running afterward serves no purpose and just adds an untracked, unmanaged instance sitting outside your Auto Scaling group.

OPTIONAL CHALLENGE: CREATE AN AMI USING THE AWS CLI
If there's time left, repeat Task 1's goal — but through the CLI instead of the console:

  1. Connect to one of your running EC2 instances using EC2 Instance Connect
  2. Configure your AWS CLI credentials
  3. Use the aws ec2 create-image command, supplying an AMI name and the instance ID you want to image

Why we did this: Every console action in this lab has a CLI equivalent — this challenge is a reminder that nothing here is console-exclusive; it's all scriptable and automatable the same way.

WHY THIS MATTERS OVERALL

  • A load balancer, target group, launch template, and Auto Scaling group aren't four separate features — they're one pipeline: template defines the instance, the group manages how many exist, and the target group is how the load balancer finds them
  • Placing Auto Scaling instances in private subnets while the load balancer sits in public subnets is a real security pattern — the only path in is through the load balancer, nothing is directly internet-facing
  • CloudWatch alarms are the trigger, not the mechanism — Auto Scaling still needs a target tracking policy telling it what to do once an alarm fires
  • Terminating the original instance after imaging it is easy to forget, but leaving it running defeats the purpose of consolidating everything into a managed, scalable group

AWS #LoadBalancing #AutoScaling #CloudWatch #EC2 #CloudComputing

Top comments (0)