EBS volumes: gp3 vs io2, snapshots and resizing without downtime

Every EC2 server stores its operating system and data on network disks called EBS volumes. This lesson on AWS EBS volumes explains the volume types, how snapshots work and how to grow a disk while the server keeps running, which is one of the most common requests a cloud engineer gets.

You’ll add a 10 GiB gp3 data disk to a private server, put a file system on it, snapshot it, grow it to 20 GiB live, and then make the two mistakes that catch people out: changing a volume twice in a row and restoring it in the wrong zone.

TimeYou needBy the end you can
60 minutes (server and endpoints running for under an hour)saat-vpc, saat-ec2-ssm-profile and saat-endpoint-sg from Lesson 13, your laptop signed in with aws login --profile saat-admin and the Session Manager plugin. Cost: about USD 0.10 if you clean up within an hour.Choose between gp3, gp2 and io2, attach and mount a new volume, take and restore snapshots, resize a live volume, and avoid zone and rate-limit errors.

What it is, in one line

AWS EBS volumes are network disks for EC2 that live in one Availability Zone, can be resized live and backed up with snapshots.

In Simple Words

External hard disks in a hotel room

Think of the server as a hotel room and EBS volumes as external hard disks you plug into it. You can plug in more disks, swap them to another room on the same floor, or ask for a bigger disk without leaving the room.

A snapshot is a photocopy of a disk stored in the hotel’s safe. The first copy takes a while; after that, only the pages that changed are copied. If a disk breaks, you make a new disk from the photocopy.

One rule: a disk only plugs into rooms on its own floor. That floor is the Availability Zone.

Engineer's View

How EBS really works

An EBS volume is block storage replicated inside one Availability Zone. It attaches to one instance at a time (Multi-Attach for io1/io2 is the exception) in the same zone. On Nitro instances, volumes appear as NVMe devices: the /dev/sdf you ask for usually shows up as /dev/nvme1n1.

gp3 gives 3,000 IOPS and 125 MiB/s whatever its size, and you can buy more, up to 80,000 IOPS and 2,000 MiB/s, on volumes up to 64 TiB. gp2 ties performance to size (3 IOPS per GiB, minimum 100) and bursts on credits. io2 Block Express is for busy databases: up to 256,000 IOPS with 99.999% durability. HDD types (st1, sc1) suit large sequential reads, never boot disks.

Elastic Volumes lets you change size, type, IOPS and throughput on a live volume. After a change, wait at least 6 hours before changing the same volume again. Growing the volume doesn’t grow the file system; you do that inside the OS (xfs_growfs or resize2fs on Linux, Disk Management or Resize-Partition on Windows).

Volumes can’t shrink.

Snapshots are point-in-time, incremental copies stored in S3 behind the scenes and kept per Region. You can create a new volume from a snapshot in any zone of that Region, copy snapshots to other Regions, and protect them from deletion with Recycle Bin rules. Data volumes you add yourself are not deleted when the instance terminates, unless you set DeleteOnTermination.

How it works, step by step

This is the life of a data disk, from creation to resize.

1Create the volume in the server’s zone

Same zone as the instance (ap-south-1a), encrypted, tagged.

AWS EBS volumes: gp3, gp2, io2 Block Express and HDD types compared

2Attach, format, mount

Attach it, create a file system once, mount it and add it to /etc/fstab by UUID with nofail, so a missing disk never stops the server booting.

3Snapshot before you change anything

A snapshot takes seconds to start and runs in the background. It is your undo button.

4Grow it while it runs

Two steps, one in AWS and one in the operating system.

AWS EBS volumes: growing a disk while the server runs

The 6-hour rule is why experienced engineers change size, type, IOPS and throughput in one modify-volume call, never one after another.

✅ Checkpoint: You can say what gp3 gives you without extra cost, why a volume must be in the same zone as its server, and why you run xfs_growfs after modify-volume.

Hands-on lab: AWS EBS volumes, snapshot and live resize

Start as usual. In step 1 you also save two small helper scripts for the Session Manager endpoints from Lesson 13, so later lessons can switch them on and off with one line.

cd C:\aws-lab
aws login --profile saat-admin
$env:AWS_PROFILE = 'saat-admin'
$env:Path += ';C:\Program Files\Amazon\SessionManagerPlugin\bin'
$v = Get-Content C:\aws-lab\saat-vpc.json | ConvertFrom-Json

1Save the endpoint helper scripts and start the endpoints

Paste this whole block:

