Creating an OpenStack Image
Here’s how I create an OpenStack disk image. Everyone has their own tweaks here; the most unusual thing I do is that I don’t use cloud-init, because I don’t want to rely on DHCP; I use OpenStack’s ‘configuration drive’ instead. I think that cloud-init has support for config-drive in its very latest versions, so I may revisit this in future.
A few comments:
- I think that Grub is crazily complicated, requiring too many UUIDs to match up with each other; I use extlinux instread.
- Some techniques inspired by vmdebootstrap
- vmbuilder can only create ubuntu images, but we really want Debian server images to be an option (and RedHat etc)
- Installing a (local) apt-cacher makes our life much more pleasant
- I’ll probably bundle this into a script sometime soon!
The Host Machine
This documentation is for a Debian machine. Either use a real Debian machine, or use a Debian guest image, or install Debian in a guest!
In particular, if you’re using Ubuntu Oneirc, it won’t work until the fix is in for this extlinux bug.
Just use Debian for this!
Pre-reqs
mkdir -p images
cd images
sudo apt-get update
sudo apt-get install --yes debootstrap curl qemu-kvm mbr extlinux parted kpartx
# An apt cache makes subsequent image-building much faster
sudo apt-get install --yes apt-cacher-ng
sudo apt-get upgrade
Image Creation
# Sadly, most of this needs to be done as root..
sudo bash
# Choose your image OS
OS=squeeze
KERNEL=linux-image-2.6-amd64
# Create a (sparse) 8 gig image
dd if=/dev/null bs=1M seek=8192 of=disk.raw
#Create partitions
parted -s disk.raw mklabel msdos
parted -s disk.raw mkpart primary 0% 100%
parted -s disk.raw set 1 boot on
# Install Master Boot Record
install-mbr disk.raw
# Mount the partitions
modprobe dm_mod
kpartx -av disk.raw
# Hopefully it’s loop0p1..
LOOPBACK_PARTITION=/dev/mapper/loop0p1
# Format filesystem
yes | mkfs.ext4 ${LOOPBACK_PARTITION}
# Don’t force a check based on dates
tune2fs -i 0 /dev/mapper/loop0p1
# Mount the disk image
mkdir mnt
mount ${LOOPBACK_PARTITION} mnt/
# Create root partition using debootstrap
http_proxy="http://127.0.0.1:3142" debootstrap \
--include=openssh-server,${KERNEL} ${OS} mnt/
# Prepare for chroot
mount -t proc proc mnt/proc/
# Use chroot to fix up a few things (locales, mostly)
chroot mnt/ apt-get update
chroot mnt/ apt-get install locales
chroot mnt/ locale-gen en_US.utf8
chroot mnt/ /bin/bash -c "DEBIAN_FRONTEND=noninteractive dpkg-reconfigure locales"
# Finishing the image
chroot mnt/ apt-get upgrade
chroot mnt/ apt-get clean
# Remove persistent device names so that eth0 comes up as eth0
rm mnt/etc/udev/rules.d/70-persistent-net.rules
Set up /etc/fstab
PARTITION_UUID=`blkid -o value -s UUID ${LOOPBACK_PARTITION}`
echo -e "# /etc/fstab: static file system information." > mnt/etc/fstab
echo -e "proc\\t/proc\\tproc\\tnodev,noexec,nosuid\\t0\\t0" >> mnt/etc/fstab
echo -e "/dev/sda1\\t/\\text4\\terrors=remount-ro\\t0\\t1" >> mnt/etc/fstab
echo -e "" >> mnt/etc/fstab
# TODO: Swap
#Check it looks good
more mnt/etc/fstab
Use config drive
I highly recommend using config drive. There’s a little init script I contributed which can apply the network configuration from the config drive, located in contrib/openstack-config in the source tree of nova.
# Install the init script for config drive
curl https://raw.github.com/openstack/nova/master/contrib/openstack-config > mnt/etc/init.d/openstack-config
chown root:root mnt/etc/init.d/openstack-config
chmod 755 mnt/etc/init.d/openstack-config
chroot mnt/ /usr/sbin/update-rc.d openstack-config defaults
Set up extlinux
VMLINUZ=`chroot mnt find boot/ -name "vmlinuz-*"`
INITRD=`chroot mnt find boot/ -name "initrd*"`
echo -e "default linux\ntimeout 1\n\nlabel linux\nkernel ${VMLINUZ}\nappend initrd=${INITRD} root=UUID=${PARTITION_UUID} ro quiet" > mnt/extlinux.conf
cat mnt/extlinux.conf
extlinux --install mnt/
Unmount & convert to a qcow image
# Sync and unmount (with paranoid levels of sync-ing)
sync; sleep 2; sync
umount mnt/proc
umount mnt/
sync
kpartx -d disk.raw
sync
# Convert to qcow2 (which means that the raw image size isn’t too important)
rm disk.qcow2
qemu-img convert -f raw -O qcow2 disk.raw disk.qcow2
Upload the image into glance
# We don't need to be root any more...
exit
RAW_SIZE=`cat disk.qcow2 | wc -c`
echo "RAW_SIZE=${RAW_SIZE}"
# Change these parameters to the correct values
export OS_AUTH_USER=`whoami`
export OS_AUTH_KEY="secret"
export OS_TENANT_NAME=privatecloud
export OS_AUTH_URL=http://192.168.191.1:5000/v2.0/
glance add name=DebianSqueeze is_public=True disk_format=qcow2 container_format=bare image_size="${RAW_SIZE}" < disk.qcow2