This how to article will go over creating a Amazon Elastic Compute Cloud (EC2) Machine Image (AMI) S3 backed as well as EBS backed. In this particular example we are creating a Centos 6 64bit AMI from beginning to end. I wrote a blog about this topic in 2010 and decided to freshen it up a bit with a CentOS 6 build.
First you will want to hop on a CentOS 6 box you have available so that all the yum commands will work below.
This first step is to setup your basic environment to start building.
cat <<EOT >>/mnt/ec2-image/etc/ssh/sshd_config UseDNS no PermitRootLogin without-password EOT |
Save your X509 certificates in the following directories:
MAKEDEV -d /mnt/ec2-image/dev -x console MAKEDEV -d /mnt/ec2-image/dev -x null MAKEDEV -d /mnt/ec2-image/dev -x zero mount -o bind /dev /mnt/ec2-image/dev mount -o bind /dev/pts /mnt/ec2-image/dev/pts mount -o bind /dev/shm /mnt/ec2-image/dev/shm mount -o bind /proc /mnt/ec2-image/proc mount -o bind /sys /mnt/ec2-image/sys |
cat <<EOT >/mnt/ec2-image/etc/sysconfig/network NETWORKING=yes HOSTNAME=localhost.localdomain EOT |
cat <<EOT >/mnt/ec2-image/etc/sysconfig/network-scripts/ifcfg-eth0 ONBOOT=yes DEVICE=eth0 BOOTPROTO=dhcp NM_CONTROLLED=yes EOT |
This step is to create your disk image and filesystem and file structure.
cat <<EOL > /mnt/ec2-image/boot/grub/grub.conf default=0 timeout=0 title CentOS$RELEASE root (hd0) kernel /boot/vmlinuz ro root=/dev/xvde1 rd_NO_PLYMOUTH selinux=0 console=hvc0 loglvl=all sync_console console_to_ring earlyprintk=xen nomodeset initrd /boot/initramfs EOL |
ln -s /boot/grub/grub.conf /mnt/ec2-image/boot/grub/menu.lst kern=`ls /mnt/ec2-image/boot/vmlin*|awk -F/ '{print $NF}'` kernver=${kern#vmlinuz-} ird=`ls /mnt/ec2-image/boot/initramfs*.img|awk -F/ '{print $NF}'` sed -ie "s/vmlinuz/$kern/" /mnt/ec2-image/boot/grub/grub.conf sed -ie "s/initramfs/$ird/" /mnt/ec2-image/boot/grub/grub.conf |
vi /mnt/ec2-image/etc/init.d/getssh #!/bin/bash # chkconfig: 2345 95 20 # description: getssh # processname: getssh # export PATH=:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. [ -r /etc/sysconfig/network ] && . /etc/sysconfig/network # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 start() { if [ ! -d /root/.ssh ] ; then mkdir -p /root/.ssh chmod 700 /root/.ssh fi # Fetch public key using HTTP /usr/bin/curl -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /tmp/my-key if [ $? -eq 0 ] ; then cat /tmp/my-key >> /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys rm /tmp/my-key fi # or fetch public key using the file in the ephemeral store: if [ -e /mnt/openssh_id.pub ] ; then cat /mnt/openssh_id.pub >> /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys fi } stop() { echo "Nothing to do here" } restart() { stop start } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart) restart ;; *) echo $"Usage: $0 {start|stop}" exit 1 esac exit $? ###END OF SCRIPT |
This step is to create your Yum conf that you will use to install the base OS
/bin/chmod +x /mnt/ec2-image/etc/init.d/getssh /usr/sbin/chroot /mnt/ec2-image /sbin/chkconfig --level 34 getssh on |
yum -c /opt/EC2YUM/yum-ami.conf --installroot=/mnt/ec2-image -y clean packages rm -rf /mnt/ec2-image/root/.bash_history rm -rf /mnt/ec2-image/var/cache/yum rm -rf /mnt/ec2-image/var/lib/yum |
/opt/EC2TOOLS/bin/ec2-describe-images -H --region us-east-1 -x all|grep "pv-grub-hd0" |
This step is to allow root login without password, since you will be using your key
/opt/EC2TOOLS/bin/ec2-bundle-image --image /data/CentOS$RELEASE-$ARCH-base.img --prefix ami-CentOS$RELEASE-$ARCH-base --cert ~/.ec2/amicert.pem --privatekey ~/.ec2/amikey.pem --user awsaccountnumber --destination /data --arch $ARCH |
Create devices so we can use chroot for the image
/opt/EC2TOOLS/bin/ec2-upload-bundle --manifest /data/ami-CentOS$RELEASE-$ARCH-base.manifest.xml --bucket yourbucket --access-key accesskeyhere --secret-key secretkeyhere |
Create network settings
ssh -i yourkey root@yournewinstance |
mkfs.ext4 /dev/xvdj mkdir /mnt/ebs && mount /dev/xvdj /mnt/ebs rsync -avHx / /mnt/ebs rsync -avHx /dev /mnt/ebs sync;sync;sync;sync && umount /mnt/ebs |
Create grub.conf and boot settings so the Amazon Kernel Image can boot into the new Kernel
cat <<EOL > /mnt/ec2-image/boot/grub/grub.conf default=0 timeout=0 title CentOS$RELEASE root (hd0) kernel /boot/vmlinuz ro root=/dev/xvde1 rd_NO_PLYMOUTH selinux=0 console=hvc0 loglvl=all sync_console console_to_ring earlyprintk=xen nomodeset initrd /boot/initramfs EOL |
ln -s /boot/grub/grub.conf /mnt/ec2-image/boot/grub/menu.lst kern=`ls /mnt/ec2-image/boot/vmlin*|awk -F/ '{print $NF}'` kernver=${kern#vmlinuz-} ird=`ls /mnt/ec2-image/boot/initramfs*.img|awk -F/ '{print $NF}'` sed -ie "s/vmlinuz/$kern/" /mnt/ec2-image/boot/grub/grub.conf sed -ie "s/initramfs/$ird/" /mnt/ec2-image/boot/grub/grub.conf |
Create a script that grabs the public key credentials for your root login.
vi /mnt/ec2-image/etc/init.d/getssh #!/bin/bash # chkconfig: 2345 95 20 # description: getssh # processname: getssh # export PATH=:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. [ -r /etc/sysconfig/network ] && . /etc/sysconfig/network # Check that networking is up. [ "${NETWORKING}" = "no" ] && exit 1 start() { if [ ! -d /root/.ssh ] ; then mkdir -p /root/.ssh chmod 700 /root/.ssh fi # Fetch public key using HTTP /usr/bin/curl -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /tmp/my-key if [ $? -eq 0 ] ; then cat /tmp/my-key >> /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys rm /tmp/my-key fi # or fetch public key using the file in the ephemeral store: if [ -e /mnt/openssh_id.pub ] ; then cat /mnt/openssh_id.pub >> /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys fi } stop() { echo "Nothing to do here" } restart() { stop start } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart) restart ;; *) echo $"Usage: $0 {start|stop}" exit 1 esac exit $? ###END OF SCRIPT |
Make your script init ready
/bin/chmod +x /mnt/ec2-image/etc/init.d/getssh /usr/sbin/chroot /mnt/ec2-image /sbin/chkconfig --level 34 getssh on |
Clean up after yourself
yum -c /opt/EC2YUM/yum-ami.conf --installroot=/mnt/ec2-image -y clean packages rm -rf /mnt/ec2-image/root/.bash_history rm -rf /mnt/ec2-image/var/cache/yum rm -rf /mnt/ec2-image/var/lib/yum |
Check for what Amazon AKI’s are available you will need this info when starting your ec2 instance
/opt/EC2TOOLS/bin/ec2-describe-images -H --region us-east-1 -x all|grep "pv-grub-hd0" |
Bundle your new image
/opt/EC2TOOLS/bin/ec2-bundle-image --image /data/CentOS$RELEASE-$ARCH-base.img --prefix ami-CentOS$RELEASE-$ARCH-base --cert ~/.ec2/amicert.pem --privatekey ~/.ec2/amikey.pem --user awsaccountnumber --destination /data --arch $ARCH |
Upload your new image
/opt/EC2TOOLS/bin/ec2-upload-bundle --manifest /data/ami-CentOS$RELEASE-$ARCH-base.manifest.xml --bucket yourbucket --access-key accesskeyhere --secret-key secretkeyhere |
Register your image
I recommend you do this via the Amazon Web Services Management console, under IMAGES->AMIs “Register New AMI” you will just need to enter bucketname/manifest.xml file for your new AMI.
Steps to create a EBS Backed AMI from your S3 Backed Instance. *Only if you want an EBS Backed AMI do these steps
Step 1
Start your newly created EC2 instance
Step 2
Go into the Amazon Web Services Management console and create a Volume at whatever size you choose
Step 3
Attach your Volume to your new running EC2 Instance
Step 4
Login to your new instance
ssh -i yourkey root@yournewinstance |
Step 5
Create your filesystem type in this case EXT4 then make a directory and mount it to the newly formated filesystem. After that we rsync the root of your ec2 instance, then unmount.
mkfs.ext4 /dev/xvdj mkdir /mnt/ebs && mount /dev/xvdj /mnt/ebs rsync -avHx / /mnt/ebs rsync -avHx /dev /mnt/ebs sync;sync;sync;sync && umount /mnt/ebs |
Step 6
Go into the Amazon Web Services Management Console section Volumes and detach the Volume
Step 7
Go into the Amazon Web Services Management Console section Volumes and create a Snapshot of your Volume
Step 8
Go into the Amazon Web Services Management Console section Snapshots and select your new Snapshot and choose “create image” Fill in the name and description and the AWS AKI you chose in my case for us-east-1 I chose aki-08ed0761 for x86_64 bit hd0
Step 9
Start your new EBS backed AMI
Also a great resource for free Realtime AWS uptime data is Systems Watch
I’m trying your instructions (on Debian testing with yum installed) and found what I suspect to be a typo, in the mkdir -p stage, shouldn’t it be:
mkdir -p proc etc dev var var/cache var/log var/lock var/lib/rpm sys
i.e. relative paths for the var/* and var/lib/rpm instead of var/loc/rpm?
Thanks for the correction Amos. You are correct there was a typo, and the paths should be relative. It shouldn’t have effected anything though since the yum half of the instructions create the dir for you. But just the same I will correct the instructions. Thanks.
Hi,
Thanks for the instructions. I followed it to create an image, but after I uploaded it into S3, I was not able to boot it up. The syslog says root disk not found.
I am not clear about the relationship between my ami image, ari image, and aki image or if I need to specify them at all. I tried both aki-427d952b and “default” (whatever that means!), but I did not provide an ari image (left its selection at “default”).
So any insight would be appreciated!
Thanks
yz