---
title: "06 — Auto Scaling: AMIs, Templates, Groups, and the Load Balancer in Front"
uid: auto-scaling
tags: ["aws", "launch-template", "ec2", "elb", "ami", "autoscaling", "roadmap:aws"]
excerpt: "Auto Scaling is three stacked layers with one job each: a golden image (AMI), a launch recipe (template), and a managed fleet with rules (the group) — with a load balancer spreading traffic across whatever size it is."
date: 2026-08-13T03:28:30+0000
source: https://www.aveshina.my.id/en/blog/auto-scaling
---

"More servers when it gets busy" described Auto Scaling's effect but not its machinery, so the console was a vocabulary list I couldn't act on. The layering that clicked: **an Auto Scaling system is a golden image (AMI) that feeds a launch recipe (template) that defines a managed fleet (the Auto Scaling Group) with scaling rules — and a load balancer in front spreads traffic across whatever size the fleet happens to be** [1]. Each layer has one job. Once I separated them, the constellation of ASG-related terms stopped being a vocabulary list and became a pipeline.

## AMIs: the golden image

An **AMI — Amazon Machine Image** — is a pre-configured template an EC2 instance boots from [2]. It bundles the OS, any installed software, configuration, and a snapshot of the root volume. Launch an instance from an AMI and you get, identically, whatever was baked in.

The pattern this enables is **immutable infrastructure**: I bake a new AMI for every release (via a build pipeline), and "deploying" means swapping which AMI the Auto Scaling Group launches from, then rolling instances. No in-place patching, no SSH-and-edit — each instance is a fresh, known-good boot. Public AMIs (Amazon Linux, Ubuntu) cover starting points; the custom ones I bake are private to my account.

## Launch Templates: the recipe

A **Launch Template** is the full recipe the group uses to make an instance [3]: which AMI, which instance type, which keypair, which security groups, what user data, what IAM instance profile, what storage. Templates are versioned, so I can roll forward and back through configurations.

The reason this is separate from the AMI: the AMI is the *contents of the disk*; the template is *how the instance is shaped and launched*. The same AMI can be launched as a t3.micro for dev and an m6i.large for prod, via two templates pointing at the same image. That separation keeps the build pipeline (which produces AMIs) cleanly decoupled from the run configuration (which lives in templates).

## Auto Scaling Groups: the managed fleet

The **Auto Scaling Group (ASG)** is the heart of the system [4]. It manages a logical group of EC2 instances spread across multiple Availability Zones, and it owns three numbers:

- **Minimum** — never fewer than this many instances.
- **Desired** — the target the group tries to hold.
- **Maximum** — never more than this many instances.

