Monday, August 13, 2012

Setting up Ubuntu on Ubuntu under KVM

This an initial installment on setting up and running multiple virtualised operating systems under Ubuntu on my home AMD based desktop machine.
Why do I want to do this?
  • I've used VMWare and Solaris 10 Zones (and some storage virtualisation on NetApp arrays) over the years but wanted to try out the state of the art in virtualisation in the x86 space
  • I have a project in mind that will likely be deployed into a multi-tier environment and I'd like an easy way to emulate this without buying more  hardware.
  • There are other things that can be tried out in a virtualised multi-host environment, including automated deployment in distributed environments and other fun activities.
  • Testing on multiple platforms/distributions should also be possible if the right guest operating systems are created
  • To get experience in managing virtualised environments - ie creating golden images, managing clones and overlays, starting up and shutting down groups of virtual hosts comprising an integrated system.
  • To determine how to perform configuration management of virtual OS images.
  • I wonder whether there is general value in running the majority of my computing out of a virtualised environment? If I blow something up, or something blows my system up, it's always nice to be able to revert to a previous snapshot of your environment without the time and hassle of going through a full reinstall. Since you can migrate running virtualised systems between hosts, it makes sense that you get a portable set of host(s) to put on a USB stick and take with you wherever you go. What would the limitations be, if any?
Presumably I'll get to some, all or more than the above points in separate posts.

Also, there are a number of different technologies to investigate (Amazon EC2, VMware, Xen, Parallels, LXC, VirtualBox, KVM and others) but I won't get through all of them, but rather focus on those that are non-commercial/FOSS, will probably be of most relevance to my project and available on my home hardware and OSes. So I'll start with KVM.


There are some official instructions for KVM here, but I've sourced information from a range of pages on the 'net.

To determine hardware support we need to see if the CPU on the machine supports the required instructions via:


egrep "flags.*:.*(svm|vmx)" /proc/cpuinfo

If anything prints from this command then the CPU provides the necessary support - but this doesn't imply you have set your BIOS to enable it. Check this now (probably under "Advanced CMOS Settings" or similar), or you will see strange results creating and starting images in the steps that follow.


There are also some software pre-requisites. KVM is already in the Linux kernel mainline from 2.6.25+. My desktop machine is on 3.2.x so should be fine for the kernel mode support.

We also need the user space components. You can get these via the Ubuntu Software Centre or:

sudo apt-get install qemu-kvm

This installs a number of packages, and gives you access to a number of command line tools:

kvm, kvm_stat, qemu-ga, qemu-i386, qemu-io, qemu-system-i386, qemu-system-x86_64, qemu-x86_64


From this point there are two ways to create the image:
  1. Build one from scratch (using ubuntu-vm-builder); or
  2. Build one from an ISO


Building an Ubuntu guest OS using ubuntu-vm-builder

Building an Ubuntu guest OS image from scratch  using ubuntu-vm-builder requires a package to be installed on the host where you will do the build.

sudo apt-get install ubuntu-vm-builder

Then you run ubuntu-vm-builder to do the work for you. This is great, because it means you can keep the creation scripts under some source code control system to be able to recreate an image exactly, although note that the process does take some time since the tool pulls packages across the network to build the image. I had a few attempts at building images until I got the options right.


There are some advanced options which I've reproduced from here to show how you can provide quite detailed image build instructions:

ubuntu-vm-builder kvm hardy \
                  --domain newvm \
                  --dest newvm \
                  --arch i386 \
                  --hostname hostnameformyvm \
                  --mem 256 \
                  --user john \
                  --pass doe \
                  --ip 192.168.0.12 \
                  --mask 255.255.255.0 \
                  --net 192.168.0.0 \
                  --bcast 192.168.0.255 \
                  --gw 192.168.0.1 \
                  --dns 192.168.0.1 \
                  --mirror http://archive.localubuntumirror.net/ubuntu \
                  --components main,universe \
                  --addpkg acpid \ 
                  --addpkg vim \
                  --addpkg openssh-server \
                  --addpkg avahi-daemon \
                  --libvirt qemu:///system ;

For my image, I eventually went with the below to get a headless server. If you want a desktop, you can add --addpkg ubuntu-desktop to the line below. Alternatively, you can connect to the guest OS later and simply run from within the guest followed by a restart (which you can just do with shutdown from within the guest).

