Debian AMI bootstrap on EC2 with EBS

Today I am going to describe, as detailed as possible, a way how to bootstrap a Debian Squeeze system AMI. I am going to go quite slowly and I am going to base off other work done previously which ill reference in due time. Anyways hands on.

First you got to have your Amazon account which requires to have a valid credit card. Right now there is a free tier available, which gives you the opportunity to try the micro instances for a year. It has limits in processing and transfer but for most effects you can play around with the system without getting charged. Be extra careful though, when you launch an instance as most images are run as t1.small by default and those DO cost.

I am going to base this step-by-step hands on tutorial from an image with id ami-8c7e8de5. It is a Debian Squeeze 64 bit version that mounts over elastic block storage (EBS) rather than on ephemeral storage. (t1.micro instances are not allowed to use ephemeral storage)

We are starting from the console but will continue mostly through command line tools. We pick the t1.micro instance and click next all the way over. It is advised you set a key/pair before hand which will allow you to download a .pem file which will be fed to ssh. If you use a client like putty you will need to convert the .pem to a .ppk using puttygen. You can find an explanation about it here

You verify all your info and launch it!

You switch back to the instances section in the EC2 tab inside the console and find the instance, right click it and connect to it. If it is still booting just wait till it turns green. It will give you a connection link, for me it is ssh -i mapleman.pem

Let's speed up our process and upload our certificate and private key at once. This upload will be done through scp or sftp.

scp -i mapleman.pem pk.pem
scp -i mapleman.pem cert.pem

Alright, what is next, lets make sure we have the latest version of the packages, oh and another small perk. We need to edit our apt sources to include contrib and non-free. We require non-free for the Sun VM because OpenJDK has some issues with the Amazon Tools. You could go the ruby way but that is just a personal choice, I feel right at home with Java.

apt-get update
vi /etc/apt/sources.list
apt-get install sun-java6-jre

This is how your apt.sources.list should look like: deb squeeze main contrib non-free

Ok lets keep going. Lets download the Amazon Tools. We are basically setting up the environment so we can run Amazon commands from our instance and we can also build the chrooted environment, so it is a dual purpose. We also get unzip. duh.

apt-get install unzip

We now go ahead and install the tools:

mkdir /usr/local/ec2


