Skip to main content

EC2 Instance Types Explained — Stop Paying for Resources You Don't Need

· 5 min read
Goel Academy
DevOps & Cloud Learning Hub

Here's a scenario that happens every single day: a team launches a c5.4xlarge for an app that uses 8% CPU. That's $500/month wasted. Multiply by 50 instances and you're throwing away $25,000 every month. Let's fix that.

Understanding Instance Families

EC2 instance types follow a naming convention: c5.xlarge means family (c) + generation (5) + size (xlarge). Each family is optimized for different workloads.

FamilyOptimized ForExample TypesReal Use Case
t3/t3aBurstable general purposet3.micro - t3.2xlargeDev/test environments, low-traffic web apps
m5/m6iBalanced compute/memorym5.large - m5.24xlargeApp servers, backend APIs, mid-size databases
c5/c6iCompute-intensivec5.large - c5.24xlargeBatch processing, video encoding, ML inference
r5/r6iMemory-intensiver5.large - r5.24xlargeIn-memory caches (Redis), real-time analytics
g4dn/g5GPU-acceleratedg4dn.xlarge - g4dn.16xlargeML training, video transcoding, 3D rendering
i3/i3enStorage-optimizedi3.large - i3.16xlargeData warehouses, distributed file systems

The a suffix (like t3a, m5a) means AMD processors — typically 10% cheaper with comparable performance.

Pricing Models — This Is Where Real Savings Happen

The biggest cost optimization lever in AWS isn't choosing the right instance type. It's choosing the right pricing model.

Pricing ModelDiscount vs On-DemandCommitmentBest For
On-Demand0% (baseline)NoneUnpredictable workloads, short-term testing
Reserved (1yr)~40%1 yearSteady-state production workloads
Reserved (3yr)~60%3 yearsCore infrastructure you know you'll keep
Savings Plans~40-60%1-3 yearsFlexible commitment across instance families
Spot InstancesUp to 90%None (can be interrupted)Batch jobs, CI/CD runners, stateless workers
# Launch a spot instance (up to 90% cheaper)
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type c5.xlarge \
--key-name my-key \
--instance-market-options '{
"MarketType": "spot",
"SpotOptions": {
"MaxPrice": "0.08",
"SpotInstanceType": "one-time",
"InstanceInterruptionBehavior": "terminate"
}
}'

# Check current spot prices
aws ec2 describe-spot-price-history \
--instance-types c5.xlarge \
--product-descriptions "Linux/UNIX" \
--start-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--query 'SpotPriceHistory[*].[AvailabilityZone,SpotPrice]' \
--output table

Key Pairs and Security Groups

Before launching any instance, you need an SSH key pair and a security group:

# Create a key pair
aws ec2 create-key-pair \
--key-name my-app-key \
--key-type ed25519 \
--query 'KeyMaterial' \
--output text > my-app-key.pem
chmod 400 my-app-key.pem

# Create a security group
aws ec2 create-security-group \
--group-name web-server-sg \
--description "Allow HTTP, HTTPS, and SSH" \
--vpc-id vpc-0abc123def456

# Add rules — be specific with source IPs
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--protocol tcp --port 22 \
--cidr 203.0.113.50/32

aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123 \
--protocol tcp --port 443 \
--cidr 0.0.0.0/0

Never open SSH (port 22) to 0.0.0.0/0. Restrict it to your IP or use Systems Manager Session Manager instead.

User Data Scripts — Automate Instance Setup

User data runs on first boot. It's perfect for installing packages, pulling code, and starting services:

# Launch an instance with user data
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t3.medium \
--key-name my-app-key \
--security-group-ids sg-0abc123 \
--user-data file://setup.sh \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-server-01},{Key=Environment,Value=production}]'

Example setup.sh:

#!/bin/bash
yum update -y
yum install -y nginx
systemctl enable nginx
systemctl start nginx
echo "<h1>Server $(hostname)</h1>" > /usr/share/nginx/html/index.html

EBS Volume Types — Choose Wisely

Volume TypeIOPSThroughputCost (per GB/month)Use Case
gp33,000 (baseline), up to 16,000125-1,000 MB/s$0.08Default for most workloads
gp2Burst to 3,000128-250 MB/s$0.10Legacy, migrate to gp3
io2Up to 64,0001,000 MB/s$0.125 + $0.065/IOPSDatabases needing consistent IOPS
st1500 baseline500 MB/s$0.045Big data, log processing
sc1250 baseline250 MB/s$0.015Cold storage, infrequent access
# Create a gp3 volume with custom performance
aws ec2 create-volume \
--volume-type gp3 \
--size 100 \
--iops 5000 \
--throughput 250 \
--availability-zone us-east-1a \
--tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=app-data}]'

Pro tip: gp3 is almost always better than gp2. It's 20% cheaper and you can independently configure IOPS and throughput.

Instance Metadata Service v2 (IMDSv2)

The instance metadata service lets EC2 instances discover information about themselves. IMDSv1 was vulnerable to SSRF attacks, so always enforce IMDSv2:

# Enforce IMDSv2 on a new instance
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t3.medium \
--metadata-options "HttpTokens=required,HttpPutResponseHopLimit=1,HttpEndpoint=enabled"

# Enforce IMDSv2 on an existing instance
aws ec2 modify-instance-metadata-options \
--instance-id i-0abc123def456 \
--http-tokens required \
--http-put-response-hop-limit 1

Using IMDSv2 from inside the instance:

# Get a token (valid for 6 hours)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

# Use the token to query metadata
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id

Right-Sizing with CloudWatch

You can't optimize what you don't measure. Set up CloudWatch to track actual utilization:

# Get average CPU for the last 7 days
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-0abc123def456 \
--start-time $(date -u -d '7 days ago' +"%Y-%m-%dT%H:%M:%SZ") \
--end-time $(date -u +"%Y-%m-%dT%H:%M:%SZ") \
--period 3600 \
--statistics Average \
--output table

If your average CPU is below 20%, you're probably one or two sizes too big. A m5.xlarge running at 15% CPU should be a m5.large or even a t3.large.

What's Next?

Your instances need a network to live in. Next up: VPC networking from scratch — we'll build subnets, configure NAT gateways, and set up security groups and NACLs the right way.


This is Part 4 of our AWS series. Right-size your instances before anything else — it's the easiest money you'll ever save.