Amazon Elastic Compute Cloud (EC2) provides resizable virtual servers in the cloud. It's the foundational compute service for running applications, from simple web servers to complex distributed systems.
Core Concepts
- Instance — a virtual server with CPU, memory, storage, and networking
- AMI — Amazon Machine Image, a template for launching instances
- Instance type — hardware configuration (t3.micro, m5.xlarge, etc.)
- Security group — virtual firewall controlling inbound/outbound traffic
- Key pair — SSH authentication for Linux instances
- EBS — Elastic Block Store, persistent block storage volumes
Launching Instances
bash
# Launch a basic EC2 instance
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.micro \
--key-name my-key-pair \
--security-group-ids sg-0123456789abcdef0 \
--subnet-id subnet-0123456789abcdef0 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=web-server-1}]' \
--count 1
bash
# Launch with user data script for bootstrapping
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.small \
--key-name my-key-pair \
--security-group-ids sg-0123456789abcdef0 \
--user-data file://setup.sh \
--iam-instance-profile Name=ec2-app-role \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=app-server},{Key=Env,Value=prod}]'
bash
# setup.sh — bootstrap script for EC2 instance
#!/bin/bash
yum update -y
yum install -y docker
systemctl start docker
systemctl enable docker
docker pull myapp:latest
docker run -d -p 80:8080 myapp:latest
Instance Management
bash
# List running instances with key details
aws ec2 describe-instances \
--filters "Name=instance-state-name,Values=running" \
--query 'Reservations[].Instances[].[InstanceId,InstanceType,PublicIpAddress,Tags[?Key==`Name`].Value|[0]]' \
--output table
bash
# Stop, start, terminate instances
aws ec2 stop-instances --instance-ids i-0123456789abcdef0
aws ec2 start-instances --instance-ids i-0123456789abcdef0
aws ec2 terminate-instances --instance-ids i-0123456789abcdef0
bash
# Resize an instance (must be stopped first)
aws ec2 stop-instances --instance-ids i-0123456789abcdef0
aws ec2 modify-instance-attribute \
--instance-id i-0123456789abcdef0 \
--instance-type '{"Value": "t3.large"}'
aws ec2 start-instances --instance-ids i-0123456789abcdef0
Security Groups
bash
# Create a security group for a web server
aws ec2 create-security-group \
--group-name web-sg \
--description "Allow HTTP, HTTPS, SSH" \
--vpc-id vpc-0123456789abcdef0
bash
# Add inbound rules
aws ec2 authorize-security-group-ingress \
--group-id sg-0123456789abcdef0 \
--ip-permissions \
'IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges=[{CidrIp=0.0.0.0/0}]' \
'IpProtocol=tcp,FromPort=443,ToPort=443,IpRanges=[{CidrIp=0.0.0.0/0}]' \
'IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=203.0.113.0/24,Description=Office}]'
AMIs
bash
# Create an AMI from a running instance
aws ec2 create-image \
--instance-id i-0123456789abcdef0 \
--name "app-server-v1.2.0-$(date +%Y%m%d)" \
--description "App server with latest patches" \
--no-reboot
bash
# List your AMIs
aws ec2 describe-images --owners self \
--query 'Images[*].[ImageId,Name,CreationDate]' --output table
bash
# Deregister old AMI and delete snapshot
aws ec2 deregister-image --image-id ami-0123456789abcdef0
aws ec2 delete-snapshot --snapshot-id snap-0123456789abcdef0
EBS Volumes
bash
# Create and attach an EBS volume
aws ec2 create-volume \
--size 100 \
--volume-type gp3 \
--availability-zone us-east-1a \
--iops 3000 \
--throughput 125 \
--tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=data-vol}]'
bash
# Attach volume to instance
aws ec2 attach-volume \
--volume-id vol-0123456789abcdef0 \
--instance-id i-0123456789abcdef0 \
--device /dev/xvdf
bash
# Create a snapshot for backup
aws ec2 create-snapshot \
--volume-id vol-0123456789abcdef0 \
--description "Daily backup $(date +%Y-%m-%d)" \
--tag-specifications 'ResourceType=snapshot,Tags=[{Key=Name,Value=daily-backup}]'
Auto Scaling
bash
# Create a launch template
aws ec2 create-launch-template \
--launch-template-name app-server-template \
--launch-template-data '{
"ImageId": "ami-0c55b159cbfafe1f0",
"InstanceType": "t3.medium",
"SecurityGroupIds": ["sg-0123456789abcdef0"],
"KeyName": "my-key-pair",
"IamInstanceProfile": {"Name": "ec2-app-role"},
"UserData": "'$(base64 -w0 setup.sh)'"
}'
bash
# Create an auto-scaling group
aws autoscaling create-auto-scaling-group \
--auto-scaling-group-name app-asg \
--launch-template LaunchTemplateName=app-server-template,Version='$Latest' \
--min-size 2 \
--max-size 10 \
--desired-capacity 2 \
--vpc-zone-identifier "subnet-aaa,subnet-bbb" \
--target-group-arns "arn:aws:elasticloadbalancing:us-east-1:123456789:targetgroup/app-tg/abc123" \
--health-check-type ELB \
--health-check-grace-period 300
bash
# Create scaling policy based on CPU
aws autoscaling put-scaling-policy \
--auto-scaling-group-name app-asg \
--policy-name cpu-scale-out \
--policy-type TargetTrackingScaling \
--target-tracking-configuration '{
"PredefinedMetricSpecification": {"PredefinedMetricType": "ASGAverageCPUUtilization"},
"TargetValue": 70.0,
"ScaleInCooldown": 300,
"ScaleOutCooldown": 60
}'
Spot Instances
bash
# Request spot instances for cost savings (up to 90% off)
aws ec2 request-spot-instances \
--instance-count 3 \
--type "one-time" \
--launch-specification '{
"ImageId": "ami-0c55b159cbfafe1f0",
"InstanceType": "c5.xlarge",
"SecurityGroupIds": ["sg-0123456789abcdef0"],
"SubnetId": "subnet-0123456789abcdef0"
}'
Best Practices
- Use launch templates over launch configurations for versioning
- Place instances in private subnets; use a bastion host or SSM for access
- Enable detailed monitoring for production workloads
- Use auto-scaling with target tracking for hands-off scaling
- Tag everything for cost allocation and resource management
- Use spot instances for fault-tolerant, flexible workloads
- Rotate AMIs regularly with latest security patches