Building JeOS images from scratch on Ubuntu

Creating VM templates from scratch is pretty simple. There is no need to download a JeOS ISO anymore since we can use vmbuilder to build a pre-configured JeOS image ourself. Moreover the the last available JeOS image is that of Hardy (8.04LTS).

Just a single command does the job (yes, its as simple as that). I ran this on my laptop running Ubuntu 11.10:

sudo vmbuilder kvm ubuntu --verbose --dest /srv/kvm/yamini/images --suite oneiric --flavour virtual --arch i386 -o --libvirt qemu:///system --hostname glassfish --part vmbuilder.partition --user cloud --name Cloud --pass cloud123 --addpkg wget --addpkg openssh-server --addpkg unzip --addpkg unattended-upgrades --addpkg acpid 

vmbuilder.partition:
root 1024

It takes about 20+ minutes to create a qow image. Sample output:

$ sh ubuntu.sh 
2012-01-19 21:16:19,309 INFO    : Calling hook: preflight_check
2012-01-19 21:16:19,380 INFO    : Calling hook: set_defaults
2012-01-19 21:16:19,381 INFO    : Calling hook: bootstrap
2012-01-19 21:29:58,681 INFO    : Calling hook: configure_os
2012-01-19 21:33:32,313 INFO    : Updating certificates in /etc/ssl/certs... WARNING: Skipping duplicate certificate cert_igca_rsa.pem
2012-01-19 21:33:32,317 INFO    : WARNING: Skipping duplicate certificate cert_igca_rsa.pem
2012-01-19 21:33:32,629 INFO    : 156 added, 0 removed; done.
2012-01-19 21:33:32,631 INFO    : Running hooks in /etc/ca-certificates/update.d....done.
2012-01-19 21:33:33,240 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-01-19 21:33:33,766 INFO    : Creating SSH2 RSA key; this may take some time ...
2012-01-19 21:33:36,392 INFO    : Creating SSH2 DSA key; this may take some time ...
2012-01-19 21:33:36,399 INFO    : Creating SSH2 ECDSA key; this may take some time ...
2012-01-19 21:33:36,550 INFO    : invoke-rc.d: policy-rc.d denied execution of stop.
2012-01-19 21:33:36,552 INFO    : 
2012-01-19 21:33:36,553 INFO    : Warning: Fake initctl called, doing nothing
2012-01-19 21:33:36,555 INFO    : 
2012-01-19 21:33:36,556 INFO    : Warning: Fake initctl called, doing nothing
2012-01-19 21:33:36,781 INFO    : update-rc.d: warning: unattended-upgrades start runlevel arguments (2 3 4 5) do not match LSB Default-Start values (none)
2012-01-19 21:33:36,781 INFO    : update-rc.d: warning: unattended-upgrades stop runlevel arguments (0 1 6) do not match LSB Default-Stop values (0 6)
2012-01-19 21:33:36,793 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-01-19 21:33:38,661 INFO    : 
2012-01-19 21:33:38,662 INFO    : Current default time zone: 'Etc/UTC'
2012-01-19 21:33:38,664 INFO    : Local time is now:      Thu Jan 19 16:03:38 UTC 2012.
2012-01-19 21:33:38,665 INFO    : Universal Time is now:  Thu Jan 19 16:03:38 UTC 2012.
2012-01-19 21:33:38,665 INFO    : 
2012-01-19 21:34:06,682 INFO    : 
2012-01-19 21:34:06,683 INFO    : Current default time zone: 'Etc/UTC'
2012-01-19 21:34:06,685 INFO    : Local time is now:      Thu Jan 19 16:04:06 UTC 2012.
2012-01-19 21:34:06,685 INFO    : Universal Time is now:  Thu Jan 19 16:04:06 UTC 2012.
2012-01-19 21:34:06,685 INFO    : Run 'dpkg-reconfigure tzdata' if you wish to change it.
2012-01-19 21:34:06,686 INFO    : 
2012-01-19 21:34:22,702 INFO    : Cleaning up
2012-01-19 21:34:22,704 INFO    : Calling hook: preflight_check
2012-01-19 21:34:24,006 INFO    : Calling hook: configure_networking
2012-01-19 21:34:24,046 INFO    : Calling hook: configure_mounting
2012-01-19 21:34:24,052 INFO    : Calling hook: mount_partitions
2012-01-19 21:34:24,053 INFO    : Mounting target filesystems
2012-01-19 21:34:24,053 INFO    : Creating disk image: "/tmp/tmp1c0Rfn" of size: 1025MB
2012-01-19 21:34:24,097 INFO    : Adding partition table to disk image: /tmp/tmp1c0Rfn
2012-01-19 21:34:24,345 INFO    : Adding type 4 partition to disk image: /tmp/tmp1c0Rfn
2012-01-19 21:34:24,346 INFO    : Partition at beginning of disk - reserving first cylinder
2012-01-19 21:34:24,445 INFO    : Creating loop devices corresponding to the created partitions
2012-01-19 21:34:24,495 INFO    : Creating file systems
2012-01-19 21:34:24,598 INFO    : mke2fs 1.41.14 (22-Dec-2010)
2012-01-19 21:34:40,881 INFO    : Calling hook: install_bootloader
2012-01-19 21:35:10,760 INFO    : Removing update-grub hooks from /etc/kernel-img.conf in favour of
2012-01-19 21:35:10,760 INFO    : /etc/kernel/ hooks.
2012-01-19 21:35:14,207 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-01-19 21:35:14,249 INFO    : Searching for default file ... Generating /boot/grub/default file and setting the default boot entry to 0
2012-01-19 21:35:14,250 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-01-19 21:35:14,254 INFO    : Testing for an existing GRUB menu.lst file ... 
2012-01-19 21:35:14,254 INFO    : 
2012-01-19 21:35:14,254 INFO    : Could not find /boot/grub/menu.lst file. 
2012-01-19 21:35:14,255 INFO    : Generating /boot/grub/menu.lst
2012-01-19 21:35:14,314 INFO    : Searching for splash image ... none found, skipping ...
2012-01-19 21:35:14,448 INFO    : grep: /boot/config*: No such file or directory
2012-01-19 21:35:14,534 INFO    : Updating /boot/grub/menu.lst ... done
2012-01-19 21:35:14,535 INFO    : 
2012-01-19 21:35:14,698 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-01-19 21:35:14,743 INFO    : Searching for default file ... found: /boot/grub/default
2012-01-19 21:35:14,744 INFO    : Testing for an existing GRUB menu.lst file ... found: /boot/grub/menu.lst
2012-01-19 21:35:14,845 INFO    : Searching for splash image ... none found, skipping ...
2012-01-19 21:35:14,876 INFO    : grep: /boot/config*: No such file or directory
2012-01-19 21:35:14,960 INFO    : Updating /boot/grub/menu.lst ... done
2012-01-19 21:35:14,961 INFO    : 
2012-01-19 21:35:15,016 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-01-19 21:35:15,024 INFO    : Calling hook: install_kernel
2012-01-19 21:40:39,581 INFO    : Done.
2012-01-19 21:40:44,292 INFO    : Running depmod.
2012-01-19 21:40:44,371 INFO    : update-initramfs: deferring update (hook will be called later)
2012-01-19 21:40:44,376 INFO    : Examining /etc/kernel/postinst.d.
2012-01-19 21:40:44,377 INFO    : run-parts: executing /etc/kernel/postinst.d/initramfs-tools 3.0.0-14-virtual /boot/vmlinuz-3.0.0-14-virtual
2012-01-19 21:40:44,380 INFO    : update-initramfs: Generating /boot/initrd.img-3.0.0-14-virtual
2012-01-19 21:40:47,687 INFO    : run-parts: executing /etc/kernel/postinst.d/zz-update-grub 3.0.0-14-virtual /boot/vmlinuz-3.0.0-14-virtual
2012-01-19 21:40:47,782 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-01-19 21:40:47,828 INFO    : Searching for default file ... found: /boot/grub/default
2012-01-19 21:40:47,829 INFO    : Testing for an existing GRUB menu.lst file ... found: /boot/grub/menu.lst
2012-01-19 21:40:47,926 INFO    : Searching for splash image ... none found, skipping ...
2012-01-19 21:40:47,985 INFO    : Found kernel: /boot/vmlinuz-3.0.0-14-virtual
2012-01-19 21:40:48,082 INFO    : Replacing config file /run/grub/menu.lst with new version
2012-01-19 21:40:48,103 INFO    : Updating /boot/grub/menu.lst ... done
2012-01-19 21:40:48,103 INFO    : 
2012-01-19 21:40:48,784 INFO    : Calling hook: post_install
2012-01-19 21:40:48,785 INFO    : Calling hook: unmount_partitions
2012-01-19 21:40:48,785 INFO    : Unmounting target filesystem
2012-01-19 21:40:52,172 INFO    : Calling hook: convert
2012-01-19 21:40:52,175 INFO    : Converting /tmp/tmp1c0Rfn to qcow2, format /srv/kvm/yamini/images/tmp1c0Rfn.qcow2
2012-01-19 21:41:06,932 INFO    : Calling hook: fix_ownership
2012-01-19 21:41:06,933 INFO    : Calling hook: deploy
$

