Skip to content
This repository

Creating a Debian EC2 EBS PVGRUB Image

aka: How to create a persistently bootable image that uses the native operating system kernel and runs on Amazon's Elastic Compute Cloud platform.

Step 1: Create a disk image

Do this first: Setup EC2 Credentials and Tools

On a currently running amazon instance

Create the image on amazon

This can also be done from the web interface

See this for a list of regions and availability zones.

I create the images with a 1 gigabyte size because it is easier to make it bigger than it is to shrink it

Create a 1 gb volume for our image
EC2_AVAIL_ZONE=`wget -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone`
EC2_REGION=${EC2_AVAIL_ZONE%?}

BUILD_VOLUME=`ec2-create-volume --size 1 --region ${EC2_REGION} --availability-zone ${EC2_AVAIL_ZONE} | awk '{print $2}'` 
Attach the volume to our running instance
BUILD_INSTANCE_ID=`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`

ec2-attach-volume ${BUILD_VOLUME} --instance ${BUILD_INSTANCE_ID} --device /dev/sdf --region ${EC2_REGION}

The status needs to be attached before moving on. You can check it with this:

ec2-describe-volumes ${BUILD_VOLUME} --region ${EC2_REGION}

Now when that device gets attached it will show up as /dev/sdf OR /dev/xvdf depending on the kernel you are using.

Use fdisk -l so see attached disks.

DEVICE=/dev/xvdf
cd /root
mkdir -p chroot/
echo y | mkfs.ext3 ${DEVICE}
mount ${DEVICE} chroot/

Step 2: Install the required software

apt-get update
apt-get -y dist-upgrade
apt-get install -y debootstrap

NOTE: if you are doing this from a non-debian linux, you will need to do the following instead

# download the .deb from http://packages.debian.org/squeeze/debootstrap
ar x debootstrap*.deb
tar xfz data.tar.gz
ln -s /root/usr/share/debootstrap/ /usr/share/
ln -s /root/usr/sbin/debootstrap /usr/sbin

We use the --no-check-certificate due to a bug in wget with wildcard certificates bugs.debian.org

mkdir ec2debian
wget http://github.com/tomheady/ec2debian/tarball/master --no-check-certificate -O - | tar --strip-components 1 -xzvf - -C ec2debian

Step 3: Install and configure the base OS

INSTALL_ARCH need to be amd64 or i386, EC2_ARCH needs to be x86_64 or i386.

INSTALL_ARCH=amd64
EC2_ARCH=x86_64
debootstrap --arch ${INSTALL_ARCH} squeeze chroot/ http://ftp.us.debian.org/debian

Having the same devices is required for when we install grub, so lets link the host OS /dev to the chroot's /dev

rm -r chroot/dev
mkdir -p chroot/dev
mount --bind /dev chroot/dev

Now copy over the customized configuration files:

mkdir -p chroot/etc/grub.d/