The ASG launches instances from the launch template, distributes them across AZs, and continuously health-checks each one. If an instance fails its health check (or the AZ it's in fails), the ASG terminates it and launches a replacement — that is self-healing, and it's the single biggest availability win EC2 offers. Spreading across AZs is the other half: lose a zone, the group keeps serving from the survivors and re-balances.

## Scaling policies: how the numbers move

The min/desired/max bound the group; **scaling policies** decide when the *desired* count changes [5]:

- **Target tracking** — "keep average CPU at 50%." CloudWatch does the math; the ASG adds or removes capacity to hold the target. The simplest and usually right choice.
- **Step scaling** — "if CPU is above 70% for 5 minutes, add 2; if above 90%, add 4." A ladder of thresholds and adjustments.
- **Simple scaling** — a single alarm triggers a single adjustment. Older, coarser; mostly replaced by the other two.

The non-obvious failure mode: **cooldowns**. After a scaling action, the group waits before acting again, so newly-launched instances have time to take load before the policy re-evaluates. Too-short cooldowns cause thrashing (add, remove, add); too-long ones cause slow response. Target tracking hides most of this.

## Elastic Load Balancers: the front door

Traffic has to reach the fleet, and that's the **Elastic Load Balancer (ELB)** [6]. It sits in front, accepts incoming requests, health-checks each instance, and routes traffic only to healthy ones — so the ASG terminating a sick instance and the ELB draining it are coordinated, not two independent events. Three flavors:

- **Application Load Balancer (ALB)** — layer 7, HTTP/HTTPS. Path-based routing, host-based routing, the right default for web apps.
- **Network Load Balancer (NLB)** — layer 4, TCP/UDP. Extreme throughput, static IPs, low latency. Right for non-HTTP or very high-volume workloads.
- **Gateway Load Balancer** — for inserting third-party security appliances in the traffic path.

(Classic Load Balancer still exists, but it's legacy — ALB and NLB cover its use cases better.)

```figure
<svg viewBox="0 0 680 280" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="A load balancer fans out incoming requests across three EC2 instances inside an Auto Scaling Group. The group is bounded by min 2, desired 3, max 6. Above the group, an AMI icon feeds a Launch Template icon, which feeds the group. CloudWatch supplies a metric (CPU 50%) that drives a target-tracking policy.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">
    <defs><marker id="asa" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto"><path d="M0,0 L10,5 L0,10 z" fill="#64748b"/></marker></defs>

    <!-- users -->
    <text x="340" y="20" font-size="11" font-weight="700" fill="#1e1b4b" text-anchor="middle">users</text>
    <path d="M340,24 L340,40" stroke="#64748b" stroke-width="1.5" marker-end="url(#asa)"/>

    <!-- ELB -->
    <rect x="240" y="42" width="200" height="36" rx="8" fill="#e0e7ff" stroke="#6366f1"/>
    <text x="340" y="65" font-size="11" font-weight="700" fill="#1e1b4b" text-anchor="middle">Application Load Balancer</text>

    <!-- ASG boundary -->
    <rect x="60" y="100" width="560" height="160" rx="10" fill="none" stroke="#16a34a" stroke-width="2" stroke-dasharray="6 4"/>
    <text x="75" y="118" font-size="10" font-weight="700" fill="#052e16">Auto Scaling Group   ·   min 2 · desired 3 · max 6</text>

    <!-- instances -->
    <rect x="120" y="140" width="100" height="50" rx="6" fill="#dcfce7" stroke="#16a34a"/><text x="170" y="170" font-size="10" font-weight="700" fill="#052e16" text-anchor="middle">EC2 (healthy)</text>
    <rect x="290" y="140" width="100" height="50" rx="6" fill="#dcfce7" stroke="#16a34a"/><text x="340" y="170" font-size="10" font-weight="700" fill="#052e16" text-anchor="middle">EC2 (healthy)</text>
    <rect x="460" y="140" width="100" height="50" rx="6" fill="#fee2e2" stroke="#dc2626" stroke-dasharray="3 3"/><text x="510" y="170" font-size="10" font-weight="700" fill="#7f1d1d" text-anchor="middle">EC2 (draining)</text>

    <!-- ELB -> instances -->
    <path d="M300,78 L170,140" stroke="#64748b" stroke-width="1.2" marker-end="url(#asa)"/>
    <path d="M340,78 L340,140" stroke="#64748b" stroke-width="1.2" marker-end="url(#asa)"/>
    <path d="M380,78 L510,140" stroke="#cbd5e1" stroke-width="1.2" stroke-dasharray="3 3"/>

    <!-- AMI / Template feeding the group -->
    <rect x="80" y="210" width="100" height="36" rx="6" fill="#fef9c3" stroke="#ca8a04"/><text x="130" y="232" font-size="10" font-weight="700" fill="#422006" text-anchor="middle">AMI (golden)</text>
    <rect x="210" y="210" width="120" height="36" rx="6" fill="#fce7f3" stroke="#db2777"/><text x="270" y="232" font-size="10" font-weight="700" fill="#500724" text-anchor="middle">Launch Template</text>
    <path d="M180,228 L210,228" stroke="#64748b" stroke-width="1.2" marker-end="url(#asa)"/>
    <path d="M270,210 L270,195" stroke="#64748b" stroke-width="1.2" marker-end="url(#asa)"/>

    <!-- CloudWatch metric -->
    <rect x="380" y="210" width="220" height="36" rx="6" fill="#e0e7ff" stroke="#6366f1"/><text x="490" y="226" font-size="10" font-weight="700" fill="#1e1b4b" text-anchor="middle">CloudWatch</text><text x="490" y="240" font-size="9" fill="#1e1b4b" text-anchor="middle">target: avg CPU = 50%</text>
  </g>
</svg>
```

The whole picture: traffic hits the ALB, which fans out to healthy instances in the ASG; CloudWatch's CPU metric drives a target-tracking policy that nudges desired capacity; the launch template (built from the AMI) defines every new instance the group spins up. Four services, one feedback loop.

## How I use this

Auto Scaling is the reason EC2 feels elastic rather than just "rented VMs." The discipline I keep: bake AMIs in CI, never edit running instances; version launch templates and treat them as the deploy unit; size ASGs across at least two AZs with min ≥ 2 so a single AZ outage doesn't take the service down; default to target-tracking scaling on a meaningful metric (CPU for compute-bound, request-count-per-target for web frontends) instead of hand-tuned step ladders; and always pair an ASG with a load balancer — without the LB, the group can scale but traffic won't follow. The min/desired/max triple is the cheapest availability insurance in AWS: I set min to what I need to survive a spike, max to what I'm willing to pay for, and let the policy ride in between.

## References

[1] Amazon Web Services, "What is Amazon EC2 Auto Scaling," EC2 Auto Scaling User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html](https://docs.aws.amazon.com/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html)

[2] Amazon Web Services, "Amazon Machine Images (AMIs)," EC2 User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html)

[3] Amazon Web Services, "Launch templates," EC2 User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-launch-templates.html)

