Last week we discussed how to remove the AWS Marketplace code from a CentOS AMI. However, CentOS only provides paravirtual (PV) AMIs for Amazon EC2, and as of yet has not provided HVM (hardware virtual machines) AMIs.

Why would you want a HVM AMI? Amazon appears to be putting preference towards future instance types requiring HVM, as shown by the latest T2 instance types requiring HVM.

Today, we’ll go through the process of creating a CentOS HVM AMI:

* Note: all shell commands should be ran as root.

Prepare the Instances

– Create a temporary IAM user account with ‘Power User’ access.

– SSH into your CentOS instance (hence forth referred to as “Instance #1”), and ensure Grub is installed:

yum install grub -y

– Stop Instance #1, and create a snapshot of its root volume.

– Create a new volume from the snapshot. Tag it as “Original Volume”.

– Launch a new instance of Amazon Linux – HVM version (hence forth referred to as “Instance #2”).

– Attach the Original Volume to Instance #2 as /dev/sdm

– Create a second new volume, the same size as the Original Volume. Tag it as “New Volume”.

– Attach the “New Volume” to Instance #2 as /sdj

 

Prepare the Volumes

– SSH into Instance #2.

– Partition the New Volume:

parted /dev/xvdj --script 'mklabel msdos mkpart primary 1M -1s print quit'
partprobe /dev/xvdj
udevadm settle

– Minimize the file system size of the Original Volume to speed up the copying process:

e2fsck -f /dev/xvdm
resize2fs -M /dev/xvdm

– Copy down the block size and count values from the resize2fs output. For example:
Resizing the filesystem on /dev/xvdm to 231523 (4k) blocks.

– Do a raw copy from the Original Volume to the New Volume, using the exact values of “bs=” and “count=” from the previous output:

dd if=/dev/xvdm of=/dev/xvdj1 bs=4K count=231523

– Resize the filesystem on New Volume:

resize2fs /dev/xvdj1

 

Setup Grub

– Prepare the New Volume for the chrooted Grub installation:

mount /dev/xvdj1 /mnt
cp -a /dev/xvdj /dev/xvdj1 /mnt/dev/
rm -f /mnt/boot/grub/*stage*
cp /mnt/usr/*/grub/*/*stage* /mnt/boot/grub/
rm -f /mnt/boot/grub/device.map

– Do an offline Grub installation on the New Volume, which is required for the HVM instance:

cat <<EOF | chroot /mnt grub --batch
device (hd0) /dev/xvdj
root (hd0,0)
setup (hd0)
EOF

– Remove the temporary device from the destination volume, which was required to install Grub:

rm -f /mnt/dev/xvdj /mnt/dev/xvdj1

– Get the filename of your boot files:

ls /mnt/boot/vmlinuz*
ls /mnt/boot/initramfs*

– Edit the Grub config:

nano /mnt/boot/grub/grub.conf

Ensure that your configuration looks similar to this example, and that file names match the files in /mnt/boot:

default=0
timeout=0

title CentOS 6.5
root (hd0,0)
kernel /boot/vmlinuz-2.6.32-431.29.2.el6.x86_64 root=LABEL=/ console=ttyS0
initrd /boot/initramfs-2.6.32-431.29.2.el6.x86_64.img

– Edit the fstab file:

nano /mnt/etc/fstab

– Ensure the first line for the root (/) entry matches this sample:

LABEL=/ / ext4 defaults,noatime 1 1

– Create a label on /dev/xvdj1, and un-mount the volume:

e2label /dev/xvdj1 /
sync
umount /mnt

 

Create a new HVM AMI

– Configure AWS CLI tools with the temporary IAM Power User account:

aws configure
AWS Access Key ID None: XXXXXXXXXXXXXXXXXXXX
AWS Secret Access Key None: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Default region name None: us-east-1
Default output format None: json

– Create a snapshot of the New Volume:

aws ec2 create-snapshot --volume-id vol-xxxxxxxx --description "CentOS 6.5 HVM snapshot"

– Register new HVM AMI (replace snap-xxxxxxxx with the snapshot ID created above):

aws ec2 register-image --name "CentOS 6.5 HVM" --description "CentOS 6.5 HVM" --architecture x86_64 --root-device-name "/dev/sda1" --virtualization-type hvm --block-device-mappings "[{"DeviceName": "/dev/sda1","Ebs":{"SnapshotId":"snap-xxxxxxxx"}}]"

 

You now have a CentOS HVM AMI, which you can now use to launch any T2 type instances!

[Credit for this solutions goes to ChrisC at Amazon.]