Filter concepts by levelShowing all levels.

AWS · Section 12

EC2 — Compute Fundamentals

Level
intermediate
Read
30 min
Concepts
5

An EC2 instance starts from an AMI and an instance type, configured at first boot by user data — but knowing how to launch one is only the start. This section covers the core EC2 vocabulary, the purchasing options and the tradeoffs each one makes, vertical versus horizontal scaling, placement groups and tenancy, and how to diagnose CPU, memory, disk, and network problems given what CloudWatch actually reports by default.

What is true here

  1. An AMI is the template, an instance type is the fixed CPU/memory/network bundle, and user data runs once at first boot only — and stays retrievable for the instance's whole life.
  2. On-Demand, Savings Plans, Reserved Instances, and Spot each trade commitment or interruption risk for a lower rate — match the option to the workload's actual shape.
  3. Vertical scaling has a ceiling and a resize-time availability gap; horizontal scaling needs statelessness and a load balancer but scales further and tolerates single-instance failure.
  4. Cluster placement trades fault isolation for the lowest latency; spread placement trades some latency for maximum fault isolation.
  5. CloudWatch's default EC2 metrics cover CPU, network, and disk I/O — memory and disk space usage require the CloudWatch agent, and missing data is not the same as a healthy reading.

What you will be able to do

  • Explain what an AMI, instance type, and user data each contribute to a launched instance
  • Choose an EC2 purchasing option that matches a workload's actual usage shape
  • Decide between vertical and horizontal scaling for a given growth scenario
  • Choose a placement group strategy based on whether a workload is latency-sensitive or fault-sensitive
  • Diagnose an instance problem knowing which resources CloudWatch reports by default and which need the agent
From launch to diagnosed

AMI + type + user data

defines what launches

Purchasing option chosen

matched to the workload's shape

Scaled vertically or horizontally

as load changes

Diagnosed with real data

not just what looks healthy by default

  1. AMI + type + user data — defines what launches
  2. Purchasing option chosen — matched to the workload's shape
  3. Scaled vertically or horizontally — as load changes
  4. Diagnosed with real data — not just what looks healthy by default

EC2 Compute Fundamentals

The core EC2 vocabulary, purchasing options and tradeoffs, vertical vs horizontal scaling, placement groups and tenancy, and diagnosing real problems.

EC2 vocabulary: instances, AMIs, and instance types

coreintermediate

An instance is a running virtual server, launched from an AMI (a template of a disk image) at a chosen instance type (a fixed bundle of CPU/memory/network). User data runs once at first boot; the instance metadata service answers questions the instance asks about itself.

Think of it as

An AMI is a recipe. An instance type is the size of pan you cook it in — the same recipe in a bigger pan gets you more of everything at once. User data is the instructions taped to the pan for exactly what to do the first time it comes out of the oven.

bash
aws ec2 run-instances --image-id ami-0abc123 --instance-type m6g.large \
  --user-data file://init.sh --security-group-ids sg-0def456

What we're doing: See a user-data script that runs once at first boot, and where it gets its instructions from.

init.shbash
#!/bin/bash
# runs once, as root, on first boot only
yum install -y nginx
systemctl enable --now nginx
1
The shebang tells EC2 how to execute this user-data payload — bash here, but it could equally be cloud-init YAML.
3
This install only happens on first boot — restarting the instance later does not re-run this script.

Why this works: User data is the mechanism that turns a generic AMI into a specifically configured instance at launch time, without needing a custom AMI baked for every possible configuration.

Assuming user data re-runs on every instance restart

Wrong

text
# "I updated the user data script and rebooted the instance — the change should apply now."

Better

text
# User data runs once at first launch — a running instance needs its
# own re-provisioning step, or should be replaced with a new launch

What you see: An updated user-data script has no effect on an already-running instance, even after a full reboot.

Why: User data executes on first boot only, by design — cloud-init (the component that runs it) tracks that it has already executed and skips it on subsequent boots unless explicitly reset, which is not the default reboot behavior.

The three pieces that define an instance

AMI

the template — OS + software

Instance type

fixed vCPU/memory/network bundle

User data

