How to reduce the size of EBS Windows boot volume in AWS?

In a previous blog I demonstrated the steps to reduce the root EBS volume size of a Amazon Linux EC2 instance.  Recently I have been asked to do it on a Windows Server instance. With minor tweaks to the steps from my previous blog I was able to reduce the Windows Server’s root volume.  With this, not only can we save the EBS usage costs, we also save the backup snapshot costs of such instances.  Furthermore, AMIs can be created with minimum spaces.  When teams at work routinely launch EC2 instances from such reduced sized AMI images the savings could be significant.

In this blog, I will demonstrate the steps to reduce a Microsoft Windows Server 2016 Base (ami-b2e756ca) root EBS volume size from 30GB to 20GB. The actual file system used size is about 19.7GB.

  1. Stop the target Windows Server EC2 instance.
  2. Snapshot the Windows Server’s root EBS volume.
  3. Create an EBS volume from the snapshot. This will be the 30GB temporary source EBS volume.
  4. Launch a new EC2 worker instance in the same availability zone as the target instance.  Here I launched the instance from Amazon Linux AMI 2017.09.1 HVM (ami-f2d3638a.)  Install the ntfsprogs RPM.
    yum --enablerepo epel install ntfsprogs
  5. Attach the source EBS volume to the worker instance as xvdf.
  6. Dump current source disk partition info to a file.  Note the root partition xvdf1 starts at sector 2048.
    sfdisk -d /dev/xvdf > sfdisk-d.xvdf
    
     # partition table of /dev/xvdf
     unit: sectors
    
     /dev/xvdf1 : start=     2048, size= 62910464, Id= 7, bootable
     /dev/xvdf2 : start=        0, size=        0, Id= 0
     /dev/xvdf3 : start=        0, size=        0, Id= 0
     /dev/xvdf4 : start=        0, size=        0, Id= 0
  7. On the worker instance, find out the minimum size the filesystem can be reduced to.
    ntfsresize --info /dev/xvdf1
    
    ntfsresize v2017.3.23 (libntfs-3g)
     Device name        : /dev/xvdf1
     NTFS volume version: 3.1
     Cluster size       : 4096 bytes
     Current volume size: 32210153984 bytes (32211 MB)
     Current device size: 32210157568 bytes (32211 MB)
     Checking filesystem consistency ...
     100.00 percent completed
     Accounting clusters ...
     Space in use       : 19227 MB (61.2%)
     Collecting resizing constraints ...
     You might resize at 19721502720 bytes or 19227 MB (freeing 12489 MB).
     Please make a test run using both the -n and -s options before real resizing!
  8. Create a new target EBS volume of a smaller size.  The size needs to be at least slightly larger than the actual filesystem used size.  Here I used 20GB.
  9. Attach the new target EBS volume to the worker instance as xvdg.
  10. Resize the filesystem to the suggested 19227MB.  Enter ‘y’ when prompted to proceed.
    ntfsresize -s 19227M /dev/xvdf1
    
    ntfsresize v2017.3.23 (libntfs-3g)
     Device name        : /dev/xvdf1
     NTFS volume version: 3.1
     Cluster size       : 4096 bytes
     Current volume size: 32210153984 bytes (32211 MB)
     Current device size: 32210157568 bytes (32211 MB)
     New volume size    : 19226997248 bytes (19227 MB)
     Checking filesystem consistency ...
     100.00 percent completedd
     Accounting clusters ...
     Space in use       : 12984 MB (40.3%)
     Collecting resizing constraints ...
     Needed relocations : 0 (0 MB)
     WARNING: Every sanity check passed and only the dangerous operations left.
     Make sure that important data has been backed up! Power outage or computer
     crash may result major data loss!
     Are you sure you want to proceed (y/[n])?y
     Schedule chkdsk for NTFS consistency check at Windows boot time ...
     Resetting $LogFile ... (this might take a while)
     Updating $BadClust file ...
     Updating $Bitmap file ...
     Updating Boot record ...
     Syncing device ...
     Successfully resized NTFS on device '/dev/xvdf1'.
     You can go on to shrink the device for example with Linux fdisk.
     IMPORTANT: When recreating the partition, make sure that you
      1)  create it at the same disk sector (use sector as the unit!)
      2)  create it with the same partition type (usually 7, HPFS/NTFS)
      3)  do not make it smaller than the new NTFS filesystem size
      4)  set the bootable flag for the partition if it existed before
     Otherwise you won't be able to access NTFS or can't boot from the disk!
     If you make a mistake and don't have a partition table backup then you
     can recover the partition table by TestDisk or Parted's rescue mode.
  11. Find out the total MB we need to copy from the source disk to the new smaller disk.  Here we need to cover the reserved sectors (2048 sectors, or 1MB, from step 6 above) at the front of the disk, to the end of the filesystem.
    echo $((1+19227))
    
    19228
  12. Block copy from xvdf to xvdg, with 1MB block size and total count of 19228.
    dd bs=1M if=/dev/xvdf of=/dev/xvdg count=19228
    
    20162019328 bytes (20 GB) copied, 442.911 s, 45.5 MB/s
  13. Dump the new target disk xvdg partition info to a file.  Edit the file by updating the xvdg1 size to the new size in sectors (39376896.)
    echo $((19227*2048))
    
    39376896
    
    sfdisk -d /dev/xvdg > sfdisk-d.xvdg
    
    # partition table of /dev/xvdg
     unit: sectors
     /dev/xvdg1 : start=     2048, size= 6291046439376896, Id= 7, bootable
     /dev/xvdg2 : start=        0, size=        0, Id= 0
     /dev/xvdg3 : start=        0, size=        0, Id= 0
     /dev/xvdg4 : start=        0, size=        0, Id= 0
  14. Repartition target disk xvdg.
    sfdisk /dev/xvdg < sfdisk-d.xvdg
    
    Checking that no-one is using this disk right now ...
     OK
     Disk /dev/xvdg: 2610 cylinders, 255 heads, 63 sectors/track
    
    Old situation:
     Units: cylinders of 8225280 bytes, blocks of 1024 bytes, counting from 0
       Device Boot Start     End   #cyls    #blocks   Id  System
     /dev/xvdg1   *      0+   3916-   3916-  31455232    7  HPFS/NTFS/exFAT
     /dev/xvdg2          0       -       0          0    0  Empty
     /dev/xvdg3          0       -       0          0    0  Empty
     /dev/xvdg4          0       -       0          0    0  Empty
     New situation:
     Units: sectors of 512 bytes, counting from 0
    
      Device Boot    Start       End   #sectors  Id  System
     /dev/xvdg1   *      2048  39378943   39376896   7  HPFS/NTFS/exFAT
     /dev/xvdg2             0         -          0   0  Empty
     /dev/xvdg3             0         -          0   0  Empty
     /dev/xvdg4             0         -          0   0  Empty
     Warning: partition 1 does not end at a cylinder boundary
     Successfully wrote the new partition table
     Re-reading the partition table ...
     If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)
     to zero the first 512 bytes:  dd if=/dev/zero of=/dev/foo7 bs=512 count=1
     (See fdisk(8).)
  15. Detach xvdg from the worker instance, attach it to the target instance as /dev/sda1, and create an AMI image from the instance.

Verify everything is good before proceeding with the cleanup.

Cleanup:

  1. Terminate the EC2 worker instance.
  2. Delete the temporary target EBS volume.
  3. Delete the snapshot.
  4. Delete the source root EBS volume.

I hope you find this blog useful.  And if you do, please head over to our web site and check out what else that we do to optimize cloud resources.  Please feel free to contact FittedCloud support (mailto:support@fittedcloud.com) if you have any questions.

Other Related Blogs

FittedCloud Cloud Cost Optimization Solutions
FittedCloud offers machine learning based cloud cost optimization solutions that help customers reduce AWS spend significantly. Our current solutions include machine learning driven actionable advisories with click through actions for EC2, EBS, RDS, DynamoDB, ElastiCache, ElasticSearch, AutoScale, Lambda, etc. and full/lights out automation for EC2, EBS, DynamoDB and RDS. Our solution typically can save customers up to 50% of their cost on AWS. For more details, please visit https://www.fittedcloud.com/.