GNU/Linux, Open Source, Cloud Computing, DevOps and more...

Partitioning and resizing the EBS Root Volume of an AWS EC2 Instance

No comments

One of the few things I do not like about the AWS EC2 service is that all available images (AMIs) used to to launch new instances require a root volume of at least 8 or 10 GB in size and all of them also have a single partition where the root filesystem is mounted on.

In my post The importance of properly partitioning a disk in Linux I discussed why in my opinion this approach is not appropriate and now I will address in a practical way how to divide those volumes into multiple partitions keeping the 8-10 GB base size or making them even smaller to save costs in case you want to deploy smaller servers that do not need as much storage space.

Prerequisites

In order to follow out this procedure it is necessary to have an auxiliary EC2 instance other than the one whose root volume we want to partition. Any instance type will be useful, so you can opt for the most economical currently available (t2.nano). Since Amazon will only charge you for the time it takes to execute the procedure (about 30 minutes) and then you will terminate the instance, the associated cost will be very low.

If you already have another EC2 instance running in the same region and availability zone, it will not be necessary to create a new one, since you can use the existing one to mount the volumes needed later. Mounting these volumes will not have any significant impact on the performance or capacity of the auxiliary instance used, but it is still a good idea not to use a production server that is critical for you, because if you make a mistake the service can be affected.

It is not essential, but highly recommended, that the auxiliary instance has the same Linux distribution and version as the instance you want to partition so that installing the boot loader in the new volume is as straightforward and trouble-free as possible. For the example of this article I have used an Ubuntu 16.04.2 LTS instance.

Thus, we start with 2 running instances: the one we want to partition and the auxiliary instance. We will call them AMI and AUX respectively, each with its corresponding root volume: amiroot and auxroot.

Starting point: AMI and AUX instances with their respective root volume

Starting point: AMI and AUX instances with their respective root volume

Initial EC2 instances

Initial EC2 instances

Initial EBS volumes

Initial EBS volumes

1. Create a new EBS volume

In our example we will create a smaller volume (6 GB) than the 8 GB default size offered by Amazon, but you can choose the size that best suits your needs, be it larger or smaller than 8 GB. You can also take the opportunity to encrypt the new volume, since by default all the root volumes used by Amazon AMIs are not encrypted.

Creation of new EBS volume to partition

Creation of new EBS volume to partition

Creation of new encrypted volume of less than 8GB

Creation of new encrypted volume of less than 8GB

New volume created but not attached to any instance

New volume created but not attached to any instance

2. Attach amiroot and myroot volumes to the auxiliary instance

Now you will detach the amiroot volume from the AMI instance and re-attach it to the AUX auxiliary instance. For this it is necessary to stop the AMI instance first, since being its root volume can not be detached without stopping it before. On the contrary, both volumes can be hot attached to the auxiliary instance with no problem because its root volume is auxroot and it will remain unchanged. You will assign the /dev/sdf device to the amiroot volume and /dev/sdg to myroot.

Diagram of auxiliary instance with 3 attached-volumes

Diagram of auxiliary instance with 3 attached volumes

Detaching amiroot volume from AMI instance

Detaching amiroot volume from AMI instance

Attaching amiroot volume to auxiliary instance

Attaching amiroot volume to auxiliary instance

3. Verify the attached volumes are recognized by the auxiliary instance

Access the auxiliary instance through SSH and verify the new attached volumes are available with lsblk command:

$ ssh ubuntu@ec2-54-194-114-199.eu-west-1.compute.amazonaws.com -i ~/.ssh/awskey.pem 
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-1020-aws x86_64)
...
...
ubuntu@ip-172-31-17-107:~$ lsblk 
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT 
xvda    202:0    0   8G  0 disk  
└─xvda1 202:1    0   8G  0 part / 
xvdf    202:80   0   8G  0 disk  
└─xvdf1 202:81   0   8G  0 part  
xvdg    202:96   0   6G  0 disk