sudo apt-get install ubuntu-desktop
The above worked out of the box for me.

gsw@goat:/media/Data/KVM$ time sudo ubuntu-vm-builder kvm precise --mem 256 --domain vm-test1 --dest vm-test1 --hostname vm-test1 --user test1 --pass test1 --components main,universe,restricted --addpkg acpid --addpkg vim --addpkg openssh-server --addpkg avahi-daemon --libvirt qemu:///system
[sudo] password for gsw:
2012-08-13 01:12:08,664 INFO    : Calling hook: preflight_check
2012-08-13 01:12:08,675 INFO    : Calling hook: set_defaults
2012-08-13 01:12:08,676 INFO    : Calling hook: bootstrap
2012-08-13 01:19:38,737 INFO    : Calling hook: configure_os
Extracting templates from packages: 100%
2012-08-13 01:22:19,034 INFO    : Updating certificates in /etc/ssl/certs... 152 added, 0 removed; done.
2012-08-13 01:22:19,036 INFO    : Running hooks in /etc/ca-certificates/update.d....done.
2012-08-13 01:22:19,225 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-08-13 01:22:19,781 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-08-13 01:22:20,008 INFO    : invoke-rc.d: policy-rc.d denied execution of force-reload.
2012-08-13 01:22:20,034 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-08-13 01:22:20,461 INFO    : Creating SSH2 RSA key; this may take some time ...
2012-08-13 01:22:20,589 INFO    : Creating SSH2 DSA key; this may take some time ...
2012-08-13 01:22:20,600 INFO    : Creating SSH2 ECDSA key; this may take some time ...
2012-08-13 01:22:20,748 INFO    : invoke-rc.d: policy-rc.d denied execution of stop.
2012-08-13 01:22:20,750 INFO    :
2012-08-13 01:22:20,750 INFO    : Warning: Fake initctl called, doing nothing
2012-08-13 01:22:20,751 INFO    :
2012-08-13 01:22:20,752 INFO    : Warning: Fake initctl called, doing nothing
2012-08-13 01:22:22,407 INFO    :
2012-08-13 01:22:22,408 INFO    : Current default time zone: 'Etc/UTC'
2012-08-13 01:22:22,414 INFO    : Local time is now:      Sun Aug 12 15:22:22 UTC 2012.
2012-08-13 01:22:22,414 INFO    : Universal Time is now:  Sun Aug 12 15:22:22 UTC 2012.
2012-08-13 01:22:22,415 INFO    :
2012-08-13 01:22:52,282 INFO    : gpg: key 437D05B5: "Ubuntu Archive Automatic Signing Key " not changed
2012-08-13 01:22:52,288 INFO    : gpg: key FBB75451: "Ubuntu CD Image Automatic Signing Key " not changed
2012-08-13 01:22:52,288 INFO    : gpg: Total number processed: 2
2012-08-13 01:22:52,289 INFO    : gpg:              unchanged: 2
2012-08-13 01:22:53,104 INFO    : invoke-rc.d: policy-rc.d denied execution of stop.
2012-08-13 01:22:54,835 INFO    : invoke-rc.d: policy-rc.d denied execution of stop.
2012-08-13 01:22:55,164 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-08-13 01:22:55,411 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-08-13 01:22:55,578 INFO    : invoke-rc.d: policy-rc.d denied execution of restart.
2012-08-13 01:22:56,133 INFO    : invoke-rc.d: policy-rc.d denied execution of start.
2012-08-13 01:23:04,897 INFO    : Cleaning up
2012-08-13 01:23:04,898 INFO    : Calling hook: preflight_check
2012-08-13 01:23:05,743 INFO    : Calling hook: configure_networking
2012-08-13 01:23:05,775 INFO    : Calling hook: configure_mounting
2012-08-13 01:23:05,780 INFO    : Calling hook: mount_partitions
2012-08-13 01:23:05,780 INFO    : Mounting target filesystems
2012-08-13 01:23:05,780 INFO    : Creating disk image: "/tmp/tmpaHg8oh" of size: 5120MB
2012-08-13 01:23:05,829 INFO    : Adding partition table to disk image: /tmp/tmpaHg8oh
2012-08-13 01:23:06,260 INFO    : Adding type 4 partition to disk image: /tmp/tmpaHg8oh
2012-08-13 01:23:06,260 INFO    : Partition at beginning of disk - reserving first cylinder
2012-08-13 01:23:06,603 INFO    : Adding type 3 partition to disk image: /tmp/tmpaHg8oh
2012-08-13 01:23:06,614 INFO    : [0] ../../libparted/filesys.c:148 (ped_file_system_type_get): File system alias linux-swap(new) is deprecated
2012-08-13 01:23:06,947 INFO    : Creating loop devices corresponding to the created partitions
2012-08-13 01:23:06,963 INFO    : Creating file systems
2012-08-13 01:23:06,972 INFO    : mke2fs 1.42 (29-Nov-2011)
2012-08-13 01:23:07,607 INFO    : mkswap: /dev/mapper/loop0p2: warning: don't erase bootbits sectors
2012-08-13 01:23:07,608 INFO    :         on whole disk. Use -f to force.
2012-08-13 01:23:11,430 INFO    : Calling hook: install_bootloader
2012-08-13 01:23:32,284 INFO    : Removing update-grub hooks from /etc/kernel-img.conf in favour of
2012-08-13 01:23:32,284 INFO    : /etc/kernel/ hooks.
2012-08-13 01:23:32,400 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-08-13 01:23:32,474 INFO    : Searching for default file ... Generating /boot/grub/default file and setting the default boot entry to 0
2012-08-13 01:23:32,477 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-08-13 01:23:32,487 INFO    : Testing for an existing GRUB menu.lst file ...
2012-08-13 01:23:32,488 INFO    :
2012-08-13 01:23:32,488 INFO    : Could not find /boot/grub/menu.lst file. Would you like /boot/grub/menu.lst generated for you? (y/N) /usr/sbin/update-grub: line 1094: read: read error: 0: Bad file descriptor
2012-08-13 01:23:33,224 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-08-13 01:23:33,298 INFO    : Searching for default file ... found: /boot/grub/default
2012-08-13 01:23:33,302 INFO    : Testing for an existing GRUB menu.lst file ...
2012-08-13 01:23:33,302 INFO    :
2012-08-13 01:23:33,303 INFO    : Could not find /boot/grub/menu.lst file.
2012-08-13 01:23:33,303 INFO    : Generating /boot/grub/menu.lst
2012-08-13 01:23:33,426 INFO    : Searching for splash image ... none found, skipping ...
2012-08-13 01:23:33,688 INFO    : grep: /boot/config*: No such file or directory
2012-08-13 01:23:33,851 INFO    : Updating /boot/grub/menu.lst ... done
2012-08-13 01:23:33,851 INFO    :
2012-08-13 01:23:34,060 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-08-13 01:23:34,130 INFO    : Searching for default file ... found: /boot/grub/default
2012-08-13 01:23:34,140 INFO    : Testing for an existing GRUB menu.lst file ... found: /boot/grub/menu.lst
2012-08-13 01:23:34,366 INFO    : Searching for splash image ... none found, skipping ...
2012-08-13 01:23:34,405 INFO    : grep: /boot/config*: No such file or directory
2012-08-13 01:23:34,584 INFO    : Updating /boot/grub/menu.lst ... done
2012-08-13 01:23:34,584 INFO    :
2012-08-13 01:23:34,638 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-08-13 01:23:34,653 INFO    : Calling hook: install_kernel
2012-08-13 01:25:56,510 INFO    : Done.
2012-08-13 01:26:00,092 INFO    : Running depmod.
2012-08-13 01:26:00,152 INFO    : update-initramfs: deferring update (hook will be called later)
2012-08-13 01:26:00,160 INFO    : Examining /etc/kernel/postinst.d.
2012-08-13 01:26:00,161 INFO    : run-parts: executing /etc/kernel/postinst.d/initramfs-tools 3.2.0-29-virtual /boot/vmlinuz-3.2.0-29-virtual
2012-08-13 01:26:00,163 INFO    : update-initramfs: Generating /boot/initrd.img-3.2.0-29-virtual
2012-08-13 01:26:03,765 INFO    : run-parts: executing /etc/kernel/postinst.d/zz-update-grub 3.2.0-29-virtual /boot/vmlinuz-3.2.0-29-virtual
2012-08-13 01:26:03,888 INFO    : Searching for GRUB installation directory ... found: /boot/grub
2012-08-13 01:26:03,952 INFO    : Searching for default file ... found: /boot/grub/default
2012-08-13 01:26:03,963 INFO    : Testing for an existing GRUB menu.lst file ... found: /boot/grub/menu.lst
2012-08-13 01:26:04,184 INFO    : Searching for splash image ... none found, skipping ...
2012-08-13 01:26:04,296 INFO    : Found kernel: /boot/vmlinuz-3.2.0-29-virtual
2012-08-13 01:26:04,514 INFO    : Replacing config file /run/grub/menu.lst with new version
2012-08-13 01:26:04,564 INFO    : Updating /boot/grub/menu.lst ... done
2012-08-13 01:26:04,564 INFO    :
2012-08-13 01:26:05,059 INFO    : Calling hook: post_install
2012-08-13 01:26:05,060 INFO    : Calling hook: unmount_partitions
2012-08-13 01:26:05,062 INFO    : Unmounting target filesystem
2012-08-13 01:26:08,404 INFO    : Calling hook: convert
2012-08-13 01:26:08,404 INFO    : Converting /tmp/tmpaHg8oh to qcow2, format vm-test1/tmpaHg8oh.qcow2
2012-08-13 01:26:36,008 INFO    : Calling hook: fix_ownership
2012-08-13 01:26:36,010 INFO    : Calling hook: deploy