VMM (Virtual Machine Manager) will show the newly created VM (named glassfish)

To further customize the VM, login to the VM (cloud/cloud123) and do the following:

  1. Make sure internet is accessible:
    ping glassfish.java.net
    If its not accessible, shutdown the VM, change the NIC settings in VMM to use shared bridge device virbr0 and boot the VM. It should also be ok to use NAT.
  2. Install JDK
    sun-java6-jdk is no longer available in oneiric partner repository, so we will need to pick it up from a private archive:
    sudo apt-get install python-software-properties
    sudo add-apt-repository ppa:ferramroberto/java
    sudo apt-get update
    sudo apt-get install sun-java6-jdk
  3. Install Glassfish bits
    cd /opt
    sudo mkdir glassfishvm
    sudo chmod a+rwx glassfishvm
    cd glassfishvm
    wget http://$das_address:$das_port/glassfish.zip
    unzip glassfish.zip
    rm glassfish.zip
  4. Install glassfish as startup service
    Copy over glassfish script and create service
    sudo chmod a+x glassfish
    sudo update-rc.d glassfish defaults
  5. Clear history
    history -c
  6. Convert the qow to raw image:
    The qcow2 disk format has some decent features like encryption, compression and copy to write support but its growing size is difficult to predict. In addition, the compression and the copy processes make it quite a bit slower than raw disk images. I could not get vmbuilder to generate a raw image directly.
qemu-img convert tmpBWigFM.qcow2 glassfish.img

Caveats:

  1. I tried to speed up the image creation process by using apt-cacher (pass --mirror http://localhost:3142/ubuntu) but apparently apt-cacher doesn't download security packages, so vmbuilder failed. But I found later that there is a --security-mirror=URL option which I haven't tried.
  2. vmbuilder creates the file layout under /tmp/tmp* but does not delete the temp files in case of failure. Delete it manually before running out of space.
  3. vmbuilder deletes all files under the --dest directory, so do not store any other data there.
  4. First time I ran vmbuilder, I ran into "device is busy error". Found that one of the scripts had to be modified as follows to avoid the problem:
    /usr/lib/python2.7/dist-packages/VMBuilder/plugins/ubuntu/dapper.py
        def unmount_dev(self):
            self.context.cancel_cleanup(self.unmount_dev)
            run_cmd('sleep', '10'); // <--- add this line.
            run_cmd('umount', '%s/dev' % self.context.chroot_dir)

    Bug:https://bugs.launchpad.net/ubuntu/+source/vm-builder/+bug/879710