runs once, at first boot only

  1. AMI — the template — OS + software
  2. Instance type — fixed vCPU/memory/network bundle
  3. User data — runs once, at first boot only

Instance lifecycle states and what changes in each

Instance lifecycle states and what changes in each
StateWhat still existsBilled?
pendingInstance being launchedNot yet
runningFully activeYes
stopping / stoppedEBS root volume persists; instance store does notNo compute charge, EBS still billed
terminatedInstance and (by default) its root EBS volume are goneNo

Together

bash
aws ec2 describe-instances --instance-ids i-0abc123 --query "Reservations[].Instances[].State.Name"

Remember: An AMI is the template, an instance type is the fixed CPU/memory/network bundle, user data runs once at first boot only — and it stays retrievable for the instance's whole life, so it is not a safe place for secrets.

See also: purchasing options · instance store vs ebs

EC2 purchasing options and their tradeoffs

coreintermediate

On-Demand costs the most per hour but requires no commitment. Savings Plans and Reserved Instances trade a 1- or 3-year commitment for a lower rate. Spot Instances are unused capacity at a steep discount, but AWS can reclaim them with short notice.

Think of it as

On-Demand is a nightly hotel rate. A Savings Plan or Reserved Instance is a year-long lease at a discount for committing. A Spot Instance is a standby airline seat — cheap, but you might get bumped if a full-fare passenger needs it.

text
Predictable, steady load     → Savings Plan / Reserved Instance
Unpredictable / short-lived  → On-Demand
Flexible timing, fault-tolerant → Spot

What we're doing: See how the same workload might mix purchasing options rather than using one exclusively.

fleet-mix.txttext
Baseline (always-on, predictable): Savings Plan-covered instances
Burst capacity (traffic spikes):    On-Demand instances
Batch processing (can be retried):  Spot Instances
1
Steady, predictable load is exactly what a 1- or 3-year commitment is priced to reward.
2
Unpredictable spikes are covered without any commitment, at the cost of the higher per-hour rate.
3
A batch job that can tolerate being interrupted and retried gets the steepest discount available.

Why this works: A single fleet rarely fits one purchasing option cleanly — mixing them so each workload characteristic (steady vs bursty vs interruptible) is matched to the option that rewards it is how the discount is actually captured without giving up flexibility where it is needed.

Running a stateful, non-interruptible workload on Spot Instances for the discount alone

Wrong

text
# Production database on a single Spot Instance, "because it's cheaper"

Better

text
# Spot for fault-tolerant, interruptible work (batch jobs, stateless
# workers) — not for anything that cannot tolerate an abrupt reclaim

What you see: The instance is reclaimed by AWS with short notice, and anything not already checkpointed or replicated elsewhere is lost or causes an outage.

Why: Spot's discount exists specifically because AWS can reclaim that capacity when needed elsewhere — the discount is not free, it is priced against workloads accepting that interruption risk, which a stateful, non-redundant workload structurally cannot.

What each option trades for a lower rate
On-Demand
highest rate, zero commitment
Reserved Instances
fixed config, 1-3yr
Savings Plans
flexible family, 1-3yr
Spot Instances
steepest discount, reclaimable
  • On-Demand: no commitment, must never be interrupted — highest rate, zero commitment
  • Reserved Instances: multi-year commitment, must never be interrupted — fixed config, 1-3yr
  • Savings Plans: multi-year commitment, must never be interrupted — flexible family, 1-3yr
  • Spot Instances: no commitment, tolerates interruption — steepest discount, reclaimable

Purchasing options and what each trades for a lower rate

Purchasing options and what each trades for a lower rate
OptionCommitmentBest for
On-DemandNoneUnpredictable or short-lived workloads
Savings Plans1 or 3 years, $/hourSteady baseline usage, flexible instance family
Reserved Instances1 or 3 years, specific configSteady usage with a known, fixed configuration
Spot InstancesNone, but interruptibleFault-tolerant, flexible-timing workloads

Together

bash
aws ec2 request-spot-instances --instance-count 1 --launch-specification file://spec.json

Remember: Match the option to the workload's shape: steady and predictable earns a Savings Plan or Reserved Instance discount, unpredictable stays On-Demand, and only genuinely interruptible workloads belong on Spot.