real    14m32.066s
user    1m4.068s
sys    0m36.362s
From the output of the time command above you can see that there is a bit of time spent creating each image. Perhaps creating a local mirror of the relevant bits of Precise would yield much faster image build times if this is something you will come to do a lot.

After including the desktop package here's what you end up with:

gsw@goat:/media/Data/KVM$ ls -al vm-test1/
total 3453704
drwx------ 1 gsw gsw          0 Aug 13 01:26 .
drwx------ 1 gsw gsw          0 Aug 13 01:26 ..
-rw------- 1 gsw gsw 3536715776 Aug 13 21:00 tmpaHg8oh.qcow2

Starting it is as easy as:

kvm -m 256 -smp 1 -drive file=vm-test1/tmpaHg8oh.qcow2 "$@"

The screen shot at the top of this post shows the end result after logging in using the test1 credentials.

Hardware specs

Some posts will reference this info, so I've put it in one spot. It's a couple of years old now but here are the machine and host OS specs:

gsw@goat:~$ uname -a
Linux goat 3.2.0-27-generic #43-Ubuntu SMP Fri Jul 6 14:25:57 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Memory: 8GB
Processor: AMD Phenom II X6 1090T (hex core), 64bit
OS: Ubuntu 12.04 LTS/Windows 7 Home Premium (Dual boot w/ GRUB)
There is also an SSD boot drive and 1TB DAS SATA storage.

