Building a CentOS 6 AMI with Cloud-Init and Automatic Resizing of the Root Partition

[EDIT 23/09/2015] the upgraded code is now available on github.

There are already multiple official/unofficial CentOS 6 images on amazon EC2. But I do not like these AMI for the following reasons:

  • the paravirtual AMI cannot use the HVM only instance types (t2.small, m4…). Still, their root filesystem can be resized easily (they use no partitioning and only the filesystem must be resized);
  • the HVM AMI can use all instances types, but the root filesystem cannot be grown after boot, you are stuck with 8Gb for the lifetime of the instance (or if you like complicated things you can add more disks and mount them);
  • they all use root to login and not the usual user+sudo combo.

So, here is Yet Another Procedure to Create a clean Centos 6 Image. This procedure will create a blank image and add the necessary packages and configuration to have the following cloud-init functionalities:

  • HVM image to be able to use all amazon instance types
  • growpart at boot to resize the root partition and filesystem
  • cloud-init to add the custom ssh key provided by the user at boot
  • user-data interpreted correctly
  • correct return values for dmidecode …

This tutorial takes a lot from Guest’s Linux Stuff and the comments from NCBI – SRA on the official Amazon centos 6 AMI.

First launch a centos 6 HVM instance on Amazon, connect to it and upgrade the machine to have the latest kernel:

yum update -yes

Reboot (this is mandatory for the dracut update in the chroot ).

Create a 2Gb volume (or bigger depending on the additional packages you may want) and attach it as /dev/sdb ( it will appear as /dev/xvdbdb in the machine).

Create a single partition /dev/xvdb1 with all the space using fdisk for example (for custom partitioning schemes, remember to customize both the fstab and the grub config). You can automate partitioning with sfdisk.

As root, create the filesystem, mount everything and install a base system on the chroot, configure the network, install grub (update if you have a custom partitioning scheme) and disable ipv6:

mkfs.ext4 /dev/xvdb1
mount /dev/xvdb1 /mnt/
mkdir /mnt/etc

export ROOT_UUID=$(blkid /dev/xvdb1 -o udev|grep ID_FS_UUID=|awk -F= '{print $2}')
cat << EOT >/mnt/etc/fstab
UUID=$ROOT_UUID / ext4 defaults 1 1
tmpfs /dev/shm tmpfs defaults 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
sysfs /sys sysfs defaults 0 0
proc /proc proc defaults 0 0
EOT

yum --releasever=6 --installroot=/mnt/ -y groupinstall Base

cat <<EOT >/mnt/etc/sysconfig/network
NETWORKING=yes
HOSTNAME=localhost.localdomain
NETWORKING_IPV6=no
IPV6INIT=no
EOT
cat <<EOT >/mnt/etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE="eth0"
NM_CONTROLLED="no"
ONBOOT="yes"
BOOTPROTO="dhcp"
EOT

echo "sysctl.conf:net.ipv6.conf.all.disable_ipv6 = 1" >> /mnt/etc/sysctl.conf

CHROOT_KERNEL=`yum --installroot=/mnt/ install kernel | awk '/kernel/ {print $2}' | cut -c 8-`

cat <<EOT > /mnt/boot/grub/grub.conf
default=0
timeout=0
hiddenmenu

title CentOS ($CHROOT_KERNEL)
 root (hd0,0)
 kernel /boot/vmlinuz-$CHROOT_KERNEL ro root=UUID=$ROOT_UUID rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD console=ttyS0,115200 crashkernel=auto SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM
 initrd /boot/initramfs-$CHROOT_KERNEL.img
EOT

ln -s /boot/grub/grub.conf /mnt/boot/grub/menu.lst

MAKEDEV -d /mnt/dev -x console
MAKEDEV -d /mnt/dev -x null
MAKEDEV -d /mnt/dev -x zero

mount -o bind /dev /mnt/dev
mount -o bind /dev/pts /mnt/dev/pts
mount -o bind /dev/shm /mnt/dev/shm
mount -o bind /proc /mnt/proc
mount -o bind /sys /mnt/sys

cp /etc/resolv.conf /mnt/etc/resolv.conf

now, chroot to the new image:

chroot /mnt

Customize the packages, install grub, and upgrade the initrd with Growpart/Growroot. Dracut MUST NOT make any warning, and requires that the running kernel is the same as the installed kernel (hence the upgrade of the host instance):

### run from inside the chroot ###

yum install -y epel-release
yum remove -y cpuspeed abrt* at hal* iptables-ipv6 irqbalance kexec-tools psacct quota sendmail smartmontools rng-tools mdadm
yum install -y openssh-server yum-plugin-fastestmirror e2fsprogs dhclient vi grub sudo cloud-init cloud-utils cloud-utils-growpart dracut-modules-growroot

cat <<EOT > /etc/cloud/cloud.cfg.d/06_growpart.cfg
growpart:
 mode: auto
 devices: ['/']
 ignore_growroot_disabled: false
 resize_rootfs: True
EOT

## you must not have any error from dracut !
dracut -f

grub-install /dev/xvdb
grub --batch <<EOT 1>/dev/null 2>/dev/null
device (hd0) /dev/xvdb
root (hd0,0)
setup (hd0)
quit
EOT

touch /.autorelabel
rm /mnt/resolv.conf
yum clean all
exit

The next stage is to remove all artefacts from building the image:

rm -f /mnt/root/.bash_history
rm -f /mnt/var/log/yum.log
rm -rf /mnt/tmp/*
> /mnt/var/log/messages

umount /mnt/dev/shm
umount /mnt/dev/pts
umount /mnt/dev
umount /mnt/proc
umount /mnt/sys
umount /mnt

You can now detach the volume, snapshot it and use it to create your new AMI . Make sure you register it as an HVM machine and not paravirtual (you should not need any kernel_id or ramdisk_id).

[EDIT]: add information about which kind of image is created

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s