See also: ec2 vocabulary · instance replacement design

Vertical vs horizontal scaling

standardintermediate

Vertical scaling means making one instance bigger (more vCPU/memory) — simple, but capped by the largest instance type and requires a stop/start. Horizontal scaling means adding more instances — takes more design (statelessness, load balancing) but scales further and survives one instance failing.

Think of it as

Vertical scaling is hiring a stronger single worker. Horizontal scaling is hiring more workers — the team keeps functioning even if any one worker is out sick, which a single (even very strong) worker cannot offer.

text
Vertical:   m6g.large → m6g.2xlarge      (bigger, same instance, ceiling exists)
Horizontal: 1x m6g.large → 4x m6g.large  (more instances, load-balanced)

What we're doing: Compare what actually happens to availability when scaling vertically versus horizontally, given the same load increase.

scaling-comparison.txttext
# Vertical scaling
1x m6g.large → stop → resize to m6g.2xlarge → start
# during the resize, that single instance is fully unavailable

# Horizontal scaling
1x m6g.large → add 3 more m6g.large behind the load balancer
# each addition happens without taking any existing instance offline
2
Vertical scaling of an EC2 instance requires stopping it first — there is a real, if brief, availability gap.
6
New instances join the target group as they become healthy — no existing capacity is ever taken offline to add more.

Why this works: The tradeoff is not just "which scales further" — vertical scaling has an unavoidable availability gap during the resize itself, which horizontal scaling does not need at all.

Scaling vertically indefinitely instead of redesigning for horizontal scale

Wrong

text
# Traffic grows → keep bumping to the next larger instance type each time

Better

text
# Recognize the ceiling (largest instance type, or diminishing returns)
# and invest in statelessness + load balancing before hitting it

What you see: The team hits the largest available instance type with load still growing, and now has to redesign for horizontal scaling under time pressure instead of by choice.

Why: Vertical scaling has a hard ceiling — the largest instance type that exists — and postponing the horizontal-scaling redesign until that ceiling is reached means doing the harder architectural work (externalizing state, adding a load balancer) during an active capacity crisis rather than proactively.

Remember: Vertical scaling is simpler but has a ceiling and a resize-time availability gap; horizontal scaling needs statelessness and a load balancer but scales further and survives single-instance failure.

See also: statelessness behind lb · target tracking and scaling policies

Placement groups and tenancy

standardintermediate

A placement group controls how EC2 physically places your instances relative to each other — clustered for low latency, spread for maximum fault isolation, or partitioned for large distributed systems. Tenancy controls whether your instance shares physical hardware with other AWS customers at all.

Think of it as