Saturday, August 11, 2012

Hardwood table

In January 2010 I set myself a summer project. Having spent a lot of time working in IT I felt I needed something a little more hands on so determined to do some wood working. This is the result, posted about 2 years after the fact.

Like any good project, it started with a plan. Or rather two rough sketches.



I then went down to a local timber recyclers (Urban Salvage) to see what stock might work. All I really knew was that I wanted a nice native hardwood but beyond that new that I'd just have to work with whatever the recyclers had on hand. I ended up picking up a load of old Blackbutt floorboards and joists which I had them cut onsite to fit into my station wagon. This is the raw timber at home.


In an apartment there isn't much space to work so I made use of our small outdoor patio area for a few weekends until the project was completed. Wood glue ("Liquid Nails") was used to fix the pieces of the table top. A couple of 4m tension straps (the sort you use on a trailer to hold down a load) were used to apply pressure to the boards whilst the glue cured. The pine batons and G-clamps were used to prevent the boards from concertinaing whilst the load was applied by the straps. The boards were fixed and set in twos before assembling and gluing all four together.

 

The large tabletop area was difficult to work in a small space so an improvised workbench was created on the floor on some structural pine.

Masking tape (see leading corner) helped to prevent the power saw from damaging the external edges of the final piece. Note also that the table top is upside down at this point.
This shot shows the legs being prepared for cutting. The masking tape assists in keeping the pieces aligned and importantly the lengths even.
 Getting the straight edge (or in this case the spirit level) at right angles is critical and can take some time to get finessed. Despite the age of this timber one can also see that the pieces are not straight with respect to one another.
  

 The underside of the table top after trimming and the first two legs.
 