@'
$v = Get-Content C:\aws-lab\saat-vpc.json | ConvertFrom-Json
$running = aws ec2 describe-vpc-endpoints --filters "Name=tag:lesson,Values=endpoints" "Name=vpc-endpoint-state,Values=pending,available" --query "VpcEndpoints[].VpcEndpointId" --output text
if ($running) { $running -split '\s+' | Set-Content C:\aws-lab\ssm-endpoints.txt; "SSM endpoints already running"; return }
$eps = foreach ($svc in 'ssm','ssmmessages','ec2messages') {
  aws ec2 create-vpc-endpoint --vpc-id $v.VpcId --vpc-endpoint-type Interface --service-name "com.amazonaws.ap-south-1.$svc" --subnet-ids $v.PrivateA --security-group-ids $v.EndpointSg --private-dns-enabled --tag-specifications "ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=saat-$svc-endpoint},{Key=course,Value=saatvedha-aws},{Key=lesson,Value=endpoints}]" --query VpcEndpoint.VpcEndpointId --output text
}
$eps | Set-Content C:\aws-lab\ssm-endpoints.txt
do { Start-Sleep 20; $s = aws ec2 describe-vpc-endpoints --vpc-endpoint-ids $eps --query "VpcEndpoints[].State" --output text } until (($s -split '\s+' | Where-Object { $_ -ne 'available' }).Count -eq 0)
"SSM endpoints ready"
'@ | Set-Content C:\aws-lab\Start-SsmEndpoints.ps1

@'
if (-not (Test-Path C:\aws-lab\ssm-endpoints.txt)) { "SSM endpoints already deleted"; return }
$eps = Get-Content C:\aws-lab\ssm-endpoints.txt
aws ec2 delete-vpc-endpoints --vpc-endpoint-ids $eps | Out-Null
Remove-Item C:\aws-lab\ssm-endpoints.txt
"SSM endpoints deleted"
'@ | Set-Content C:\aws-lab\Stop-SsmEndpoints.ps1

.\Start-SsmEndpoints.ps1

After two to three minutes you should see:

SSM endpoints ready

2Launch data01 and wait for Session Manager

Paste this whole block:

$ami = aws ssm get-parameter --name /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64 --query Parameter.Value --output text
$id = aws ec2 run-instances --image-id $ami --instance-type t3.micro --subnet-id $v.PrivateA --security-group-ids $v.AppSg --iam-instance-profile Name=saat-ec2-ssm-profile --metadata-options HttpTokens=required --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=data01},{Key=course,Value=saatvedha-aws},{Key=lesson,Value=14}]' 'ResourceType=volume,Tags=[{Key=course,Value=saatvedha-aws},{Key=lesson,Value=14}]' --query "Instances[0].InstanceId" --output text
do { Start-Sleep 20; $ping = aws ssm describe-instance-information --filters "Key=InstanceIds,Values=$id" --query "InstanceInformationList[0].PingStatus" --output text } until ($ping -eq 'Online')
"data01 $id is $ping"

3Create and attach a 10 GiB gp3 volume

Paste this whole block:

$vol = aws ec2 create-volume --availability-zone ap-south-1a --size 10 --volume-type gp3 --encrypted --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=data01-data},{Key=course,Value=saatvedha-aws},{Key=lesson,Value=14}]' --query VolumeId --output text
aws ec2 wait volume-available --volume-ids $vol
aws ec2 attach-volume --volume-id $vol --instance-id $id --device /dev/sdf --query State --output text
aws ec2 wait volume-in-use --volume-ids $vol
aws ec2 describe-volumes --volume-ids $vol --query "Volumes[0].[VolumeType,Size,Iops,Throughput,Encrypted]" --output text

You should see something like this:

attaching
gp3     10      3000    125     True

4Format and mount it inside the server

Open a session with aws ssm start-session --target $id, then type this at the sh-5.2$ prompt:

lsblk -l -o NAME,SIZE,MOUNTPOINTS
sudo mkfs -t xfs /dev/nvme1n1
sudo mkdir /data
sudo mount /dev/nvme1n1 /data
echo "UUID=$(sudo blkid -s UUID -o value /dev/nvme1n1) /data xfs defaults,nofail 0 2" | sudo tee -a /etc/fstab
echo "order 1001" | sudo tee /data/orders.txt
df -h /data | tail -1

The last line should show something like this:

/dev/nvme1n1     10G  104M  9.9G   2% /data

Check that nvme1n1 is the 10G disk in the lsblk list before you format it. Formatting the wrong device destroys its data. Leave the session open.

5Take a snapshot

Back in PowerShell, run this:

