Advanced Scaling and Load Balancer Deep Dive
Build an NLB, configure step scaling, warm pools, and lifecycle hooks on AWS.
Introduction
30 Second Summary
Think about how a popular online store handles Black Friday. If every customer hits the same single server, it crashes. Real-world applications solve this by spreading traffic across multiple servers and automatically adding more when demand spikes.
In this project, you will build a multi-layered scaling and load balancing lab on AWS that demonstrates Network Load Balancers, step scaling policies, scheduled scaling, warm pools, and lifecycle hooks.
What You'll Build
A fully-instrumented Auto Scaling environment showcasing every major ELB type and ASG scaling mechanism tested on the AWS SAA-C03 exam.
By the end of this project, you'll have:
- A Network Load Balancer with static Elastic IPs running alongside your ALB, demonstrating the Layer 4 vs Layer 7 difference.
- Step scaling and scheduled scaling policies tied to custom CloudWatch alarms, plus a warm pool with a lifecycle hook for faster, controlled scale-out.
- Exam-ready understanding of when to choose each ELB type and each scaling policy type for the SAA-C03.
- Secret Mission: add a scale-in step policy and configure warm pool instance reuse for cost-optimized recycling.
Are there any prerequisites?
This project builds on Project 4a (Launch Templates, ALB, Auto Scaling Groups, and Target Tracking policies). You should be familiar with EC2, VPCs, Security Groups, and CloudWatch basics before starting.
Set Up Base Infrastructure
Before you can explore advanced scaling policies and load balancer types, you need a working foundation. This step recreates the base infrastructure from Project 4a: a Launch Template, an Application Load Balancer, and an Auto Scaling Group with running instances.
Since you tore down those resources at the end of Project 4a, you need a working ASG with instances behind an ALB before adding advanced features. The setup is familiar, so you will move through it quickly.
In this step, get ready to:
- Create a launch template with Apache web server user data.
- Create an ALB with a target group for HTTP traffic.
- Create an Auto Scaling Group that launches 2 instances behind the ALB.
Create a launch template with Apache user data
A launch template defines everything EC2 needs to know when spinning up a new instance. You will configure one that automatically installs Apache and displays the instance ID on a web page.
- In the AWS Management Console, use the search bar at the top to search for EC2 and select the EC2 service.
- In the left navigation pane, scroll down and click Launch Templates.
- Click Create launch template.
- For Launch template name, enter lab-4b-template.
- Under Application and OS Images (Amazon Machine Image), select Amazon Linux 2023 (it should appear under Quick Start as the default Amazon Linux option).
- Under Instance type, select t2.micro.
- Under Network settings, click Create security group.
- Add a rule: Type HTTP, Port 80, Source Anywhere (0.0.0.0/0).
- Add a second rule: Type SSH, Port 22, Source My IP.
- Expand Advanced details at the bottom of the page.
- Scroll all the way down to the User data field and paste the following script:
#!/bin/bash
# Update all installed packages
yum update -y
# Install the Apache web server
yum install -y httpd
# Start Apache and enable it to start on boot
systemctl start httpd
systemctl enable httpd
# Retrieve the instance ID using IMDSv2 (required by Amazon Linux 2023)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
INSTANCE_ID=$(curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
# Write a simple page showing this instance's ID
echo "<h1>Instance ID: $INSTANCE_ID</h1>" > /var/www/html/index.html
What does this user data script do?
User data runs automatically the first time an instance boots. This script performs four jobs:
- Updates the OS packages to their latest versions.
- Installs and starts Apache httpd so the instance can serve web pages on port 80.
- Fetches the instance's own ID from the EC2 metadata service using IMDSv2 (the token-based method required by Amazon Linux 2023).
- Writes a simple HTML page to /var/www/html/index.html so you can see which instance is responding.
- Click Create launch template.
You should see a success banner confirming that lab-4b-template was created.
Don't see the User data field?
The User data field is hidden inside the Advanced details section at the very bottom of the Create launch template page. Click the section header to expand it, then scroll down past all the other advanced options.
help me find the User data field in the EC2 launch template console
Create an ALB with a target group
The ALB distributes incoming HTTP requests across your instances. You will first create the target group (which tracks healthy instances), then create the load balancer itself.
- In the EC2 left navigation pane, click Target Groups (under Load Balancing).
- Click Create target group.
- For target type, keep Instances selected.
- For Target group name, enter lab-4b-tg.
- Set Protocol to HTTP and Port to 80.
- Under Health checks, confirm the health check path is /.
- Click Next, then click Create target group (skip registering targets manually, the ASG will handle it).
Now create the Application Load Balancer:
- In the left navigation pane, click Load Balancers (under Load Balancing).
- Click Create load balancer.
- Under Application Load Balancer, click Create.
- For Load balancer name, enter lab-4b-alb.
- For Scheme, select Internet-facing.
- Under Network mapping, select at least 2 Availability Zone subnets (pick the same ones you will use for the ASG).
- Under Listeners and routing, confirm the listener is HTTP on port 80.
- For Default action, select your lab-4b-tg target group from the dropdown.
- Click Create load balancer.
Wait for the ALB state to change from provisioning to active. This typically takes 2-3 minutes.
Why create the target group separately?
Creating the target group first gives you full control over its health check settings. When you later create the ASG and attach this target group, the ASG automatically registers and deregisters instances as they launch or terminate.
Can't find your target group in the ALB dropdown?
Make sure the target group's VPC matches the VPC you selected for the load balancer. They must be in the same VPC and the same AWS Region.
help me troubleshoot why my target group doesn't appear in the ALB listener dropdown
Create an Auto Scaling Group
The Auto Scaling Group ties your launch template to the ALB target group. It will launch 2 instances, register them with the load balancer, and keep them healthy automatically.
- In the left navigation pane, scroll down and click Auto Scaling Groups.
- Click Create Auto Scaling group.
- For Auto Scaling group name, enter lab-4b-asg.
- For Launch template, select lab-4b-template.
- Click Next.
- Under Network, select your VPC, then choose the same 2 Availability Zone subnets you used for the ALB.
- Click Next.
- Under Load balancing, select Attach to an existing load balancer.
- Choose Choose from your load balancer target groups, then select lab-4b-tg.
- Under Health checks, check Turn on Elastic Load Balancing health checks.
- Click Next.
- Under Group size, set Desired capacity to 2.
- Under Scaling, set Min desired capacity to 1 and Max desired capacity to 4.
- For Automatic scaling, select No scaling policies (you will add step scaling in a later step).
- Click Next through the remaining pages, then click Create Auto Scaling group.
Why no scaling policy?
You are deliberately leaving the group without a scaling policy for now. In Step 4, you will add a step scaling policy tied to a custom CloudWatch alarm. This separation lets you observe the difference between an ASG that only maintains desired capacity versus one that reacts dynamically to load.
- Wait 3-5 minutes for both instances to launch and pass health checks.
- In the Auto Scaling Groups page, select lab-4b-asg and check the Instance management tab. Both instances should show a lifecycle state of InService.
- Navigate to Target Groups, select lab-4b-tg, and click the Targets tab. Both instances should show a status of healthy.
- Go back to Load Balancers, select lab-4b-alb, and copy the DNS name value.
- Paste the DNS name into a new browser tab. You should see an Instance ID: heading.
- Refresh the page several times. You should see the instance ID change between your two instances, proving the ALB is distributing traffic.
Instances stuck in Initial or Unhealthy?
If your target group shows instances as initial for more than 5 minutes, check these common causes:
- The security group on the launch template must allow inbound HTTP on port 80 from anywhere. Without this, the ALB health checks cannot reach the instance.
- The subnets you selected for the ALB must match the subnets for the ASG. If they are in different AZs, the ALB cannot route to the targets.
- Verify the user data script was pasted correctly. A missing #!/bin/bash line at the top will prevent the script from running.
help me troubleshoot why my ASG instances are not passing ALB health checks
Your base infrastructure is live. Two instances are serving traffic through the ALB, and the Auto Scaling Group is maintaining the desired count. Next up, you will create a Network Load Balancer alongside this ALB to see the difference between Layer 4 and Layer 7 load balancing.
Create a Network Load Balancer and Compare ELB Types
Your ALB distributes HTTP traffic by inspecting request content at Layer 7. Some workloads need something different. They need raw TCP/UDP load balancing at Layer 4, with static IP addresses that never change.
In this step, you will build a Network Load Balancer (NLB) alongside your existing ALB. By pointing both at the same instances, you can observe the behavioral differences firsthand and understand when the SAA-C03 exam expects you to choose one over the other.
In this step, get ready to:
- Create an NLB with a TCP target group and static Elastic IPs.
- Compare NLB and ALB behavior using DNS resolution and browser tests.
- Understand Gateway Load Balancer architecture for the SAA-C03 exam.
Create an NLB with a TCP target group
Before creating the NLB itself, you need two things: a TCP target group for routing, and two Elastic IPs to give your NLB static addresses.
Allocate Elastic IPs
- In the EC2 console left sidebar, expand Network & Security and click Elastic IPs.
- Click Allocate Elastic IP address.
- Leave Public IPv4 address pool set to Amazon's pool of IPv4 addresses.
- Click Allocate.
- Repeat these steps to allocate a second Elastic IP. You need one per Availability Zone for your NLB.
Why do you need Elastic IPs for the NLB?
An internet-facing NLB lets you select an Elastic IP address for each Availability Zone, giving it static IP addresses. This is one of the key differences from an ALB, whose IP addresses change dynamically. Static IPs let clients whitelist specific addresses in their firewalls.
Create the TCP target group
- In the EC2 console left sidebar, under Load Balancing, click Target Groups.
- Click Create target group.
- For Choose a target type, select Instances.
- For Target group name, enter lab-4b-nlb-tg.
- For Protocol, select TCP.
- For Port, enter 80.
- For VPC, select the same VPC your ASG instances are running in.
- Under Health checks, leave the health check protocol as TCP.
- Click Next.
- On the Register targets page, select both of your running ASG instances by ticking their checkboxes.
- Click Include as pending below.
- Click Create target group.
Why TCP instead of HTTP?
The NLB operates at the fourth layer (Transport layer) of the OSI model. It handles TCP, UDP, and TLS traffic without inspecting application-level content like HTTP headers or cookies. TCP health checks simply verify that the port is open and accepting connections.
Create the Network Load Balancer
- In the EC2 console left sidebar, under Load Balancing, click Load Balancers.
- Click Create load balancer.
- Under Network Load Balancer, choose Create.
- For Load balancer name, enter lab-4b-nlb.
- For Scheme, select Internet-facing.
- For IP address type, select IPv4.
- Under Network mapping, select the same VPC and the same 2 Availability Zone subnets you used for your ALB.
- For each AZ subnet, expand the IPv4 settings and select one of your allocated Elastic IPs from the dropdown. Assign a different EIP to each AZ.
- Under Listeners and routing, set the listener Protocol to TCP and Port to 80.
- For Default action, select your target group lab-4b-nlb-tg.
- Click Create load balancer.
Wait for the NLB state to change from Provisioning to Active. This typically takes 2-3 minutes.
NLB stuck in provisioning?
Ensure both Elastic IPs are allocated in the same region as your subnets. If you see an error about EIPs, go back to the Elastic IPs page and confirm you have two available (unassociated) addresses.
help me troubleshoot my NLB creation
Observe NLB vs ALB differences
Your NLB is now active alongside your ALB, both pointing at the same two EC2 instances. Time to compare their behavior.
- Copy the NLB DNS name from the Load Balancers page (it appears under DNS name in the details panel).
- Open Command Prompt on your Windows device by pressing the Windows key, typing cmd, and pressing Enter.
- Run nslookup on your NLB DNS name:
nslookup [[NLB_DNS="your NLB DNS name"]]
- The result shows your two static Elastic IPs. These addresses never change for the life of the NLB.
- Now run the same command with your ALB DNS name:
nslookup [[ALB_DNS="your ALB DNS name"]]
- Notice that the ALB resolves to different dynamic IPs that can change over time.
- Paste your NLB DNS name into a browser tab. You should see the same Apache page showing an instance ID.
- Refresh a few times. Traffic distributes across your two instances, just like the ALB.
What is different about NLB traffic?
The NLB passes TCP connections through without modifying them. Unlike the ALB, it does not add HTTP headers like X-Forwarded-For by default. Your backend sees the client's real IP address directly in the TCP connection.
Another key exam difference: NLB cross-zone load balancing is OFF by default. Each NLB node distributes traffic only to targets in its own Availability Zone unless you explicitly enable cross-zone.
When does the exam expect NLB vs ALB?
- Choose NLB when the question mentions: static IPs, IP whitelisting, TCP/UDP protocols, extreme performance, or millions of requests per second.
- Choose ALB when the question mentions: HTTP routing, path-based routing, host-based routing, cookies, sticky sessions, or WAF integration.
GWLB conceptual coverage (exam focus)
The SAA-C03 exam also tests your knowledge of Gateway Load Balancer (GWLB). You will not build one here because it requires Marketplace virtual appliances and complex multi-VPC routing. However, you need to understand its architecture for exam questions.
What is a Gateway Load Balancer?
A Gateway Load Balancer operates at the third layer of the OSI model (Network layer). It listens for all IP packets across all ports and forwards traffic to the target group using the GENEVE protocol on port 6081.
GWLB is designed for deploying and scaling third-party virtual appliances. Think firewalls, intrusion detection/prevention systems (IDS/IPS), and deep packet inspection tools. It acts as a transparent network gateway for inline traffic inspection.
GWLB uses Gateway Load Balancer endpoints (VPC endpoints via PrivateLink) to route traffic across VPC boundaries to the appliances. Flow stickiness uses 5-tuple by default, with 3-tuple and 2-tuple also available.
GWLB exam keywords
If a question mentions "virtual appliances", "GENEVE", "traffic inspection", "inline security", or "third-party firewalls" the answer is GWLB. Never confuse it with NLB or ALB.
ELB type summary for SAA-C03
- ALB: Layer 7 (HTTP/HTTPS). Path and host routing, cookies, WAF. Dynamic IPs. Cross-zone ON by default.
- NLB: Layer 4 (TCP/UDP/TLS). Static IPs via Elastic IPs. Extreme performance. Cross-zone OFF by default.
- GWLB: Layer 3 (all IP packets). GENEVE protocol on port 6081. Virtual appliance deployment and inline inspection.
You now have both an ALB and an NLB running side by side, and you understand where GWLB fits. Next up, you will configure sticky sessions on your ALB to control which instance handles repeat visitors.
Configure Sticky Sessions on ALB
Your NLB is live and serving traffic at Layer 4 with static IPs. Now you'll explore a feature that only exists on your ALB: sticky sessions.
By default, a load balancer sends each request to whichever instance is healthiest or least loaded. But some applications need a user to stay connected to the same backend instance for the entire session. Sticky sessions solve this by attaching a cookie to the user's browser that tells the ALB where to route subsequent requests.
In this step, get ready to:
- Enable duration-based sticky sessions on your ALB target group and verify with browser cookies.
- Understand application-based cookies and the exam traps around cookie types.
- Disable sticky sessions to prepare for scaling tests in the next step.
Enable duration-based sticky sessions
Duration-based stickiness uses a cookie generated by the ALB itself. The ALB sets this cookie in the user's browser, and on every subsequent request within the configured duration, the ALB reads the cookie and routes to the same target instance.
- In the EC2 console, click Target Groups in the left sidebar.
- Select lab-4b-tg.
- Click the Attributes tab, then click Edit.
- Scroll down to the Stickiness section and turn it On.
- For Stickiness type, select Load balancer generated cookie.
- Set Stickiness duration to 120 seconds.
- Click Save changes.
What did you just configure?
You told the ALB to set a cookie called AWSALB in every user's browser. For the next 120 seconds after the first request, the ALB reads that cookie and sends the user back to the same instance.
Once 120 seconds pass, the cookie expires and the ALB is free to route the next request to any healthy target.
Now test that stickiness is working by observing the same instance ID on refresh.
- Open your ALB DNS name in a browser tab. You should see the Apache page with an instance ID.
- Refresh the page multiple times. Notice that the instance ID stays the same on every refresh.
- Open your browser developer tools by pressing F12.
- Click the Application tab (Chrome) or Storage tab (Firefox).
- Expand Cookies in the left panel and click on your ALB DNS name. Look for the AWSALB cookie set by the load balancer.
Seeing different instance IDs on refresh?
Make sure you saved the stickiness changes. Return to the Attributes tab of lab-4b-tg and confirm Stickiness shows as enabled with 120 seconds.
If you waited more than 120 seconds between refreshes, the cookie has expired and routing resets. Try refreshing several times quickly within the window.
Help me troubleshoot why my ALB sticky sessions aren't routing to the same instance on refresh.
Understand application-based cookies for the exam
The SAA-C03 exam tests two types of ALB stickiness. You just configured the first type (load balancer generated cookie). The second type is application-based, where your own application creates the cookie.
What are the two ALB stickiness types?
- Duration-based (lb_cookie): The ALB generates and manages the cookie (AWSALB). You just configured this.
- Application-based (app_cookie): Your application generates its own cookie with a custom name. The ALB reads that cookie for routing decisions.
Both types support a stickiness duration from 1 second to 604800 seconds (1 week). The default is 86400 seconds (1 day).
What cookie names are reserved?
If you use application-based stickiness, your custom cookie name cannot start with AWSALB, AWSALBAPP, or AWSALBTG. These prefixes are reserved by the load balancer.
The AWSALBTG cookie is a separate concept entirely. It handles target group stickiness when you forward to multiple weighted target groups. Do not confuse it with AWSALB (target-level stickiness within a single target group).
Exam trap: sticky sessions and Auto Scaling
If a sticky instance becomes unhealthy, the ALB breaks stickiness and routes to a healthy target. New instances launched by Auto Scaling will not receive sticky traffic until existing cookies expire.
Disable sticky sessions for remaining steps
Sticky sessions can interfere with the scaling tests you will run in the next step. You need traffic distributed evenly across instances to trigger CloudWatch alarms properly.
- Return to Target Groups in the EC2 console and select lab-4b-tg.
- Click the Attributes tab, then click Edit.
- Turn Stickiness to Off.
- Click Save changes.
- Verify by refreshing your ALB DNS name several times. You should now see different instance IDs appearing as traffic distributes across both instances.
Still hitting the same instance after disabling?
Your browser may still have the AWSALB cookie cached from the previous test. Clear your cookies or open an incognito/private window to get a fresh session.
Help me figure out why I'm still seeing the same instance after disabling sticky sessions on my ALB target group.
You now understand how sticky sessions work and when the exam expects you to choose each type. Next up, you'll configure step scaling and scheduled scaling policies to give your ASG multi-tiered, intelligent responses to demand changes.
Configure Step Scaling and Scheduled Scaling Policies
Your ASG currently has no scaling policy attached. It launched 2 instances and will keep exactly 2 running no matter what happens to CPU or traffic.
In this step, you will wire up intelligent scaling. You will create a CloudWatch alarm that monitors CPU utilization, attach a step scaling policy that adds instances in tiers as load increases, and schedule a capacity change for predictable traffic patterns.
In this step, get ready to:
- Create a CloudWatch alarm that triggers when CPU crosses 60%.
- Attach a step scaling policy with tiered instance additions.
- Set up a scheduled scaling action for predictable load patterns.
Create a CloudWatch alarm for step scaling
Step scaling policies need a CloudWatch alarm to tell them when to fire. The alarm watches a metric and enters the ALARM state when the metric breaches a threshold for a set number of evaluation periods.
- Open the CloudWatch console.
- In the left navigation pane, choose Alarms, then All alarms.
- Click Create alarm.
- Click Select metric.
- On the All metrics tab, choose EC2, then choose By Auto Scaling Group.
- Search for lab-4b-asg and select the CPUUtilization metric row.
- Click Select metric.
- Under Statistic, choose Average.
- Under Period, choose 1 minute.
- Under Conditions, select Static for the threshold type.
- For the comparison, choose Greater/Equal and enter 60 as the threshold value.
- Expand Additional configuration.
- Set Datapoints to alarm to 2 out of 2. This means 2 consecutive 1-minute periods must breach before the alarm fires.
- Click Next.
- On the Configure actions page, remove all notification actions. You will link this alarm from the ASG console instead.
- Click Next.
- For Alarm name, enter lab-4b-cpu-high.
- Click Next, review your settings, then click Create alarm.
Why remove notification actions?
You only need this alarm to trigger the step scaling policy you are about to create. Linking happens on the ASG side when you select this alarm in the policy wizard.
Adding an SNS notification is optional and would send you an email every time CPU crosses 60%. For a lab environment that is unnecessary noise.
Your new alarm appears in the All alarms list. It will initially show Insufficient data because CloudWatch needs a couple of minutes to collect data points.
Don't see your alarm?
Make sure you are in the same Region where your ASG runs. Check the Region selector in the top-right corner of the console.
help me find my CloudWatch alarm for lab-4b-cpu-high
Create a step scaling policy
Step scaling lets you define tiered responses to load. Instead of a single reaction, you can add 1 instance at 60% CPU and add 2 more instances at 80% CPU. This aggressive, multi-tier approach handles sudden traffic spikes faster than target tracking alone.
- Switch to the EC2 console.
- In the left navigation pane, choose Auto Scaling Groups.
- Select the checkbox next to lab-4b-asg.
- Click the Automatic scaling tab in the bottom pane.
- In the Dynamic scaling policies section, click Create dynamic scaling policy.
- For Policy type, choose Step scaling.
- For the policy name, enter lab-4b-step-scale-out.
- For CloudWatch alarm, select lab-4b-cpu-high from the dropdown.
- Define the first step: Add 1 capacity units when the metric is >= 60 (the alarm threshold).
- Click Add step to add a second tier: Add 2 capacity units when the metric is >= 80.
- For Instance warmup, enter 60 seconds.
- Click Create.
What is instance warmup?
A newly launched instance needs time to boot and start serving traffic. During the warmup period (60 seconds here), the instance is not counted toward the group's aggregated CPU metric.
Without a warmup, the ASG might see high average CPU (because the new instance is still booting) and launch yet another instance unnecessarily.
Why step scaling instead of target tracking?
Target tracking (from Project 4a) maintains a single metric target like a thermostat. It works well for steady workloads. Step scaling gives you multi-tier control. You decide exactly how many instances to add at each severity level.
Use step scaling when you need aggressive, tiered responses to sudden load spikes or when you are scaling on custom metrics that don't fit the thermostat model.
You should now see lab-4b-step-scale-out listed under Dynamic scaling policies on the Automatic scaling tab.
Policy not appearing?
If the alarm dropdown did not show lab-4b-cpu-high, confirm the alarm was created in the same Region as your ASG. Also check that the alarm has no actions attached (the step scaling wizard expects to claim it).
help me troubleshoot my step scaling policy creation
Create a scheduled scaling action and understand predictive scaling
Scheduled scaling pre-adjusts your group's capacity at known times. If you know traffic spikes every Monday at 9 AM, you can scale out before users arrive instead of waiting for CPU to climb.
- Stay on the Automatic scaling tab for lab-4b-asg.
- Scroll down to the Scheduled actions section.
- Click Create scheduled action.
- For Name, enter lab-4b-morning-scaleout.
- Set Desired capacity to 3.
- Set Min to 2.
- Set Max to 4.
- For the time, choose a specific time a few minutes from now (one-time schedule for testing purposes).
- Click Create.
After the scheduled time passes, check the Activity tab. You should see the ASG launching a third instance to meet the new desired capacity of 3.
Can scheduled scaling and step scaling coexist?
Yes. Scheduled scaling sets a new baseline capacity at the scheduled time. Step scaling (or target tracking) then handles unexpected spikes above that baseline.
For example, you might schedule minimum capacity of 5 every weekday at 8 AM, then let step scaling add more if CPU exceeds 60% during an unexpected surge.
What is predictive scaling?
Predictive scaling uses machine learning to forecast future traffic based on historical patterns. It requires at least 24 hours of CloudWatch data (ideally 14 days) to build an accurate model.
You can run it in forecast-only mode (observe recommendations without acting) or forecast-and-scale mode. It works best with cyclical, repeating patterns.
For the SAA-C03 exam, remember that predictive scaling complements target tracking. Predictive handles the expected pattern while target tracking catches unexpected spikes on top.
Exam trap: scaling policy types
The four EC2 Auto Scaling policy types are: TargetTrackingScaling, StepScaling, SimpleScaling (default, deprecated in practice), and PredictiveScaling.
If a question mentions "tiered responses" or "custom metric thresholds" the answer is step scaling. If it mentions "forecast" or "machine learning" the answer is predictive scaling.
Scheduled action didn't fire?
Ensure the scheduled time is set in the future (even by 2 minutes). Check the Scheduled actions section to confirm the action shows a valid start time.
Also confirm your ASG's max capacity is at least 3. If max is 2, the scheduled action cannot raise desired to 3.
help me troubleshoot my scheduled scaling action
Your ASG now has intelligent scaling. The step policy handles sudden CPU spikes in tiers, and the scheduled action pre-scales for predictable patterns. Next up, you will configure a warm pool and lifecycle hook to make scale-out even faster.
Configure Warm Pools and Lifecycle Hooks
Your ASG now has a step scaling policy for aggressive scale-out and a scheduled action for predictable patterns. The missing piece is speed.
When your ASG launches a fresh instance, it has to boot the OS, run user data, and pass health checks before it can serve traffic. A warm pool keeps pre-initialized instances on standby so scale-out is nearly instant. A lifecycle hook pauses the instance during launch so you can run custom initialization before it enters service.
In this step, get ready to:
- Create a warm pool with stopped instances for faster scale-out.
- Add a lifecycle hook that pauses new instances during launch.
- Test the hook by triggering a scale-out and observing the wait state.
Create a warm pool
A warm pool is a set of pre-initialized EC2 instances that sit alongside your ASG. When a scale-out event fires, the ASG draws from the warm pool instead of launching a cold instance from scratch.
- In the EC2 console, select Auto Scaling Groups from the left navigation pane.
- Select the checkbox next to lab-4b-asg.
- In the lower pane, choose the Instance management tab.
- Scroll to the Warm pool section and choose Create warm pool.
- For Warm pool instance state, leave the default Stopped.
- For Minimum warm pool size, enter 1.
- Leave Instance reuse (Reuse on scale in) unchecked.
- For Warm pool size, keep the Default specification selected.
- Choose Create.
The ASG launches an additional instance, runs its user data (installing Apache), and then stops it. This takes a minute or two.
- Stay on the Instance management tab and look under Warm pool instances.
- Wait until the Lifecycle column shows Warmed:Stopped for the new instance.
What are the warm pool states?
Warm pool instances can be in one of three states:
- Stopped (cheapest). The instance is stopped. You only pay for EBS volumes.
- Running (fastest). The instance stays fully running. You pay full instance cost.
- Hibernated. RAM is preserved to EBS. Resume is fast, but you pay for the larger EBS volume.
The default warm pool size equals your ASG's max capacity minus desired capacity. With max 4 and desired 2, the pool can hold up to 2 instances.
Why Stopped instead of Running?
For the exam, remember that Stopped is the default and the cheapest option. You only pay for EBS storage while the instance is stopped. Running is fastest (zero boot time) but costs as much as a live instance.
On SAA-C03, if a question mentions reducing scale-out latency without paying full instance cost, the answer is a warm pool in Stopped state.
Add a lifecycle hook for instance launch
A lifecycle hook pauses an instance at a specific point during its lifecycle. For launches, the hook holds the instance in a Pending:Wait state so you can run custom initialization (install software, register with config management, or pull data from S3) before it joins the target group.
- Still on the Instance management tab for lab-4b-asg, scroll to the Lifecycle hooks section.
- Choose Create lifecycle hook.
- For Lifecycle hook name, enter lab-4b-launch-hook.
- For Lifecycle transition, choose Instance launch.
- For Heartbeat timeout, enter 300 (5 minutes).
- For Default result, choose CONTINUE.
- Leave Notification metadata blank.
- Choose Create.
What do the lifecycle hook settings mean?
- Heartbeat timeout is the maximum time (in seconds) an instance stays in the wait state. The valid range is 30 to 7200 seconds. The default is 3600 seconds (1 hour).
- Default result determines what happens if the timeout expires without a response. CONTINUE proceeds with the launch. ABANDON terminates the instance immediately.
- The AWS default for Default result is ABANDON. You are choosing CONTINUE here so test instances still enter service after the wait expires.
For the exam, remember that lifecycle hooks support two transitions: Pending:Wait for launches and Terminating:Wait for terminations.
When would you use a lifecycle hook?
Common use cases include installing software that is not baked into the AMI, registering with a configuration management tool, pulling application data from S3, or running a health validation script before the instance serves traffic.
On SAA-C03, if a question mentions running custom actions before an instance enters service or before it terminates, the answer is a lifecycle hook.
Test the lifecycle hook
You will trigger a scale-out manually and observe the new instance pause in the wait state before entering service.
- In the EC2 console, select Auto Scaling Groups and choose lab-4b-asg.
- Choose the Details tab.
- Under Group details, choose Edit.
- Change Desired capacity from 2 to 3.
- Choose Update.
The ASG draws an instance from the warm pool (or launches a new one if the pool is empty). Because of your lifecycle hook, the instance pauses before joining the target group.
- Switch to the Activity tab.
- Look for a new activity entry. The Status column shows the instance is launching.
- Switch to the Instance management tab.
- Under Instances, find the new instance. Its Lifecycle column shows Pending:Wait.
What happens next?
Since you set Default result to CONTINUE with a 300-second timeout, the instance will automatically proceed to Pending:Proceed and then InService after 5 minutes. You do not need to take any manual action.
In production, your automation would call the complete-lifecycle-action API once initialization finishes, so the instance enters service immediately instead of waiting the full timeout.
- Wait approximately 5 minutes (or refresh the page periodically). The instance moves from Pending:Wait to InService.
Now reset the desired capacity so you do not leave extra instances running.
- Return to the Details tab of lab-4b-asg.
- Under Group details, choose Edit.
- Change Desired capacity back to 2.
- Choose Update.
Not seeing Pending:Wait?
- If the instance goes straight to InService, double-check that the lifecycle hook lab-4b-launch-hook exists under the Lifecycle hooks section.
- Make sure the Lifecycle transition is set to Instance launch, not Instance terminate.
- If you waited too long before checking, the 300-second timeout may have already elapsed and the instance moved to InService automatically.
Help me troubleshoot why my lifecycle hook isn't pausing instances in Pending:Wait.
Secret mission
Scale-In Step Policy and Warm Pool Instance Reuse
Your Auto Scaling Group can scale out aggressively, but what happens when load drops? Right now, scaled-in instances are terminated and new ones must be launched from scratch on the next spike. Add a scale-in policy and enable warm pool instance reuse to recycle instances instead of destroying them.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses load balancers and Elastic IPs that charge per hour, so costs accumulate if left running.
Cost warning
The NLB charges approximately $0.0225/hr per AZ, and the ALB charges the same rate. Elastic IPs charge $0.005/hr each when not attached to a running instance. Together, the load balancers alone cost approximately $0.10-0.20/hr.
EC2 t2.micro instances are free tier eligible. If you are outside the free tier, those also incur charges. Delete all resources when you are finished to avoid unexpected bills.
Resources you used:
- 1 Launch Template (lab-4b-template).
- 1 Application Load Balancer (lab-4b-alb).
- 1 Network Load Balancer (lab-4b-nlb).
- 2 Target Groups (lab-4b-tg and lab-4b-nlb-tg).
- 1 Auto Scaling Group (lab-4b-asg) with warm pool, lifecycle hook, scaling policies, and scheduled action.
- 2-4 EC2 instances launched by the ASG.
- 2 Elastic IPs assigned to the NLB.
- 2 CloudWatch alarms (lab-4b-cpu-high and lab-4b-cpu-low).
Keep everything running
No action needed. Choose this if you are still actively building or experimenting with your scaling setup.
- Your load balancers will continue charging approximately $0.10-0.20/hr combined.
- Elastic IPs remain attached to the NLB at no additional cost while the NLB is active.
- EC2 instances remain running (free tier eligible for t2.micro).
Pause - I'll come back to this later
Shut down your instances to stop compute charges, but be aware that load balancers still charge per hour even with no healthy targets.
- In the EC2 console, go to Auto Scaling Groups.
- Select lab-4b-asg and click Edit on the Group details section.
- Set Desired capacity, Minimum capacity, and Maximum capacity all to 0.
- Click Update. The ASG terminates all instances and drains the warm pool.
- Note: your ALB and NLB will continue to charge per hour even with no instances. If you will be away for more than an hour or two, consider deleting instead.
Delete - I don't want to use this again
Remove all project resources completely. Follow this order to avoid dependency errors.
- Go to EC2 > Auto Scaling Groups. Select lab-4b-asg, click Delete, and confirm. This terminates all running instances and clears the warm pool.
- Go to EC2 > Load Balancers. Select lab-4b-alb, click Actions > Delete load balancer, and confirm.
- Select lab-4b-nlb, click Actions > Delete load balancer, and confirm.
- Go to EC2 > Elastic IPs. Select both Elastic IPs you allocated for the NLB. Click Actions > Release Elastic IP addresses and confirm.
- Go to CloudWatch > Alarms. Select lab-4b-cpu-high and lab-4b-cpu-low. Click Actions > Delete and confirm.
- Go to EC2 > Target Groups. Select lab-4b-tg, click Actions > Delete, and confirm. Repeat for lab-4b-nlb-tg.
- Go to EC2 > Launch Templates. Select lab-4b-template, click Actions > Delete template, and confirm.
Verify everything is gone
After completing all deletions, check the EC2 instances page. All instances should show a Terminated state. Also confirm no Elastic IPs remain under EC2 > Elastic IPs.
That's a Wrap!
That's a Wrap!
Nice work! You've built a complete advanced scaling and load balancing lab that covers every major mechanism tested on the SAA-C03 exam.
You've learned how to:
- Built a Network Load Balancer with static Elastic IPs and compared Layer 4 vs Layer 7 behavior against your ALB, plus covered Gateway Load Balancer architecture for exam readiness.
- Configured step scaling policies with custom CloudWatch alarms for tiered scaling responses, scheduled scaling for predictable load patterns, and understood predictive scaling requirements.
- Set up a warm pool with pre-initialized stopped instances for faster scale-out and added a lifecycle hook that pauses instances during launch for custom initialization.
- Secret Mission: Created a scale-in step policy and enabled warm pool instance reuse for cost-optimized recycling of scaled-in instances.
Ready to quiz yourself?