AWS / Guide 7
EC2 instances
Instance types, EBS volumes, availability, patching with Systems Manager, monitoring agents and saving money on EC2.
EC2 is where most AWS operations work still happens, and usually where most of the bill is. This guide covers the day-to-day: knowing what's running, choosing instance types and volumes, availability, patching, monitoring, and spending less.
Know what you have
Start with an inventory across every region, not just the one the console opened in. Get-AwsEC2Inventory.ps1 lists every instance with type, state, platform, IPs, volumes, IMDS setting, and the owner and cost tags. Quick checks from the shell:
# Running instances in this region, with their Name tag
(Get-EC2Instance -Filter @{ Name = 'instance-state-name'; Values = 'running' }).Instances |
Select-Object InstanceId, InstanceType, @{n='Name';e={ ($_.Tags | Where-Object Key -eq 'Name').Value }},
PrivateIpAddress, LaunchTime
# Instances stopped for more than 30 days still pay for their EBS volumes (and any Elastic IPs)
(Get-EC2Instance -Filter @{ Name = 'instance-state-name'; Values = 'stopped' }).Instances |
Where-Object { $_.StateTransitionReason -match '\((\d{4}-\d{2}-\d{2})' -and [datetime]$Matches[1] -lt (Get-Date).AddDays(-30) } |
Select-Object InstanceId, InstanceType, StateTransitionReason
Choose the instance type
An instance type name reads as family, generation, options and size: m7g.large is general purpose (m), 7th generation, Graviton (g), large.
| Family | Good for |
|---|---|
t (burstable) | Small, spiky workloads: jump boxes, dev servers, low-traffic sites. Watch CPU credits: in unlimited mode, sustained load costs extra |
m (general purpose) | Most application servers |
c (compute) | CPU-heavy work: builds, batch, web front ends at scale |
r, x (memory) | Databases, caches, SQL Server, SAP |
i, d (storage) | Local NVMe for very fast temporary data |
g, p, inf, trn | Graphics and machine learning |
- Use the current generation. Newer generations usually cost the same or less for more performance. Moving from
m5tom7iis often a straight win. - Consider Graviton (the
gsuffix, Arm-based) for Linux workloads: typically around 20% cheaper for similar or better performance. Most open-source stacks, containers and managed runtimes work unchanged. - Rightsize with data. AWS Compute Optimizer recommends instance types from 14 days of CloudWatch metrics (longer with enhanced metrics). Install the CloudWatch agent so it can see memory, not just CPU.
EBS volumes
| Type | Use for |
|---|---|
| gp3 | The default for almost everything. 3,000 IOPS and 125 MB/s included at any size; buy more of either separately |
| gp2 | Older default; performance tied to size. Migrate to gp3, usually about 20% cheaper, with no downtime |
| io2 Block Express | Databases needing guaranteed high IOPS and 99.999% durability |
| st1, sc1 | Large sequential data (logs, big data) at low cost; can't be boot volumes |
# Convert every gp2 volume in this region to gp3 (online; runs in the background)
Get-EC2Volume -Filter @{ Name = 'volume-type'; Values = 'gp2' } | ForEach-Object {
Edit-EC2Volume -VolumeId $_.VolumeId -VolumeType gp3 -WhatIf
}
Remove -WhatIf to run it. Also: turn on EBS encryption by default (Guide 6), set Delete on termination for volumes that shouldn't outlive the instance, and delete the unattached volumes and old snapshots Find-AwsOrphanedResources.ps1 finds.
Availability
- A single instance lives in one Availability Zone. An AZ outage takes it down. For anything that must stay up, run at least two instances in different AZs behind a load balancer.
- Use Auto Scaling groups, even with a fixed size. A group of two with health checks replaces a failed instance automatically, across AZs.
- Launch templates describe how an instance is built (AMI, type, security groups, IMDSv2, tags, user data). Version them and use them everywhere, instead of hand-launching.
- Automatic recovery is on by default for most current instance types: if the underlying host fails, the instance restarts on new hardware with the same ID, IPs and volumes.
- Stateful servers that can't be load-balanced (a legacy app server, SQL Server on EC2) need backups (Guide 8) and, for fast failover, a replica or AWS Elastic Disaster Recovery.
Patching with Systems Manager
AWS Systems Manager manages instances through the SSM Agent: patching, inventory, running commands and shell access, without SSH or RDP. Every instance should be a managed node, which needs the agent, an instance profile with AmazonSSMManagedInstanceCore (or Default Host Management Configuration for the whole account), and a route to Systems Manager.
- Quick Setup > Patch Manager creates a patch policy for the whole organisation: scan daily, install weekly in a maintenance window, with separate baselines for production and non-production.
- Patch baselines set which updates are approved and how long after release (for example, critical and security updates after 7 days).
- Patch groups (the
PatchGrouptag) or tag-based targets decide which instances follow which schedule, so the two halves of a pair aren't patched at the same time. - Replace rather than patch where you can: instances in an Auto Scaling group can be refreshed from a newly patched AMI built by EC2 Image Builder.
# Instances Systems Manager can't manage (agent missing, no role, or no route)
$managed = (Get-SSMInstanceInformation).InstanceId
(Get-EC2Instance -Filter @{ Name = 'instance-state-name'; Values = 'running' }).Instances |
Where-Object { $_.InstanceId -notin $managed } | Select-Object InstanceId, @{n='Name';e={ ($_.Tags | Where-Object Key -eq 'Name').Value }}
# Patch compliance summary (the API takes up to 50 instance IDs per call)
Get-SSMInstancePatchStateList -InstanceId ($managed | Select-Object -First 50) | Select-Object InstanceId, InstalledCount, MissingCount, FailedCount, OperationEndTime
Monitoring agents
EC2 sends CPU, network and disk operations to CloudWatch without an agent, but not memory or disk space: those need the CloudWatch agent. Install and configure it through Systems Manager (the AWS-ConfigureAWSPackage document and a configuration stored in Parameter Store) so every instance gets the same setup. Collect memory and disk-used percentages, and the Windows event logs or Linux log files you actually troubleshoot with. Guide 9 covers the alarms to set on them.
Save money on EC2
- Stop non-production instances out of hours. A server running 12 hours on weekdays costs about 36% of one running all month.
Invoke-AwsEC2PowerSchedule.ps1starts and stops instances by tag. Stopped instances still pay for EBS. - Rightsize, then commit. Act on Compute Optimizer first, then cover the steady baseline with Savings Plans (Guide 10).
- Spot Instances cost up to 90% less for work that can be interrupted: CI runners, batch, stateless workers in an Auto Scaling group with mixed instance types.
- Release unused Elastic IPs and avoid public IPv4 addresses where you can: every public IPv4 address is charged by the hour.
- Windows and SQL Server licences are a large part of the price. Check whether bring-your-own-licence or a smaller SQL edition applies.
Troubleshooting without SSH or RDP
- Status checks: a failed system check is AWS's problem (stop and start moves the instance to new hardware); a failed instance check is the OS's (boot failure, full disk, bad network config).
- Get system log and instance screenshot (Actions > Monitor and troubleshoot) show the boot output and the console screen.
- EC2 Serial Console gives a text console to fix a broken network or boot configuration. It's off by default; turn it on per account only when needed.
- Session Manager and Run Command work as long as the SSM Agent can reach Systems Manager, even when SSH is broken or blocked.
- AWSSupport-ExecuteEC2Rescue (a Systems Manager Automation runbook) fixes common Windows and Linux boot and connectivity problems by attaching the volume to a helper instance.
Examples to try
From aws.ravindran.in: EC2 and user data, EC2 Auto Scaling, EBS (including resizing), and Application Load Balancer.