$snap = aws ec2 create-snapshot --volume-id $vol --description "data01-data before resize" --tag-specifications 'ResourceType=snapshot,Tags=[{Key=course,Value=saatvedha-aws},{Key=lesson,Value=14}]' --query SnapshotId --output text
aws ec2 wait snapshot-completed --snapshot-ids $snap
aws ec2 describe-snapshots --snapshot-ids $snap --query "Snapshots[0].[SnapshotId,State,VolumeSize]" --output text

You should see something like this:

snap-0c1d2e3f4a5b60718   completed       10

6Grow the volume to 20 GiB while it runs

Run this:

aws ec2 modify-volume --volume-id $vol --size 20 --query "VolumeModification.ModificationState" --output text
do { Start-Sleep 10; $st = aws ec2 describe-volumes-modifications --volume-ids $vol --query "VolumesModifications[0].ModificationState" --output text } until ($st -in 'optimizing','completed')
$st

You should see this:

modifying
optimizing

In the session, grow the file system:

lsblk -l -o NAME,SIZE,MOUNTPOINTS
df -h /data | tail -1
sudo xfs_growfs /data | tail -1
df -h /data | tail -1
cat /data/orders.txt

You should see something like this:

NAME         SIZE MOUNTPOINTS
nvme0n1        8G
nvme0n1p1      8G /
nvme0n1p127    1M
nvme0n1p128   10M /boot/efi
nvme1n1       20G /data
/dev/nvme1n1     10G  104M  9.9G   2% /data
data blocks changed from 2621440 to 5242880
/dev/nvme1n1     20G  176M   20G   1% /data
order 1001

The disk showed 20G as soon as AWS reached optimizing, but the file system stayed at 10G until xfs_growfs. Your file was never touched.

AWS EBS volumes lab: the 20 GiB disk and xfs_growfs
The grown disk inside data01. Something like this; the block counts are exact for 10 and 20 GiB XFS.

7Compare gp2 and gp3 for different sizes

Back in PowerShell, paste this whole block:

foreach ($gib in 20, 100, 1000, 4000) {
  [pscustomobject]@{ SizeGiB = $gib; Gp2Iops = [math]::Max(100, [math]::Min(16000, 3 * $gib)); Gp3IncludedIops = 3000 }
} | Format-Table

You should see this:

SizeGiB Gp2Iops Gp3IncludedIops
------- ------- ---------------
     20     100            3000
    100     300            3000
   1000    3000            3000
   4000   12000            3000

Small gp2 disks are slow unless they burst. gp3 gives 3,000 IOPS at any size, and you add more only when a big disk needs it.

✅ Checkpoint: data01 has a 20 GiB gp3 data disk mounted at /data with orders.txt intact, and a completed snapshot from before the resize. Keep everything for the break lab.

Break It, Then Fix It

Two EBS rules that the console doesn’t warn you about until you break them.

1Break it: change the volume again straight away

Ask for more IOPS on the volume you just resized:

aws ec2 modify-volume --volume-id $vol --iops 4000

You’ll get this error (something like this):

An error occurred (VolumeModificationRateExceeded) when calling the ModifyVolume operation: You've reached the maximum modification rate per volume limit. Wait at least 6 hours between modifications per EBS volume.
AWS EBS volumes break lab: modification rate limit and zone mismatch
Both EBS errors, something like this.

Fix: there isn’t one for the next 6 hours. Plan changes together: --size 20 --iops 4000 --throughput 250 in one call. In an emergency, create a new volume from a snapshot with the settings you need and swap it in.

2Break it: restore a snapshot in the wrong zone

Create a volume from the snapshot in ap-south-1b and try to attach it to data01 (in ap-south-1a):

$restored = aws ec2 create-volume --availability-zone ap-south-1b --snapshot-id $snap --volume-type gp3 --tag-specifications 'ResourceType=volume,Tags=[{Key=course,Value=saatvedha-aws},{Key=lesson,Value=14}]' --query VolumeId --output text
aws ec2 wait volume-available --volume-ids $restored
aws ec2 attach-volume --volume-id $restored --instance-id $id --device /dev/sdg

You’ll get this error (something like this):

An error occurred (InvalidVolume.ZoneMismatch) when calling the AttachVolume operation: The volume 'vol-0b1c2d3e4f5a60718' is not in the same availability zone as instance 'i-0a9b8c7d6e5f40312'

Snapshots belong to the Region, volumes belong to a zone. Fix: create the volume in the instance’s zone:

aws ec2 delete-volume --volume-id $restored
$restored = aws ec2 create-volume --availability-zone ap-south-1a --snapshot-id $snap --volume-type gp3 --tag-specifications 'ResourceType=volume,Tags=[{Key=course,Value=saatvedha-aws},{Key=lesson,Value=14}]' --query VolumeId --output text
aws ec2 wait volume-available --volume-ids $restored
aws ec2 attach-volume --volume-id $restored --instance-id $id --device /dev/sdg --query State --output text

