Home / AWS

AWSRunbookBeginner

Transformation: migrate every EBS gp2 volume to gp3 without downtime

Move EBS volumes from gp2 to gp3 live with Elastic Volumes. Find gp2 volumes across regions, set IOPS and throughput so performance doesn't drop, convert in batches, and update launch templates and IaC so gp2 doesn't come back.

Deepak Bhardwaj2 min read

Applies toAmazon EBS gp2 and gp3 volumes, EC2 launch templates, AWS CLI v2

Why

gp3 is cheaper per GB than gp2 and gives a baseline of IOPS and throughput regardless of size, with performance you can raise independently. On gp2, IOPS scale with size, which is why people over-provision big volumes just for IOPS.

1. Find gp2 volumes

for r in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
  aws ec2 describe-volumes --region $r --filters Name=volume-type,Values=gp2 \
    --query "Volumes[].[VolumeId,Size,State,Attachments[0].InstanceId]" --output text | sed "s/^/$r /"
done > gp2-volumes.txt
wc -l gp2-volumes.txt

2. Match performance

gp2 performance: 3 IOPS per GiB (minimum 100, up to the gp2 maximum) plus burst to 3,000 IOPS for smaller volumes. gp3 baseline: 3,000 IOPS and 125 MiB/s.

gp2 size gp2 baseline IOPS gp3 setting
Up to 1,000 GiB Up to 3,000 (burst to 3,000) Baseline 3,000 is enough
Larger 3 × size Set --iops to 3 × size (or measured peak)
Throughput-heavy (big sequential reads) Up to 250 MiB/s Set --throughput (e.g. 250)

Check real usage before deciding: CloudWatch VolumeReadOps, VolumeWriteOps, VolumeReadBytes, VolumeWriteBytes over a busy week. Check the current gp2/gp3 limits in the EBS documentation.

3. Convert (online)

aws ec2 modify-volume --volume-id vol-0abc123 --volume-type gp3 --iops 3000 --throughput 125
aws ec2 describe-volumes-modifications --volume-ids vol-0abc123 \
  --query "VolumesModifications[0].{state:ModificationState, progress:Progress}"

The volume stays attached and usable during modifying and optimizing. Performance during optimisation is between the old and new specification.

Batch conversion for small volumes:

awk '$3 <= 1000 {print $1, $2}' gp2-volumes.txt | while read region vol; do
  aws ec2 modify-volume --region $region --volume-id $vol --volume-type gp3
done

Note

After a modification you must wait (currently six hours) before modifying the same volume again. Get the settings right the first time for large volumes.

4. Stop creating gp2

  • Launch templates and AMI block device mappings: set VolumeType: gp3.
  • IaC defaults: Terraform aws_ebs_volume.type = "gp3", CloudFormation VolumeType: gp3.
  • EKS: a gp3 StorageClass (EBS CSI driver) as default; the old gp2 class as non-default.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
  annotations: { storageclass.kubernetes.io/is-default-class: "true" }
provisioner: ebs.csi.aws.com
parameters: { type: gp3 }
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
  • AWS Config custom rule or a periodic report for any remaining gp2 volumes.

Checklist

  • gp2 inventory across all regions and accounts
  • IOPS/throughput set from measured usage for large volumes
  • All volumes converted; modifications completed
  • Launch templates, AMIs, IaC and StorageClasses default to gp3