Uploading Custom Images to Amazon EC2

To upload your image to Amazon EC2, you need to ensure that your image is in the raw format. You can do that by create the image in the raw format to start with, or you can covert it at a later time. For example, to convert a Virtual Box Image to a raw format, you can run the following command.

VBoxManage internalcommands converttoraw ec2.vdi ec2.img

We compress the image to avoid uploading a bunch of zero-ed disk.

gzip -9 ec2.img

My image is 8 GB uncompressed and 334 MB compressed.

We create a standard Amazon instance, upload the image. We then attach an EBS volume the appropriate size for our image. We then extract the new image onto the EBS volume.

gzip -c -d ec2.img.gz | dd of=/dev/xvdf bs=10M

Detach the image and create a snapshot.

We then register our image with a user provider kernel. See Custom Kernel Docs.

Here is an example command for North Virginia

ec2-register -a x86_64 -n "CentOS 6.5" -d "CentOS 6.5 x86_64 minimal install \
Provided by me" --root-device-name /dev/sda -b /dev/sda="snap-b9db2b10":8:true -b /dev/sdf=ephemeral0 --kernel aki-b4aa75dd -K somekey.pem -C somecert.pem

Or using the newer ami command

aws ec2 register-image --architecture x86_64 --name "CentOS 6.5" --description "CentOS 6.5 x86_64 minimal install \
Provided by me" --root-device-name /dev/sda --block-device-mappings "[{\"DeviceName\": \"/dev/sda\", \"Ebs\": {\"SnapshotId\": \"snap-b9db2b10\", \"VolumeSize\":8}},{\"DeviceName\": \"/dev/sdf\",\"VirtualName\":\"ephemeral0\"}]" --kernel-id aki-b4aa75dd

Building Custom Amazon Images

Working with Amazon EC2 Images, it has been helpful to build custom images, so they match the same images that are installed in customer environments. I also find it help to be able to run the same Operating System that is running in dev and production environments.

CentOS and several other Linux Operating system will work with the default Kernel. Building a custom image is pretty easy to do, but there are a few things you need to do to get your system to work on Amazon EC2 instances. Here are the steps we took to build this image.

1) When doing the install select the correct partitioning method. I’ve found that LVM doesn’t work with the boot system that Amazon is using for custom Kernels. I also found it helpful to have the root partition also contain grub. Here is my partitioning:

/ <- 8 GB <-- FIRST PARTITION!!!
Swap <- 1 GB

2) I then did a minimal Linux install.

3) After configuring the root password, I setup the basics on the machine, and add the ec2-user.

dhclient eth0

adduser ec2-user

yum update

yum install system-config-firewall-tui system-config-network-tui setuptool vim screen openssh-clients rsync wget man acpid ntp

chkconfig acpid on
chkconfig ntpd on

setup
# enable SSH Firewall
# configure network for dhcp

3) Configuring the network is important to get right, otherwise our machine will not be accessible to other machines on the network. I configure the network using DHCP, and then remove the Hardware address line from the configuration, so on-boot the new network devices will get the default configuration.

vim /etc/sysconfig/networking/devices/ifcfg-eth0
#remove mac address line
#on boot yes
#NM Controlled no

4) I setup the ec2-ami tools and cloud-init tools that are provided for CentOS using the Epel Repository. I use the cloud-init tools to get the keys installed on to the server at boot time.

yum install http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm

yum install epel (http://linux.mirrors.es.net/fedora-epel/6/i386/repoview/epel-release.html)

yum install cloud-init

vim /etc/cloud/cloud.cfg

chpasswd:
 list: |
  root:RANDOM
  ec2-user:RANDOM
 expire: false

5) I wanted to keep SELinux running on the system, and I found that I needed to restore some linux contexts to the files the cloud-init was creating on boot. This allows the SSH keys to work with cloud-init, and we get to keep SELinux on.

#Work around selinux problem and persistent net
vim /etc/rc.d/rc.local
#add the following line
rm -f /etc/udev/rules.d/70-persistent-net.rules
restorecon -r /home/*/.ssh

# ensure menu.lst symbolic links to grub.conf

yum install sudo

#as root
vim /etc/sudoers.d/cloud-init
#add line
ec2-user ALL = NOPASSWD: ALL

chmod a-rwx /etc/sudoers.d/cloud-init
chmod ug+r /etc/sudoers.d/cloud-init

#test sudo access from ec2-user

6) We get rid of any existing keys in the environment so the image can be shared with others.

#delete keys
find / -name “authorized_keys” –exec rm –f {} \;

#Delete third party keys CVS, SVN, GIT, ETC

exit
login

#delete shell history
find /root/.*history /home/*/.*history -exec rm -f {} \;

#fill disk with zeros
cat /dev/zero > /tmp/zerofill
sleep 1
sync
rm -f /tmp/zerofill
sleep 1
sync

shutdown -h -P now