cp -r ec2-ami-tools-1.3-66634/* /usr/local/ec2/
cp -r ec2-api-tools-* /usr/local/ec2/

We need to setup the environment to be able to run these tools properly and to save on typing. :)

export EC2_HOME=/usr/local/ec2
export PATH=$PATH:$EC2_HOME/bin
export JAVA_HOME=/usr

export EC2_PRIVATE_KEY=/root/pk.pem
export EC2_CERT=/root/cert.pem
export AWS_USER_ID=#################
export AWS_ACCESS_KEY_ID=##################
export AWS_SECRET_ACCESS_KEY=########################

Now that you can hopefully, if all goes well, call EC2 commands from the command line lets start with finding your instance id and then creating and attaching a volume to it. Which will be the one that will host your EBS backed instance.


INSTANCE i-29d31247 ami-8c7e8de5 domU-12-31-39-06-76-91.compute-1.internal running mapleman 0 t1.micro 2011-05-19T16:37:42+0000 us-east-1b aki-427d952b

The i-### is the instance ID and us-east-1b is the region we need to create the EBS volume where we will create our AMI.

ec2-create-volume -z us-east-1b -s 8

The system will reply with a volume id in the form vol-##### in my case it was vol-3d218a56.

Now we gotta link our instance with this block device, for that we require our instance ID and our volume ID and we have both.

ec2-attach-volume vol-3d218a56 -i 'i-29d31247' -d '/dev/sdi'

You should be able to realize when it is attached when you can ls /dev/xv* and get in this case /dev/xvdi

Moving on we create a filesystem on the volume, mount it and start installing the base system. This AMI does not include debootstrap so make sure you install that aswell.

mkfs.ext3 -F /dev/xvdi
mount /dev/xvdi /mnt
apt-get install debootstrap
debootstrap --arch=amd64 squeeze /mnt

Lets copy our private key and certificate to the new block device as well as the Amazon tools and chroot to it.

cp cert.pem /mnt/root/
cp pk.pem /mnt/root
cp -r /usr/local/ec2 /mnt/usr/local/ec2
chroot /mnt

Alright we are now in a 'different' system. Lets set up our environment.

Mounting proc and dev and updating our package system. Same issue as before, gotta edit sources.list and add non-free.

mount -t proc none /proc
mount -t devpts none /dev/pts
vi /etc/apt/sources.list
apt-get update

We should install Java again. You might want to copy it before chrooting but that is totally up to you. We also setup our environment variables.

apt-get install sun-java6-jre
export EC2_HOME=/usr/local/ec2
export PATH=$PATH:$EC2_HOME/bin
export JAVA_HOME=/usr

export EC2_PRIVATE_KEY=/root/pk.pem
export EC2_CERT=/root/cert.pem
export AWS_USER_ID=#################
export AWS_ACCESS_KEY_ID=##################
export AWS_SECRET_ACCESS_KEY=########################

In order to avoid more locale spam install them and reconfigure.

apt-get install locales
dpkg-reconfigure locales

Alright lets carry on with preparing /dev filesystem. We are referencing this article heavily. However, we will divert in the end a bit.

First download makedev, then create your devices.

apt-get install makedev

ln -s /sbin/MAKEDEV /dev
cd /dev

MAKEDEV generic
MAKEDEV console

Create an /etc/fstab that looks like this:

/dev/sda1 / ext3 defaults 1 1
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0

Prepare the network like this and delete the hostname

vi /etc/network/interfaces

auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp

rm -rf /etc/hostname

Follow the SSH installation instructions from here

That is start with the section

Installation of ssh client and server

and ending with

exiting chroot

But DONT exit yet!
We need to install an image and grub-legacy for it to boot!

apt-get install grub-legacy
apt-get install xen-linux-system-2.6.32-5-xen-amd64

Now here is where it gets dirty. We follow for starters this blog post. We dive in and modify our copies.

vi /usr/sbin/update-grub

Paste the first section on the top, and comment and add the other part based on a search. After you have done that you can exit chroot, but just for a bit, we still need to do things in the environment.
Copy the modules to the chrooted environment and chroot back, and run a depmod -a for the heck of it.

cp -r /lib/modules/$(uname -r) /mnt/lib/modules/
chroot /mnt
depmod -a

We still need to setup our grub and image kernel properly. We will have to hack more. Edit /var/lib/dpkg/info/linux-image-2.6.32-5-xen-amd64.postinst go all the way to line 799 and comment the section.

if (-d "/etc/kernel/postinst.d") {
print STDERR "Examining /etc/kernel/postinst.d.\n";
# system ("run-parts --verbose --exit-on-error --arg=$version " .
# "--arg=$realimageloc$kimage-$version " .
# "/etc/kernel/postinst.d") &&
# die "Failed to process /etc/kernel/postinst.d";

After that run a reinstall on the kernel image. It will still whine but it won't matter.

apt-get install xen-linux-system-2.6.32-5-xen-amd64 --reinstall

Do this then:

grub-install /
cd /boot/grub

change fd0 line to:

(hd0) /dev/xvda

lets move on:

grub-set-default /dev/xvda
umount /proc
umount /dev/pts

finally copy this and umount:

cp /boot/grub/menu.lst /mnt/boot/grub
umount /dev/xvdi

Now we will check the kernel version we need to boot and with that we will build our own image! and hopefully it will boot :^)

curl http://instance-data/latest/meta-data/kernel-id ; echo


Lets detach our volume and create a snapshot.

ec2-detach-volume vol-3d218a56
ATTACHMENT vol-3d218a56 i-29d31247 /dev/sdi detaching 2011-05-19T17:50:38+0000

ec2-create-snapshot --description "Our Debian snapshot" "vol-3d218a56"
SNAPSHOT snap-49ede326 vol-3d218a56 pending 2011-05-20T22:50:19+0000

And there we go, a snapshot. Final step, creating an image from this snapshot.

ec2-register -a x86_64 -b '/dev/sda1=snap-49ede326:8:false' -n 'debian-x64' -d 'My Debian x64' --kernel="aki-427d952b"
IMAGE ami-3220de5b

This creates the Image we can run. It uses an EBS block of storage based on the data of the snapshot we just created, took a while huh. And uses the kernel we previously got from the meta-data. Now lets run it and hope for the best.

ec2-run-instances ami-3220de5b -t t1.micro -k mapleman -g quick-start-1
INSTANCE i-ad428ec3 ami-3220de5b pending 0 t1.micro

Use your keypair, mine is named mapleman and your security group, mine is named quick-start-1

ssh -i mapleman.pem

The authenticity of host ' (' can't be established.
RSA key fingerprint is 93:6b:61:a4:2a:ac:32:b0:51:3e:d7:93:45:94:19:ef.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ',' (RSA) to the list of known hosts.
Linux (none) 2.6.32-5-xen-amd64 #1 SMP Tue Mar 8 00:01:30 UTC 2011 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@(none):~# ls
cert.pem pk.pem


As you can see the cert.pem and pk.pem are present huh, maybe do a little clean up before snapshotting ! but all in all this has been success!