AWS for DevOps — EC2 Basics
3.1 — EC2 Basics
EC2 (Elastic Compute Cloud) lets you launch virtual servers — called instances — in minutes. You choose the operating system, CPU, memory, storage, and network configuration.
Instance Types
AWS offers hundreds of instance types, grouped into families:
| Family | Optimised For | Example | Use Case |
|---|---|---|---|
| t3/t4g | General purpose (burstable) | t3.micro, t3.medium | Dev servers, small apps |
| m5/m6i | General purpose (fixed) | m5.xlarge | Production web servers |
| c5/c6i | Compute | c5.2xlarge | Build agents, batch jobs |
| r5/r6i | Memory | r5.large | Databases, caching |
| g4/g5 | GPU | g4dn.xlarge | ML inference, video |
| i3/i4i | Storage I/O | i3.large | Databases, data lakes |
Naming convention: t3.micro
t3= family + generationmicro= size (vCPU + memory)
Instance Lifecycle
pending ──► running ──► stopping ──► stopped
│ │
│ └──► starting ──► running
│
└──► shutting-down ──► terminated
| State | Billing | Data |
|---|---|---|
| Running | Charged | Instance store data persists |
| Stopped | Not charged (EBS still charged) | EBS data persists |
| Terminated | Not charged | All data lost (unless EBS DeleteOnTermination: false) |
Launching an Instance (CLI)
$ aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t3.micro \
--key-name my-key-pair \
--security-group-ids sg-0abc123def456 \
--subnet-id subnet-0abc123 \
--count 1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-server-01},{Key=Environment,Value=dev}]'
{
"Instances": [
{
"InstanceId": "i-0abc123def456789",
"InstanceType": "t3.micro",
"State": {"Name": "pending"},
"PrivateIpAddress": "10.0.1.50"
}
]
}
Describing Instances
# List all running instances
$ aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query 'Reservations[*].Instances[*].[InstanceId,InstanceType,PublicIpAddress,Tags[?Key==`Name`].Value|[0]]' \
--output table
------------------------------------------------------
| DescribeInstances |
+-----------------+----------+----------------+-------+
| i-0abc123def456 | t3.micro | 3.110.45.67 | web-1 |
| i-0def456abc789 | t3.small | 3.110.45.68 | web-2 |
+-----------------+----------+----------------+-------+
Connecting to an Instance
# SSH (Linux)
$ ssh -i my-key-pair.pem ec2-user@3.110.45.67
# Or use SSM Session Manager (no SSH key needed, no inbound port)
$ aws ssm start-session --target i-0abc123def456
DevOps preference: Use SSM Session Manager — it requires no open inbound ports, logs all sessions to CloudTrail, and works through private subnets.
Elastic IP Addresses
By default, a public IP changes every time you stop and start an instance. An Elastic IP is a static public IP:
# Allocate an Elastic IP
$ aws ec2 allocate-address --domain vpc
{
"AllocationId": "eipalloc-0abc123",
"PublicIp": "52.66.100.200"
}
# Associate it with an instance
$ aws ec2 associate-address \
--instance-id i-0abc123def456 \
--allocation-id eipalloc-0abc123
Warning: An unattached Elastic IP costs money. Always release it when not in use.
Pricing Models
| Model | Discount | Commitment | Best For |
|---|---|---|---|
| On-Demand | None (full price) | None | Short-term, unpredictable workloads |
| Reserved | Up to 72% | 1 or 3 years | Steady-state production |
| Savings Plans | Up to 72% | 1 or 3 years (flexible) | Mixed workloads |
| Spot | Up to 90% | None (can be interrupted) | Build agents, batch jobs, testing |
Spot Instances are perfect for DevOps:
- CI/CD build agents (job can retry if interrupted)
- Load testing (short-lived, cost-sensitive)
- Data processing (checkpointable work)
# Request a spot instance
$ aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type c5.large \
--instance-market-options 'MarketType=spot,SpotOptions={MaxPrice=0.05,SpotInstanceType=one-time}' \
--count 1
Instance Metadata
From inside an EC2 instance, you can query metadata about itself:
# Get the instance ID (IMDSv2 — recommended)
$ TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 300")
$ curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id
i-0abc123def456789
# Get the IAM role credentials
$ curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2-S3-ReadRole
{
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"Token": "...",
"Expiration": "2026-03-30T12:00:00Z"
}
Security note: Always use IMDSv2 (token-required). IMDSv1 is vulnerable to SSRF attacks.
Common Mistakes
| Mistake | Why It Hurts | Fix |
|---|---|---|
| Leaving instances running after testing | Unexpected bills | Use tags + scheduled shutdown |
| Using t3.micro for production | CPU credits run out under load | Use m5/m6i for steady workloads |
| Allowing IMDSv1 | SSRF attacks can steal credentials | Enforce IMDSv2 with --metadata-options HttpTokens=required |
| Not tagging instances | Can’t tell what anything is for | Tag everything: Name, Environment, Owner |
Quick Reference
| Task | Command |
|---|---|
| Launch instance | aws ec2 run-instances --image-id AMI --instance-type TYPE --key-name KEY |
| List instances | aws ec2 describe-instances --filters Name=instance-state-name,Values=running |
| Stop instance | aws ec2 stop-instances --instance-ids ID |
| Start instance | aws ec2 start-instances --instance-ids ID |
| Terminate instance | aws ec2 terminate-instances --instance-ids ID |
| Get public IP | aws ec2 describe-instances --instance-ids ID --query 'Reservations[0].Instances[0].PublicIpAddress' |
Next → AMIs & Key Pairs