Amazon EC2 Essentials
Quick reference guide for AWS Elastic Compute Cloud (EC2).
What is Amazon EC2?
Amazon EC2 provides scalable virtual servers in the cloud:
Instance Types
General Purpose
T-Series (Burstable)
├── t4g: ARM-based, best value (up to 40% cost savings)
├── t3: Intel/AMD, balanced performance
└── t2: Previous generation
M-Series (Balanced)
├── m7g: ARM-based, latest generation
├── m6i: Intel, general purpose
└── m5: Previous generation Intel
Use Cases: Web servers, development environments, small databases
Compute Optimized
C-Series
├── c7g: ARM-based, highest performance
├── c6i: Intel, compute intensive
└── c5: Previous generation
Use Cases: Batch processing, high-performance web servers, gaming servers
Memory Optimized
R-Series (Memory Intensive)
├── r7g: ARM-based, large memory
├── r6i: Intel, memory optimized
└── r5: Previous generation
X-Series (Extreme Memory)
└── x2: Up to 4TB RAM
Use Cases: In-memory databases (Redis, SAP HANA), big data analytics
Storage Optimized
I-Series (High IOPS)
└── i4i: NVMe SSD storage
D-Series (Dense Storage)
└── d3: HDD-based, large capacity
Use Cases: NoSQL databases, data warehousing, log processing
Accelerated Computing
P-Series (GPU - ML/AI)
├── p4: NVIDIA A100 GPUs
└── p3: NVIDIA V100 GPUs
G-Series (GPU - Graphics)
└── g5: NVIDIA A10G GPUs
Use Cases: Machine learning, video processing, gaming
Launching Instances
AWS CLI - Launch Instance
# ========== Launch Basic Instance ==========
aws ec2 run-instances \
--image-id ami-12345678 \
--instance-type t3.micro \
--key-name my-key-pair \
--security-group-ids sg-12345678 \
--subnet-id subnet-12345678 \
--count 1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=MyInstance}]'
# ========== Launch with User Data ==========
aws ec2 run-instances \
--image-id ami-12345678 \
--instance-type t3.micro \
--key-name my-key-pair \
--security-group-ids sg-12345678 \
--subnet-id subnet-12345678 \
--user-data file://user-data.sh
# ========== Launch with Multiple Storage Volumes ==========
aws ec2 run-instances \
--image-id ami-12345678 \
--instance-type t3.medium \
--key-name my-key-pair \
--block-device-mappings '[
{
"DeviceName": "/dev/xvda",
"Ebs": {
"VolumeSize": 30,
"VolumeType": "gp3",
"DeleteOnTermination": true,
"Encrypted": true
}
},
{
"DeviceName": "/dev/sdf",
"Ebs": {
"VolumeSize": 100,
"VolumeType": "gp3",
"DeleteOnTermination": false
}
}
]'
User Data Script
#!/bin/bash
# This script runs on instance first launch
# Update packages
yum update -y
# Install web server
yum install -y httpd
# Start web server
systemctl start httpd
systemctl enable httpd
# Create simple webpage
echo "<h1>Hello from EC2!</h1>" > /var/www/html/index.html
# Install CloudWatch agent
wget https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
rpm -U ./amazon-cloudwatch-agent.rpm
Instance Management
Start, Stop, Reboot
# ========== Start Instance ==========
aws ec2 start-instances --instance-ids i-1234567890abcdef0
# ========== Stop Instance ==========
aws ec2 stop-instances --instance-ids i-1234567890abcdef0
# ========== Reboot Instance ==========
aws ec2 reboot-instances --instance-ids i-1234567890abcdef0
# ========== Terminate Instance ==========
aws ec2 terminate-instances --instance-ids i-1234567890abcdef0
Describe and List Instances
# ========== List All Instances ==========
aws ec2 describe-instances
# ========== List 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
# ========== Get Instance Details ==========
aws ec2 describe-instances \
--instance-ids i-1234567890abcdef0
# ========== List Instances by Tag ==========
aws ec2 describe-instances \
--filters "Name=tag:Environment,Values=production"
Modify Instance
# ========== Change Instance Type ==========
# 1. Stop the instance
aws ec2 stop-instances --instance-ids i-1234567890abcdef0
# 2. Wait for stopped state
aws ec2 wait instance-stopped --instance-ids i-1234567890abcdef0
# 3. Modify instance type
aws ec2 modify-instance-attribute \
--instance-id i-1234567890abcdef0 \
--instance-type "{\"Value\": \"t3.medium\"}"
# 4. Start the instance
aws ec2 start-instances --instance-ids i-1234567890abcdef0
# ========== Enable Termination Protection ==========
aws ec2 modify-instance-attribute \
--instance-id i-1234567890abcdef0 \
--disable-api-termination
# ========== Disable Termination Protection ==========
aws ec2 modify-instance-attribute \
--instance-id i-1234567890abcdef0 \
--no-disable-api-termination
Elastic Block Store (EBS)
Volume Types
| Type | Use Case | IOPS | Throughput | Size |
|---|---|---|---|---|
| gp3 | General purpose SSD | 3,000-16,000 | 125-1,000 MB/s | 1GB-16TB |
| gp2 | General purpose SSD (legacy) | 100-16,000 | Up to 250 MB/s | 1GB-16TB |
| io2 | High performance SSD | Up to 64,000 | Up to 1,000 MB/s | 4GB-16TB |
| st1 | Throughput optimized HDD | 500 | Up to 500 MB/s | 125GB-16TB |
| sc1 | Cold HDD (lowest cost) | 250 | Up to 250 MB/s | 125GB-16TB |
EBS Commands
# ========== Create Volume ==========
aws ec2 create-volume \
--volume-type gp3 \
--size 100 \
--availability-zone us-east-1a \
--encrypted \
--tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=MyVolume}]'
# ========== Attach Volume ==========
aws ec2 attach-volume \
--volume-id vol-1234567890abcdef0 \
--instance-id i-1234567890abcdef0 \
--device /dev/sdf
# ========== Detach Volume ==========
aws ec2 detach-volume \
--volume-id vol-1234567890abcdef0
# ========== Create Snapshot ==========
aws ec2 create-snapshot \
--volume-id vol-1234567890abcdef0 \
--description "Backup before upgrade" \
--tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=MySnapshot}]'
# ========== List Snapshots ==========
aws ec2 describe-snapshots --owner-ids self
# ========== Delete Snapshot ==========
aws ec2 delete-snapshot --snapshot-id snap-1234567890abcdef0
# ========== Modify Volume ==========
aws ec2 modify-volume \
--volume-id vol-1234567890abcdef0 \
--size 200 \
--volume-type gp3 \
--iops 4000
Mount EBS Volume (Linux)
# ========== Check Available Disks ==========
lsblk
# ========== Create Filesystem ==========
sudo mkfs -t ext4 /dev/xvdf
# ========== Mount Volume ==========
sudo mkdir /data
sudo mount /dev/xvdf /data
# ========== Persist Mount (Add to /etc/fstab) ==========
# Get UUID
sudo blkid /dev/xvdf
# Add to /etc/fstab
echo "UUID=your-uuid-here /data ext4 defaults,nofail 0 2" | sudo tee -a /etc/fstab
# ========== Verify ==========
df -h
AMI (Amazon Machine Image)
Create AMI
# ========== Create AMI from Instance ==========
aws ec2 create-image \
--instance-id i-1234567890abcdef0 \
--name "MyApp-v1.0-$(date +%Y%m%d)" \
--description "MyApp production image" \
--no-reboot
# ========== Create AMI with Reboot ==========
aws ec2 create-image \
--instance-id i-1234567890abcdef0 \
--name "MyApp-v1.0" \
--reboot
# ========== List AMIs ==========
aws ec2 describe-images --owners self
# ========== Deregister AMI ==========
aws ec2 deregister-image --image-id ami-1234567890abcdef0
# ========== Copy AMI to Another Region ==========
aws ec2 copy-image \
--source-region us-east-1 \
--source-image-id ami-1234567890abcdef0 \
--region us-west-2 \
--name "MyApp-v1.0-west"
Security Groups
Security Group Commands
# ========== Create Security Group ==========
aws ec2 create-security-group \
--group-name web-sg \
--description "Security group for web servers" \
--vpc-id vpc-1234567890abcdef0
# ========== Add Inbound Rules ==========
# Allow HTTP
aws ec2 authorize-security-group-ingress \
--group-id sg-1234567890abcdef0 \
--protocol tcp \
--port 80 \
--cidr 0.0.0.0/0
# Allow HTTPS
aws ec2 authorize-security-group-ingress \
--group-id sg-1234567890abcdef0 \
--protocol tcp \
--port 443 \
--cidr 0.0.0.0/0
# Allow SSH from specific IP
aws ec2 authorize-security-group-ingress \
--group-id sg-1234567890abcdef0 \
--protocol tcp \
--port 22 \
--cidr 203.0.113.0/24
# Allow traffic from another security group
aws ec2 authorize-security-group-ingress \
--group-id sg-1234567890abcdef0 \
--protocol tcp \
--port 3306 \
--source-group sg-0987654321fedcba0
# ========== Remove Inbound Rule ==========
aws ec2 revoke-security-group-ingress \
--group-id sg-1234567890abcdef0 \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0
# ========== List Security Groups ==========
aws ec2 describe-security-groups
# ========== Delete Security Group ==========
aws ec2 delete-security-group --group-id sg-1234567890abcdef0
Key Pairs
Key Pair Management
# ========== Create Key Pair ==========
aws ec2 create-key-pair \
--key-name my-key-pair \
--query 'KeyMaterial' \
--output text > my-key-pair.pem
# Set proper permissions
chmod 400 my-key-pair.pem
# ========== List Key Pairs ==========
aws ec2 describe-key-pairs
# ========== Delete Key Pair ==========
aws ec2 delete-key-pair --key-name my-key-pair
# ========== Import Existing Key ==========
aws ec2 import-key-pair \
--key-name imported-key \
--public-key-material fileb://~/.ssh/id_rsa.pub
Connect to Instance
# ========== SSH Connection ==========
ssh -i my-key-pair.pem ec2-user@54.123.45.67
# For Ubuntu
ssh -i my-key-pair.pem ubuntu@54.123.45.67
# ========== SSH with Port Forwarding ==========
ssh -i my-key-pair.pem -L 8080:localhost:80 ec2-user@54.123.45.67
# ========== SCP File Transfer ==========
# Upload file
scp -i my-key-pair.pem file.txt ec2-user@54.123.45.67:/home/ec2-user/
# Download file
scp -i my-key-pair.pem ec2-user@54.123.45.67:/home/ec2-user/file.txt ./
# ========== Session Manager (No SSH Key Needed) ==========
aws ssm start-session --target i-1234567890abcdef0
Elastic IP (Static IP)
Elastic IP Commands
# ========== Allocate Elastic IP ==========
aws ec2 allocate-address --domain vpc
# ========== Associate Elastic IP ==========
aws ec2 associate-address \
--instance-id i-1234567890abcdef0 \
--allocation-id eipalloc-12345678
# ========== Disassociate Elastic IP ==========
aws ec2 disassociate-address --association-id eipassoc-12345678
# ========== Release Elastic IP ==========
aws ec2 release-address --allocation-id eipalloc-12345678
# ========== List Elastic IPs ==========
aws ec2 describe-addresses
Auto Scaling
Launch Template
# ========== Create Launch Template ==========
aws ec2 create-launch-template \
--launch-template-name my-template \
--version-description "v1" \
--launch-template-data '{
"ImageId": "ami-12345678",
"InstanceType": "t3.micro",
"KeyName": "my-key-pair",
"SecurityGroupIds": ["sg-12345678"],
"UserData": "IyEvYmluL2Jhc2gKeXVtIHVwZGF0ZSAteQ==",
"TagSpecifications": [{
"ResourceType": "instance",
"Tags": [{
"Key": "Name",
"Value": "AutoScaled-Instance"
}]
}]
}'
# ========== Create Auto Scaling Group ==========
aws autoscaling create-auto-scaling-group \
--auto-scaling-group-name my-asg \
--launch-template "LaunchTemplateName=my-template,Version=1" \
--min-size 2 \
--max-size 10 \
--desired-capacity 2 \
--vpc-zone-identifier "subnet-12345,subnet-67890" \
--health-check-type ELB \
--health-check-grace-period 300 \
--tags "Key=Environment,Value=production,PropagateAtLaunch=true"
# ========== Update Auto Scaling Group ==========
aws autoscaling update-auto-scaling-group \
--auto-scaling-group-name my-asg \
--desired-capacity 5
# ========== Create Scaling Policy ==========
aws autoscaling put-scaling-policy \
--auto-scaling-group-name my-asg \
--policy-name scale-up \
--policy-type TargetTrackingScaling \
--target-tracking-configuration '{
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ASGAverageCPUUtilization"
},
"TargetValue": 70.0
}'
Load Balancer Integration
Application Load Balancer
# ========== Create Target Group ==========
aws elbv2 create-target-group \
--name my-targets \
--protocol HTTP \
--port 80 \
--vpc-id vpc-12345678 \
--health-check-path /health \
--health-check-interval-seconds 30
# ========== Register Instances ==========
aws elbv2 register-targets \
--target-group-arn arn:aws:elasticloadbalancing:region:account:targetgroup/my-targets \
--targets Id=i-1234567890abcdef0 Id=i-0987654321fedcba0
# ========== Create Load Balancer ==========
aws elbv2 create-load-balancer \
--name my-alb \
--subnets subnet-12345 subnet-67890 \
--security-groups sg-12345678
# ========== Create Listener ==========
aws elbv2 create-listener \
--load-balancer-arn arn:aws:elasticloadbalancing:region:account:loadbalancer/app/my-alb \
--protocol HTTP \
--port 80 \
--default-actions Type=forward,TargetGroupArn=arn:aws:elasticloadbalancing:region:account:targetgroup/my-targets
Monitoring and Logging
CloudWatch Metrics
# ========== Get CPU Utilization ==========
aws cloudwatch get-metric-statistics \
--namespace AWS/EC2 \
--metric-name CPUUtilization \
--dimensions Name=InstanceId,Value=i-1234567890abcdef0 \
--start-time 2024-01-01T00:00:00Z \
--end-time 2024-01-02T00:00:00Z \
--period 3600 \
--statistics Average
# ========== Create Alarm ==========
aws cloudwatch put-metric-alarm \
--alarm-name high-cpu \
--alarm-description "Alert when CPU exceeds 80%" \
--metric-name CPUUtilization \
--namespace AWS/EC2 \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 2 \
--dimensions Name=InstanceId,Value=i-1234567890abcdef0 \
--alarm-actions arn:aws:sns:region:account:my-topic
Instance Metadata
# ========== Get Instance ID ==========
curl http://169.254.169.254/latest/meta-data/instance-id
# ========== Get Instance Type ==========
curl http://169.254.169.254/latest/meta-data/instance-type
# ========== Get Public IP ==========
curl http://169.254.169.254/latest/meta-data/public-ipv4
# ========== Get User Data ==========
curl http://169.254.169.254/latest/user-data
# ========== IMDSv2 (More Secure) ==========
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
Pricing Models
On-Demand Instances
Pay per hour/second with no commitment
├── Best for: Short-term, unpredictable workloads
├── Flexibility: Highest
└── Cost: Highest per hour
Reserved Instances
1 or 3 year commitment for significant discount (up to 72%)
├── Standard RI: Fixed instance type and region
├── Convertible RI: Can change instance type
└── Scheduled RI: Run on specific schedule
Savings Plans
Flexible pricing model (1 or 3 year commitment)
├── Compute Savings Plans: Up to 66% savings
├── EC2 Instance Savings Plans: Up to 72% savings
└── Flexibility: Can change instance type, OS, region
Spot Instances
Up to 90% discount, can be interrupted
├── Best for: Fault-tolerant workloads
├── Use cases: Batch processing, data analysis
└── Risk: Can be terminated with 2-minute warning
Best Practices
Security
Performance
Cost Optimization
Reliability
Troubleshooting
Common Issues
# ========== Cannot Connect via SSH ==========
# Check security group allows port 22
# Verify key pair permissions (chmod 400)
# Check instance is running
# Verify public IP/DNS
# ========== Instance Status Checks Failing ==========
# System status check: AWS infrastructure issue
# Instance status check: OS/application issue
aws ec2 describe-instance-status --instance-ids i-1234567890abcdef0
# ========== Disk Space Full ==========
df -h
# Clean up logs, delete unused files
# Increase EBS volume size
# ========== High CPU Usage ==========
top
# Identify processes consuming CPU
# Optimize application or upgrade instance type
# ========== View System Logs ==========
aws ec2 get-console-output --instance-id i-1234567890abcdef0