Preparing the second legs. More clamps are better, although G-clamps are time consuming to operate but provide a robust grip. Chocks are used here to compensate for my under-investment in G-clamps.



 
Again the baton alignment and masking tape help ensure a nice, clean cut.





A mock-up of the final piece can be useful to visualise the end result. In this case, the orientation of the rail (thin-edge horizontal) was being assessed.


G-clamps again came in handy to mock-up the final table configuration despite none of the critical joins having been cut. The chair provided proof positive that the dimensions were indeed correct.

 

A mix of the recycled timber and some spare pine provided a realistic idea of how the final piece might come to look since the dimensions more or less matched.


I had no experience with a router before I purchased this one so made some simple practice cuts on some pine scraps that were lying around. It quickly became apparent that a simple jig was required to ensure that the router was restricted to only being able to remove material from the required locations. This jig has the obvious shortcoming that it needs to be recalibrated for each workpiece, but it nevertheless served its purpose for getting some practice in before moving on to the final hardwood pieces.

 
As a step up from the simple jig in the previous slide I constructed the above to ensure the router didn't wander from the marked area on the hardwood offcut I was using to practice preparing the mortis end of the join.

The wood marking gauge lines can be seen in the wood here and the jig has done a pretty good job of keeping the router in the required area. It could have used a little extra length and about half a milimeter down one side to reduce manual adjustments with a hammer and chisel later on.

  
This is the final mortis and tennon joint made from off-cuts of Black Butt. Again, this was a practice piece using the end materials as the pine used during the first trial is in contrast extremely soft.

Some manual work with the chisel got these pieces to fit snugly after the bulk of the work was done with the router. I was relieved that these had come out square and flush, but I'd also invested quite some time in setting things up correctly so this would happen.
 

A macro shot showing the spacing between the tenon cheek and mortis.


Legs all marked and ready for the router.


Legs all routed and ready for chiselling. As you can see from the floor in the background this process creates a lot of sawdust, seemingly more than you might expect from the volume removed from the legs.
 

A simple jig was prepared to prepare mortis and tenon joints with a router. Close inspection will show some feint markings in the wood made using a traditional wood gauge. These marks indicate where the cuts are to be made.


Part of the table frame after the final cuts had been made.


This shot shows the completed pieces of the table, four legs, two long rails and 2 short rails.


Each leg was routed out using a home-made jig and hand-chiselled to make it square. Note again the feint etchings in the wood showing where the wood guage had been applied to mark out the cutting area. In this shot the square end had been chiselled out, the rounded edge is the result of routing alone.


 Finishing was performed with this orbital (finishing) sander. The machine was used with 80 then 120 grit paper, with a final hand sanding at 600 and 800 grit wet and dry silicon carbide paper.


A mock-up of a mortis and tenon joint was prepared prior to cutting up the 'real' timber. This practice piece was finished using French polish, mixed by hand from garnet shellac flakes. The holes were filled with wax. A piece of the real, unfinished timber sits alongside for contrast.


More French polish on a practice piece against a fully sanded but otherwise untreated piece of Black Butt.


A practice piece (left) treated with Danish/Scandinavian Oil, with the piece on the right sanded down to 800 grit and a final wet cloth applied to remove dust and raise the grain.


My father's hand plane was used to remove the machined groove in the timber which was there at the time of purchase. Disassembly and blade sharpening were required before this tool operated efficiently. The sheen of the Danish/Scandinavian-oiled surface can be seen in the table top.


This is so old-school but I couldn't help taking this shot! It will probably remind many of their father's and grand father's workshops.

The finished tabletop after two coats of Scandinavian Oil. The product used here has a small amount of urethane added to achieve a satin finish. The major knot and other holes in the final surface were filed using wax prior to oiling.


The table required indoor assembly due to the constrained dimensions of the doorways in our abode. The ends are glued but the brackets can be unscrewed to allow the long rails of the frame to be removed and the table taken outside again.


The frame and tabletop united in the same room for the first time.


The final piece assembled in the dining room.


Black butt is suprisingly hard hardwood. My basic home handyman drill shredded a drill bit trying to drill small holes required for the frame. I would encourage punters to use a drill with a manual chuck as this provides far better grip on the drill bit itself and won't leave bits stuck in the wood.
 

The finished product in place with some very outdated computer equipment.