Shrinking Root EBS Volume for AWS EC2 Linux Instances

For AWS EC2 Linux instances created from offical AWS AMI, the root EBS volume is at minimal size of 8G. Unfortunately, there is no direct way to create a smaller root EBS volume or shrink it.

Shrinking a root volume could have several benefits:

  • It may save you a few penny each month,
  • By mounting important directories to other volumes/partitions, you can enhance the flexibility, maintainability and security of the system setup.

When searching for available solutions, I found both Alexander Todorov and Matt Berther have provided useful tips, but following their step-by-step instructions only resulting to a unbootable EC2 instance. Luckily, Mike Oliver’s comment under Matt’s article and web_ninjia’s Q&A on StackOverflow pointed out the right direction.

Since the BIOS boot partition is required for a root EBS volume, the whole process is about to copy the entire volume data, including the MBR, partition table and BIOS boot partition, from the bigger volume to a smaller one. Detailed procedure is described below:

  1. Take notes about the availability zone (AZ) and block device name of current root EBS volume. You can find them in the AWS Console.

  2. Take notes about the disk usage of current root EBS volume. You can find it by SSH into your EC2 instance, then df -h.

    $ df -h
    Filesystem      Size  Used Avail Use% Mounted on
    /dev/xvda1      7.8G  780M  6.6G  11% /
    ....
  3. Backup by shutting down your EC2 instance and taking a snapshot from the current root EBS volume.

  4. Create an EBS volume from the snapshot created in step 3, give it a name such as “source”.

  5. Create another empty EBS volume with a smaller size, give it a name such as “target”.

  6. Launch your instance to fully running.

  7. Attach the source volume to /dev/sdf and the target volume to /dev/sdg. In SSH terminal, their block device name will become /dev/xvdf and /dev/xvdg respectively.

  8. SSH into your instance, check the filesystem of source volume by e2fsck -f /dev/xvdf1.

    # e2fsck -f /dev/xvdf1
    e2fsck 1.42.9 (4-Feb-2014)
    Pass 1: Checking inodes, blocks, and sizes
    Pass 2: Checking directory structure
    Pass 3: Checking directory connectivity
    Pass 4: Checking reference counts
    Pass 5: Checking group summary information
    cloudimg-rootfs: 58324/524288 files (0.2% non-contiguous), 265281/2094474 blocks
  9. Resize the filesystem of source volume to a small size by resize2fs -p /dev/xvdf1 SMALL-SIZE. The SMALL-SIZE must be larger than the actual disk usage found in step 2.

    # resize2fs -p /dev/xvdf1 1024M
    resize2fs 1.42.9 (4-Feb-2014)
    Resizing the filesystem on /dev/xvdf1 to 262144 (4k) blocks.
    Begin pass 2 (max = 101573)
    Relocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Begin pass 3 (max = 64)
    Scanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Begin pass 4 (max = 7856)
    Updating inode references     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    The filesystem on /dev/xvdf1 is now 262144 blocks long.
  10. Take notes about the number of 16MB blocks, by following Matt’s instruction: “The last line from the resize2fs command should tell you how many 4k blocks the filesystem now is. To calculate the number of 16MB blocks you need, use the following formula: blockcount * 4 / (16 * 1024). Round this number up to give yourself a little buffer.” (So the number of 16MB blocks is 262144 * 4 / (16 * 1024) = 64. We round it up to 70, ensuring that the MBR, partition table and BIOS boot partition in source volume could get copied in the following steps.)

  11. Resize the root partition of source volume to equal or a little bit larger than the resized filesystem, by parted /dev/xvdf, then resizepart.

    # parted /dev/xvdf
    GNU Parted 2.3
    Using /dev/xvdf
    Welcome to GNU Parted! Type 'help' to view a list of commands.
    (parted) print
    Model: Xen Virtual Block Device (xvd)
    Disk /dev/xvdf: 8590MB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    
    Number  Start   End     Size    Type     File system  Flags
     1      8225kB  8587MB  8579MB  primary  ext4         boot
    
    (parted) resizepart
    Partition number? 1
    Warning: Partition /dev/xvdf1 is being used. Are you sure you want to continue?
    Yes/No? Yes
    End?  [8587MB]? 1056MB
    Warning: Shrinking a partition can cause data loss, are you sure you want to continue?
    Yes/No? Yes
    (parted) print
    Model: Xen Virtual Block Device (xvd)
    Disk /dev/xvdf: 8590MB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    
    Number  Start   End     Size    Type     File system  Flags
     1      8225kB  1056MB  1048MB  primary  ext4         boot
    
    (parted) quit
    Information: You may need to update /etc/fstab.
  12. Issue a source volume to target volume copy, by dd bs=16M if=/dev/xvdf of=/dev/xvdg count=NUMBER-OF-16MB-BLKS. The NUMBER-OF-16MB-BLKS is what we get in step 10.

    # dd bs=16M if=/dev/xvdf of=/dev/xvdg count=70
    70+0 records in
    70+0 records out
    1174405120 bytes (1.2 GB) copied, 17.6647 s, 66.5 MB/s
  13. Check the partition table and filesystem of target volume with fdisk -l.

    # fdisk -l
    
    Disk /dev/xvda: 8589 MB, 8589934592 bytes
    ...
        Device Boot      Start         End      Blocks   Id  System
    /dev/xvda1   *       16065    16771859     8377897+  83  Linux
    
    Disk /dev/xvdf: 8589 MB, 8589934592 bytes
    ...
        Device Boot      Start         End      Blocks   Id  System
    /dev/xvdf1   *       16065     2062500     1023218   83  Linux
    
    Disk /dev/xvdg: 3221 MB, 3221225472 bytes
    ...
        Device Boot      Start         End      Blocks   Id  System
    /dev/xvdg1   *       16065     2062500     1023218   83  Linux
  14. Resize the root partition in target volume, by parted /dev/xvdg then resizepart.

    # parted /dev/xvdg
    GNU Parted 2.3
    Using /dev/xvdg
    Welcome to GNU Parted! Type 'help' to view a list of commands.
    (parted) print
    Model: Xen Virtual Block Device (xvd)
    Disk /dev/xvdg: 3221MB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    
    Number  Start   End     Size    Type     File system  Flags
     1      8225kB  1056MB  1048MB  primary  ext4         boot
    
    (parted) resizepart
    Partition number? 1
    End?  [1056MB]? 3150MB
    (parted) print
    Model: Xen Virtual Block Device (xvd)
    Disk /dev/xvdg: 3221MB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    
    Number  Start   End     Size    Type     File system  Flags
     1      8225kB  3150MB  3142MB  primary  ext4         boot
    
    (parted) quit
    Information: You may need to update /etc/fstab.
  15. Resize the filesystem of target volume, by resize2fs -p /dev/xvdg1.

    # resize2fs -p /dev/xvdg1
    resize2fs 1.42.9 (4-Feb-2014)
    Resizing the filesystem on /dev/xvdg1 to 767034 (4k) blocks.
    The filesystem on /dev/xvdg1 is now 767034 blocks long.
  16. Stop your EC2 instance, detach all EBS volumes.

  17. Attach the target volume to your EC2 instance at position /dev/sda1, so it becomes the root volume of your instance.

  18. Launch your instance and check if everything is working properly.

If everything goes right, remember to clean up by deleting the leftover EBS volumes, and the backup snapshot created in step 3. Also, you could create a snapshot or even your own AMI from the new smaller root volume, in case of similar situation.

As you can see, shrinking a root EBS volume for AWS EC2 Linux instances is a daunting job and consists lots of steps. My final thoughts is: When infrastructure dynamically scales up and down, could the extra layer of complexity derives from it be another problem?

What’s your idea?

Leave a Reply

Your email address will not be published. Required fields are marked *