If everything was ok then amiroot volume should appear as xvdf and myroot as xvdg. As you can see, there is an 8GB partition already created and mounted on /dev/xvdf1 which corresponds to the partition that came with the root volume of the instance created from the AMI. Since myroot volume was created from scratch it doesn’t have any partitions created yet.

4. Create custom partition scheme on myroot volume

It is time to partition the volume to your choice, which was the initial goal. If you have doubts about what partitions to create and how to size them I recommend to have a look to the following article:

Recommended reading:
  The importance of properly partitioning a disk in Linux

Here are some parted commands to set up a GPT partition table, a BIOS Boot Partition (BBP) and a suitable partitioning scheme for our example 6GB volume:

# parted /dev/xvdg
GNU Parted 3.2 
Using /dev/xvdg 
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) mklabel gpt
(parted) mkpart bbp 1MB 2MB
(parted) set 1 bios_grub on
(parted) mkpart root ext4 2MB 20%
(parted) mkpart swap linux-swap 20% 25%
(parted) mkpart home ext4 25% 30%
(parted) mkpart usr ext4 30% 65%
(parted) mkpart var ext4 65% 100%

Once created, the partition table should look like this:

(parted) unit GiB                                                          
(parted) p                                                                 
Model: Xen Virtual Block Device (xvd) 
Disk /dev/xvdg: 6.00GiB 
Sector size (logical/physical): 512B/512B 
Partition Table: gpt 
Disk Flags:  
 
Number  Start    End      Size     File system     Name  Flags 
 1      0.00GiB  0.00GiB  0.00GiB                  bbp   bios_grub 
 2      0.00GiB  1.20GiB  1.20GiB                  root 
 3      1.20GiB  1.50GiB  0.30GiB  linux-swap(v1)  swap 
 4      1.50GiB  1.80GiB  0.30GiB  ext4            home 
 5      1.80GiB  3.90GiB  2.10GiB  ext4            usr 
 6      3.90GiB  6.00GiB  2.10GiB  ext4            var

In order to achieve a better performance you will want to check if all partitions are optimally aligned according to the disk geometry. Actually this is only necessary if you created an HDD type EBS volume, such as st1, sc1 or magnetic, since gp2 and io1 volumes are backed by SSD disks (you can see details of different types of AWS EBS volumes at http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSVolumeTypes.html).

(parted) align-check optimal 1                                             
1 aligned 
(parted) align-check optimal 2 
2 aligned 
(parted) align-check optimal 3 
3 aligned 
(parted) align-check optimal 4 
4 aligned 
(parted) align-check optimal 5 
5 aligned
(parted) align-check optimal 6
6 aligned

However, if you specified partition size using percentages (%) instead of GB, MB or sectors you will not have to worry about this because parted will always align them optimally and the result of the previous check will always be satisfactory.

When leaving parted it is possible that you receive the following message:

(parted) quit 
Information: You may need to update /etc/fstab.

In that case, if you don’t see the new partition scheme with lsblk command you will have to execute the partprobe command and then it should be displayed correctly:

# lsblk                                             
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT 
xvda    202:0    0    8G  0 disk  
└─xvda1 202:1    0    8G  0 part / 
xvdf    202:80   0    8G  0 disk  
└─xvdf1 202:81   0    8G  0 part  
xvdg    202:96   0    6G  0 disk  
├─xvdg1 202:97   0    1M  0 part  
├─xvdg2 202:98   0  1.2G  0 part  
├─xvdg3 202:99   0  307M  0 part  
├─xvdg4 202:100  0  307M  0 part  
├─xvdg5 202:101  0  2.1G  0 part  
└─xvdg6 202:102  0  2.1G  0 part

5. Format the new partitions

Once you get your desired partition layout you will proceed to format all partitions except BPP and swap partitions. In the example we use the most standard Linux file system, ext4:

# for I in 2 4 5 6; do mkfs.ext4 /dev/xvdg${I}; done
...
...
# mkswap /dev/xvdg3
Setting up swapspace version 1, size = 307 MiB (321908736 bytes) 
no label, UUID=1aad1fa2-188e-4b7a-8a0f-33f775cdd329