[4] Amazon Web Services, "Auto Scaling groups," EC2 Auto Scaling User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html](https://docs.aws.amazon.com/autoscaling/ec2/userguide/auto-scaling-groups.html)

[5] Amazon Web Services, "Scaling policies for Amazon EC2 Auto Scaling," EC2 Auto Scaling User Guide, 2024. [Online]. Available: [https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-scaling-and-policies.html](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-scaling-and-policies.html)

[6] Amazon Web Services, "Elastic Load Balancing," 2024. [Online]. Available: [https://aws.amazon.com/elasticloadbalancing/](https://aws.amazon.com/elasticloadbalancing/)

```quiz
Q: What is the role of an AMI in an Auto Scaling setup?
- It is the pre-baked disk image the launch template boots new instances from
- It is the load balancer that distributes traffic
correct: 0
explain: The AMI is the golden image — OS plus software. The launch template references it, and the ASG launches instances from the template. Baking a new AMI per release enables immutable deploys.

Q: A target-tracking scaling policy set to "avg CPU = 50%" will…
- add capacity when CPU rises above 50%, remove it when below, trying to hold the target
- keep the instance count fixed at 50
correct: 0
explain: Target tracking treats a metric as a setpoint. CloudWatch does the math and the ASG adds or removes instances to hold the target value.

Q: Why spread an Auto Scaling Group across multiple Availability Zones?
- So that losing one AZ still leaves healthy instances serving in the others
- Because a single AZ has a hard instance limit
correct: 0
explain: Multi-AZ distribution is the core availability mechanism. The ASG also auto-rebalances when an AZ comes back.

Q: Which load balancer is the right default for an HTTP/HTTPS web app with path-based routing?
- Application Load Balancer (ALB)
- Network Load Balancer (NLB)
correct: 0
explain: ALB is layer 7 and supports path/host-based routing. NLB is layer 4 (TCP/UDP) and is chosen for throughput or non-HTTP protocols.

Q: Without a load balancer in front of an Auto Scaling Group, the group can still…
- scale up and down, but new traffic won't be distributed to the new instances
- terminate any instance at will, which is the same effect
correct: 0
explain: The ASG scales the fleet, but the ELB is what actually routes traffic to healthy instances and coordinates draining. Without one, scaling happens in a fleet nothing is sending traffic to correctly.
```