In the session, mount the copy read-only. The nouuid option is needed because it has the same XFS ID as /data:

sudo mkdir /restore
sudo mount -o ro,nouuid /dev/nvme2n1 /restore
cat /restore/orders.txt

You should see this:

order 1001

3Clean up

Type exit in the session, then paste this whole block in PowerShell:

aws ec2 terminate-instances --instance-ids $id | Out-Null
aws ec2 wait instance-terminated --instance-ids $id
aws ec2 describe-volumes --volume-ids $vol $restored --query "Volumes[].[VolumeId,State]" --output text
aws ec2 delete-volume --volume-id $vol
aws ec2 delete-volume --volume-id $restored
aws ec2 delete-snapshot --snapshot-id $snap
.\Stop-SsmEndpoints.ps1
.\Find-LabResources.ps1

The describe line shows something like this before you delete them:

vol-0a1b2c3d4e5f60718   available
vol-0b1c2d3e4f5a60718   available

Both data volumes survived the termination, because volumes you add yourself are kept unless DeleteOnTermination is set. This is exactly how forgotten volumes pile up on real bills.

✅ Checkpoint: You met the 6-hour rule and the zone rule, read the copy from the snapshot, and deleted the instance, both volumes, the snapshot and the endpoints.

This happened at work

1,200 disks nobody owned

A gaming company’s AWS bill kept growing even though the number of servers stayed the same. A cost review found about 1,200 EBS volumes in the available state, attached to nothing. Most were data disks from test servers that had been terminated over three years; terminating them had left the extra volumes behind.

On top of that, a script took daily snapshots of every volume and never deleted any. There were more than 200,000 snapshots. Together the orphaned volumes and snapshots cost more than all the running servers.

The team tagged everything with an owner, deleted unattached volumes after a two-week notice (with a final snapshot of anything unclear), and moved snapshot schedules to Amazon Data Lifecycle Manager with 7 daily and 4 weekly copies kept. An AWS Config rule now flags unattached volumes older than 14 days, and a Recycle Bin rule keeps deleted snapshots for 7 days in case someone needs one back.

Common mistakes and troubleshooting

MistakeWhat happensWhat to do
Creating a volume in a different zone from the serverInvalidVolume.ZoneMismatchCreate it in the instance’s zone; snapshots can restore to any zone
Changing size, then IOPS, then throughputVolumeModificationRateExceeded for 6 hoursChange everything in one modify-volume call
Growing the volume but not the file systemdf still shows the old sizexfs_growfs or resize2fs (growpart first if partitioned)
Mounting by device name in fstabServer may not boot when names changeMount by UUID with nofail
Formatting the wrong deviceData destroyedCheck lsblk sizes and names before mkfs
Forgetting added volumes after terminateUnattached volumes keep chargingDelete them or set DeleteOnTermination
Keeping gp2 out of habitSlow small disks, burst credit surprisesUse gp3; migrate gp2 with modify-volume

Interview questions

Click a question to open it. Each one is written the way an interviewer would ask it. Under it you will see why they ask it and one way you could answer, in your own words.

Fresher level

1. How would you explain an EBS volume to someone who has only used a laptop hard disk?

Why they ask this: They want to check basic storage knowledge. Knowing that EBS is tied to one zone explains many later design choices.

How you might answer: I’d say it’s like a disk for your EC2 instance, but it lives on the network, not inside the server. It’s copied within one Availability Zone, and it keeps its data even if the instance goes away.

It can only attach to an instance in the same zone.

2. You find a lot of old gp2 volumes in an account. Why might you move them to gp3?

Why they ask this: They want to see practical cost and performance awareness. This is one of the easiest savings in many accounts.

How you might answer: On gp2, performance depends on size, 3 IOPS per GiB, and small volumes burst on credits. gp3 gives 3,000 IOPS and 125 MiB/s at any size, and I can buy more of each separately.

So gp3 is usually cheaper and more predictable.

3. Can you explain in simple words what an EBS snapshot is?

Why they ask this: They want to check backup basics. Snapshots are behind most EC2 backups and restores.

How you might answer: A snapshot is a point-in-time copy of a volume, and it’s incremental, so only changed blocks are stored after the first one. AWS stores it at the Region level.

I can create a new volume from it in any zone of that Region, or copy it to another Region.

2–5 years experience

4. A Linux server is running out of disk space and you can’t take it down. How would you add space?