6. Mount partitions

Now mount all partitions whose contents you are interested in replicating from the root disk of the starting AMI. In our example we will mount the root partition (/), /home, /usr and /var of myroot volume. Also mount the root partition of amiroot volume to later sync files from it:

# mkdir /mnt/amiroot
# mkdir -p /mnt/myroot/root /mnt/myroot/home /mnt/myroot/usr /mnt/myroot/var

# tree /mnt 
/mnt 
├── amiroot 
└── myroot 
    ├── home 
    ├── root 
    ├── usr 
    └── var 
 
6 directories, 0 files

# mount /dev/xvdf1 /mnt/amiroot
# mount /dev/xvdg2 /mnt/myroot/root
# mount /dev/xvdg4 /mnt/myroot/home
# mount /dev/xvdg5 /mnt/myroot/usr
# mount /dev/xvdg6 /mnt/myroot/var

7. Synchronize amiroot contents into its corresponding partition

Use rsync command to synchronize contents of the different directories in the single partition of amiroot root volume into their corresponding separate partitions in myroot volume. You have to be careful not to copy the contents of the same directories that now have their own allocated partition into the new root partition, so be sure to use the rsync –exclude parameter. Since these directories are being excluded, you will have to create them manually, but empty and with the appropriate permissions:

# rsync -av /mnt/amiroot/home/ /mnt/myroot/home/
# rsync -av /mnt/amiroot/usr/ /mnt/myroot/usr/
# rsync -av /mnt/amiroot/var/ /mnt/myroot/var/
# rsync -av --exclude=boot --exclude=home --exclude=usr --exclude=var /mnt/amiroot/ /mnt/myroot/root/
# mkdir /mnt/myroot/root/home;chmod 755 /mnt/myroot/root/home
# mkdir /mnt/myroot/root/usr;chmod 755 /mnt/myroot/root/usr
# mkdir /mnt/myroot/root/var;chmod 755 /mnt/myroot/root/var

It is very important at this point to unmount the original amiroot volume single partition and detach it from the auxiliary instance so that the grub boot loader installer that will be run later can not detect there is another bootable partition that interferes with that in the new partitioned volume. It is not enough just to unmount it with the umount command, but it will also be necessary to detach it from the instance as did previously in section #2.

# sync && umount /mnt/amiroot

8. Install grub boot loader on new volume myroot

Before doing so be careful to disable the /etc/grub.d/10_linux and /etc/grub.d/20_linux_xen scripts because they can cause problems in detecting the bootable BPP partition. To do this, simply add the exit command to the second line of both files, just after #!/bin/sh.

Next remove the /boot/grub/grub.cfg file which was the one that brought the AMI in origin and then replace it with another one adapted to your partitioned new volume:

# rm /mnt/myroot/root/boot/grub/grub.cfg
# grub-mkconfig -o /mnt/myroot/root/boot/grub/grub.cfg

Now you can install the grub boot loader on the new 6 GB disk:

# grub-install --target=i386-pc --directory=/mnt/myroot/usr/lib/grub/i386-pc --recheck --boot-directory=/mnt/myroot/root/boot /dev/xvdg

Do not forget to re-enable the 10_linux and 20_linux_xen scripts when you are finished if you have used as your auxiliary instance a server that you will use for other purposes. If not it doesn’t matter because at the end of the procedure the auxiliary instance will be terminated and destroyed.

9. Set new partitions in /etc/fstab file

First it is necessary to obtain partition UUID identifiers using the blkid command. It is best to run as root because otherwise it will not display swap related information.