A placement group is choosing seating arrangement for a group at a venue: all together at one table (cluster, fast to pass things around), spread across separate rooms (spread, so one room's problem does not affect the others), or divided into a few group tables (partition). Tenancy is choosing whether you're in a shared building or one entirely to yourself.

text
Need lowest latency between instances → cluster
Need max fault isolation, few instances → spread
Large distributed system, rack-aware     → partition

What we're doing: See the actual tradeoff cluster placement makes explicit: speed against blast radius.

cluster-tradeoff.txttext
# Cluster placement group
Instances packed close together on the same underlying hardware/network
→ lowest possible inter-instance latency

# But:
A single hardware failure can simultaneously affect many instances
in the same cluster placement group
2
Physical proximity is exactly what buys the latency improvement.
5
That same physical proximity is what makes a hardware failure's blast radius larger than instances spread across distinct hardware.

Why this works: Cluster placement is a deliberate tradeoff, not a strictly-better option — the same physical closeness that minimizes latency is what increases the number of instances a single hardware failure could affect at once.

Using cluster placement for a fault-tolerant, latency-insensitive workload

Wrong

text
# General web app instances behind a load balancer, "clustered for best performance"

Better

text
# Spread placement (or no placement group) — this workload cares more
# about fault isolation than shaving inter-instance latency

What you see: A single hardware issue takes out an unexpectedly large fraction of the fleet at once, for a workload that never actually needed the latency benefit cluster placement provides.

Why: Cluster placement optimizes specifically for inter-instance network performance — a workload whose instances barely talk to each other (like independent web servers behind a load balancer) gains little from it while still taking on its larger blast-radius tradeoff.

Placement group strategies

Placement group strategies
StrategyOptimizes forConstraint
ClusterLowest network latency, highest throughputSingle AZ; a hardware failure can affect many at once
SpreadMaximum fault isolationMax 7 running instances per AZ per group
PartitionLarge-scale distributed systems needing rack-level isolationPartitions map to distinct racks, tracked by the app

Together

bash
aws ec2 create-placement-group --group-name low-latency-cluster --strategy cluster

Remember: Cluster placement trades fault isolation for the lowest latency; spread placement trades some latency for maximum fault isolation — choose based on whether the workload is latency-sensitive or fault-sensitive.

See also: ec2 vocabulary · blast radius containment

Diagnosing instance resource problems

coreintermediate

CloudWatch's default EC2 metrics cover CPU, network, and disk I/O — but not memory or disk space, which require the CloudWatch agent installed on the instance. Diagnosing "the instance is slow" starts with knowing which of these five resources CloudWatch already sees, and which it does not.

Think of it as

A car's dashboard shows speed and engine RPM by default (like default EC2 metrics), but checking oil level or tire pressure needs a separate sensor installed (like the CloudWatch agent for memory and disk space) — the dashboard was never blind, it just never had that sensor to begin with.

text
StatusCheckFailed_System → AWS infrastructure issue, often self-resolves or needs a stop/start
StatusCheckFailed_Instance → OS-level issue, often needs investigation on the instance

What we're doing: See why "the instance seems fine in CloudWatch" can still mean it is out of memory.

metrics-available.txttext
CPUUtilization: 12%        # looks healthy
NetworkIn/Out: normal       # looks healthy

# but without the CloudWatch agent installed:
mem_used_percent: not reported at all — no data, not "0%"
2
Every default metric can look completely normal even while the instance is struggling.
5
Missing memory data is not the same as healthy memory — it means nothing was ever configured to report it.

Why this works: A gap in CloudWatch's dashboard is easy to misread as "nothing wrong here" instead of "this was never being measured" — an out-of-memory condition can be invisible to CloudWatch entirely without the agent, even while CPU and network both look completely fine.

Concluding an instance is healthy because default CloudWatch metrics look normal

Wrong

text
# "CPU and network both look fine in CloudWatch — the instance must be healthy."

Better

text
# Confirm the CloudWatch agent is installed and check mem_used_percent /
# disk_used_percent explicitly before ruling those out

What you see: An instance repeatedly gets OOM-killed or runs out of disk space, while every dashboard graph that was actually being watched showed nothing abnormal the whole time.

Why: Default EC2 metrics simply do not include memory or disk space — a dashboard with no data for those two is not evidence of health, it is evidence that nothing was ever configured to report on them.

What CloudWatch already sees, before reaching for the agent

CPUUtilization

visible by default, no agent needed

NetworkIn / NetworkOut

visible by default, no agent needed

Disk I/O

visible by default, no agent needed

mem_used_percent / disk_used_percent

no data at all without the CloudWatch agent installed

  1. CPUUtilization — visible by default, no agent needed
  2. NetworkIn / NetworkOut — visible by default, no agent needed
  3. Disk I/O — visible by default, no agent needed
  4. mem_used_percent / disk_used_percent — no data at all without the CloudWatch agent installed

What is visible by default vs what needs the CloudWatch agent

What is visible by default vs what needs the CloudWatch agent
ResourceVisible by default?
CPU utilizationYes — CPUUtilization metric
Network in/outYes — NetworkIn / NetworkOut
Disk I/OYes — read/write ops and bytes
Memory usageNo — requires the CloudWatch agent
Disk space usageNo — requires the CloudWatch agent

Together

bash
aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name CPUUtilization \
  --dimensions Name=InstanceId,Value=i-0abc123 --start-time ... --end-time ... --period 300 --statistics Average

Remember: CloudWatch's default metrics cover CPU, network, and disk I/O — memory and disk space need the CloudWatch agent explicitly installed, and a metric with no data is not the same as a healthy metric.

See also: ec2 vocabulary · vertical vs horizontal scaling

Advertisement