Why they ask this: They want to see a daily operations task done safely. Taking a snapshot first shows good habits.

How you might answer: First I’d take a snapshot. Then I’d use modify-volume to set the new size and wait for the volume to reach the optimizing state.

After that I grow the partition with growpart if needed, and the file system with xfs_growfs or resize2fs. No reboot is needed.

5. A database team asks for io2 volumes. When would you agree, and when would you push back?

Why they ask this: They want to see judgement when choosing storage for databases. io2 is often requested when gp3 would do.

How you might answer: I’d agree when the database needs very high or very consistent IOPS beyond what gp3 can give, or needs 99.999% durability or Multi-Attach.

Otherwise I’d suggest gp3 with extra provisioned IOPS, because many workloads run fine on it and it’s cheaper.

6. You restored a volume from a snapshot, and the app is slow for the first hour. Why does that happen?

Why they ask this: They want to see whether you understand how snapshot restores work inside. It matters a lot during an incident.

How you might answer: Blocks are loaded from snapshot storage the first time they’re read, which is called lazy loading. So the first reads are slow.

For restores where speed matters, I’d use Fast Snapshot Restore, or read every block once with something like fio or dd before the app goes live.

Senior level

7. You’re asked to design EBS backup and retention for 300 servers. What would you put in place?

Why they ask this: They want to see operational design at scale. Backups that are never tested, or snapshots that are never cleaned, are both common problems.

How you might answer: I’d use tag-based policies in Amazon Data Lifecycle Manager or AWS Backup, with daily and weekly retention and cross-Region copies for disaster recovery. Recycle Bin rules protect against accidental deletion, and everything is encrypted with KMS.

We’d run restore tests regularly. Reports on unattached volumes and old snapshots keep the cost under control.

8. The DBA says a database server has high disk latency. How would you check whether EBS is the problem?

Why they ask this: They want to see performance troubleshooting. Senior engineers know the instance can be the bottleneck, not only the volume.

How you might answer: I’d look at the volume’s CloudWatch metrics, like VolumeReadOps, VolumeWriteOps, VolumeQueueLength and the latency metrics. I’d also check the instance’s EBSIOBalance% and EBSByteBalance% to see if it’s hitting instance-level limits.

Once I know whether the volume or the instance type is the bottleneck, I’d raise gp3 IOPS and throughput, move to io2, or choose an instance with more EBS bandwidth.

Quick quiz

Q1. How many IOPS does a gp3 volume include at any size?

  1. 100
  2. 1,000
  3. 3,000
  4. 16,000
Show answer

C — gp3 includes 3,000 IOPS and 125 MiB/s whatever its size.

Q2. After modify-volume grows a disk, what else must you do on Linux?

  1. Nothing
  2. Reboot
  3. Grow the file system (for example xfs_growfs)
  4. Create a new instance
Show answer

C — AWS grows the block device; the OS has to grow the file system.

Q3. Attaching a volume fails with InvalidVolume.ZoneMismatch. Why?

  1. The volume is encrypted
  2. The volume and instance are in different Availability Zones
  3. The volume is too large
  4. The snapshot is incomplete
Show answer

B — Volumes attach only to instances in the same zone.

Q4. How long must you wait between modifications of the same volume?

  1. 1 minute
  2. 1 hour
  3. 6 hours
  4. 24 hours
Show answer

C — EBS allows one modification per volume every 6 hours.

Q5. What happens to a data volume you attached yourself when the instance is terminated?

  1. Always deleted
  2. Kept unless DeleteOnTermination is set
  3. Moved to S3
  4. Converted to a snapshot
Show answer

B — Added volumes are kept by default, so delete them yourself.

Quick recap

  • EBS volumes live in one zone; snapshots belong to the Region and restore to any zone.
  • gp3 gives 3,000 IOPS and 125 MiB/s at any size (up to 80,000 IOPS and 2,000 MiB/s); io2 Block Express for the busiest databases.
  • Resize live: modify-volume, wait for optimizing, then grow the file system. One change per 6 hours.
  • Mount data disks by UUID with nofail; check lsblk before mkfs.
  • Added volumes and snapshots outlive instances; delete them or they keep charging. Start-SsmEndpoints.ps1 and Stop-SsmEndpoints.ps1 are ready for later labs.

Next lesson

Lesson 15: AMIs and launch templates → You’ll turn a configured server into your own image and launch identical copies from a template.

Further reading: AWS EBS volumes

Want to go deeper into AWS EBS volumes? Read Amazon EBS volume types and Modify a volume using Amazon EBS Elastic Volumes. You can also see the full plan for this course on the AWS Cloud Administration course page.

Scroll to Top