cp ec2debian/src/root/etc/{fstab,hosts,rc.local} chroot/etc/
cp ec2debian/src/root/etc/apt/sources.list       chroot/etc/apt/
cp ec2debian/src/root/etc/network/interfaces     chroot/etc/network/
cp ec2debian/src/root/usr/local/bin/*            chroot/usr/local/bin/
cp ec2debian/src/root/etc/ssh/sshd_config        chroot/root/
cp ec2debian/src/root/etc/grub.d/40_custom       chroot/root/

chroot into the new image and do some mounts

INSTALL_ARCH=$INSTALL_ARCH chroot chroot/
mount /proc
mount /sys
mount -t devpts none /dev/pts

update the packages inside our image

apt-get update

install and configure locales. en_US.UTF8 will be generated, and used as default. (thanks Boris for the pointers)

apt-get install -y locales
echo en_US.UTF-8 UTF-8 > /etc/locale.gen
dpkg-reconfigure --priority=critical locales

Now upgrade the system, remove some dhcp clients that cause problems

apt-get -y dist-upgrade
apt-get -y remove --purge isc-dhcp-client isc-dhcp-common dhcp3-client

Install some required packages

declare -A debian_kernels=( ["amd64"]="linux-image-xen-amd64" ["i386"]="linux-image-xen-686" )
DEBIAN_KERNEL="${debian_kernels[${INSTALL_ARCH}]}"
apt-get install -y openssh-server grub less locate curl file dhcpcd resolvconf ${DEBIAN_KERNEL}

When grub prompts for "Linux command line:" you can leave it blank.

When grub prompts for "GRUB install devices:", do not select a disk, and tell it "Yes" when asked to "Continue without installing GRUB?".

pvgrub looks for /boot/grub/menu.lst and grub2 only generates /boot/grub/grub.cfg, so we link it.

ln -s /boot/grub/grub.cfg /boot/grub/menu.lst
mv /root/40_custom /etc/grub.d/

We don't really want a grub2 configuration, so we disable all the default configs, and enable our custom one which generates an old style config. We do this so that we can still boot the latest kernel when it is upgraded.

chmod -x /etc/grub.d/*
chmod +x /etc/grub.d/40_custom
update-grub

Now that openssh-server is installed, move the config file into place

mv /root/sshd_config /etc/ssh/

Inside Xen, CMOS clock is irrelevant, so we disable it

update-rc.d -f hwclock.sh remove
update-rc.d -f hwclockfirst.sh remove

cleanup our image

apt-get autoremove --purge
apt-get clean
apt-get autoclean

rm -f /root/.ssh/authorized_keys /etc/hostname
rm -rf /var/log/*.gz /var/log/{bootstrap,dpkg}.log /var/cache/apt/*.bin /var/lib/apt/lists 
rm -rf /tmp/*
mkdir -p /var/lib/apt/lists/partial

umount /proc
umount /sys
umount /dev/pts

exit

# this gets written when we exit, so get rid of it now
rm chroot/root/.bash_history
touch chroot/root/.bash_history

umount chroot/dev
umount chroot/

Step 4: create EBS AMI

We now have a good base image, let's create our EBS AMI. This is done by taking a snapshot of our disk image and then registering it.

# detaching is optional
DESCRIPTION="Debian 6.0 Squeeze ${EC2_ARCH} image"
ec2-detach-volume ${BUILD_VOLUME} --instance ${BUILD_INSTANCE_ID} --device /dev/sdf --region ${EC2_REGION}
SNAPSHOT=`ec2-create-snapshot --description "${DESCRIPTION}" ${BUILD_VOLUME} --region ${EC2_REGION} | awk '{print $2}'`

declare -A kernels=( ["us-east-1_x86_64"]="aki-427d952b" ["us-west-1_x86_64"]="aki-9ba0f1de" ["eu-west-1_x86_64"]="aki-4feec43b" ["ap-southeast-1_x86_64"]="aki-11d5aa43" ["ap-northeast-1_x86_64"]="aki-d409a2d5" ["us-west-2_x86_64"]="aki-98e26fa8" ["us-east-1_i386"]="aki-407d9529" ["us-west-1_i386"]="aki-99a0f1dc" ["eu-west-1_i386"]="aki-4deec439" ["ap-southeast-1_i386"]="aki-13d5aa41" ["ap-northeast-1_i386"]="aki-d209a2d3" ["us-west-2_i386"]="aki-c2e26ff2" )
KERNEL="${kernels[${EC2_REGION}_${EC2_ARCH}]}"
NAME=debian-6.0-squeeze-base-${INSTALL_ARCH}-`date "+%Y%m%d"`

Wait for the snapshot to be complete, then register it.

ec2-describe-snapshots ${SNAPSHOT} --region ${EC2_REGION}
ec2-register --architecture=${EC2_ARCH} --name ${NAME} --description "${DESCRIPTION}" --kernel ${KERNEL} --snapshot ${SNAPSHOT} --region ${EC2_REGION}

You should now have a EBS backed ami that boots the debian kernel.

Something went wrong with that request. Please try again.