# blkid 
/dev/xvda1: LABEL="cloudimg-rootfs" UUID="567ab888-a3b5-43d4-a92a-f594e8653924" TYPE="ext4" PARTUUID="1a7d4c6a-01" 
/dev/xvdg2: UUID="286a4418-45b4-40c6-aece-6a4e1efd247a" TYPE="ext4" PARTLABEL="root" PARTUUID="56c0cfb6-20eb-4123-a766-420911980fb3" 
/dev/xvdg4: UUID="6e244eed-310f-4aae-aaa1-7ef549bbdbd1" TYPE="ext4" PARTLABEL="home" PARTUUID="bdbacb79-532b-410f-853e-f5530c4f9fa7" 
/dev/xvdg5: UUID="cceffcdd-1aeb-4aab-b8e0-7ac04893858c" TYPE="ext4" PARTLABEL="usr" PARTUUID="fbee2b01-9d41-4c16-bda6-a4b2abc02a04" 
/dev/xvdg6: UUID="b3fe50cb-b147-4b3b-b8ce-17ee445db64c" TYPE="ext4" PARTLABEL="var" PARTUUID="b4983050-a4e6-4d8a-9284-1a269a451d35"
/dev/xvdg3: UUID="1aad1fa2-188e-4b7a-8a0f-33f775cdd329" TYPE="swap" PARTLABEL="swap" PARTUUID="24eecaf3-4942-4ead-bab4-909e359dd5ae"
/dev/xvdg1: PARTLABEL="bbp" PARTUUID="916ca11f-db90-48d1-93d2-de6a99b60f40"

Then move those identifiers to /etc/fstab as follows:

UUID=286a4418-45b4-40c6-aece-6a4e1efd247a  /      ext4   defaults,discard,noatime,errors=remount-ro      0 1
UUID=6e244eed-310f-4aae-aaa1-7ef549bbdbd1  /home  ext4   defaults,noatime,acl,user_xattr,nodev,nosuid    0 2
UUID=cceffcdd-1aeb-4aab-b8e0-7ac04893858c  /usr   ext4   defaults,noatime,nodev,errors=remount-ro        0 2
UUID=b3fe50cb-b147-4b3b-b8ce-17ee445db64c  /var   ext4   defaults,noatime,nodev,nosuid                   0 2
UUID=1aad1fa2-188e-4b7a-8a0f-33f775cdd329  swap   swap   defaults                                        0 0
tmpfs                                      /tmp   tmpfs  defaults,noatime,nodev,noexec,nosuid,size=256m  0 0

If you want to know more about the different mount options used in the example I recommend you again reading my article The importance of properly partitioning a disk in Linux.

10. Attach the new volume as the root volume of the instance launched in first place from the AMI

As part of the last step of this procedure, unmount all partitions previously mounted and detach the myroot volume already partitioned, configured and bootable from the auxiliary instance. Then re-attach it to the final instance in which it will be used, the AMI instance launched at first.

# sync && umount /mnt/myroot/root /mnt/myroot/home /mnt/myroot/usr /mnt/myroot/var

It is very important to attach the myroot volume to the EC2 instance as /dev/sda1 device in order to state it as root volume. Otherwise you will have problems booting the operating system.

If everything turned out well your instance should boot normally and you will be able to see in the EC2 instance system log the login message as it is shown in the third picture below. If something goes wrong you will get more information about the issue in the same log.

Final result diagram: AMI instance with root volume attached

Final result diagram: AMI instance with root volume attached

Very important: attach volume as root volume (/dev/sda1)

Very important: attach volume as root volume (/dev/sda1)

System log of EC2 instance successfully started

System log of EC2 instance successfully started

And that’s all. Now if you access the new instance you will see that everything is the same as before, but if you do a df -h you will see that all partitions you created before are displayed as mounted, and if you run the free -h command you will see a swap amount available equivalent to the size of the partition created in step #4. Do not forget to terminate the auxiliary instance if you are not going to use it anymore.

Enjoy your new system, which is now safer and better prepared to deal with changes that may occur in the future!



 

About the author

Daniel López Azaña
Cloud Solutions Architect

Entrepreneur, a generator of ideas and restless mind. Passionate about new technologies, especially Linux systems and Open Source Software. I also like to write about Technology News, Cloud Computing, DevOps, System Security, Web Development and Programming, SEO, Science, Innovation, Entrepreneurship, etc.

DanielPartitioning and resizing the EBS Root Volume of an AWS EC2 Instance

Related Posts

Leave a Reply

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