Building a custom OpenSolaris LiveCD
I've been playing with OpenSolaris lately, and I was finally able to build my own OpenSolaris LiveCD with Hudson, so this is the record of what/how I did it.
There are two ways to read this post; if you are just interested in installing Hudson on a machine, real or virtual, then you can just download the ISO file, boot from the ISO, then run the installer. It will install OpenSolaris and Hudson. For a tool like Hudson, OpenSolaris is a nice platform because I can support fully automated one-click upgrade, build isolation, incremental back ups, etc.
Now if you are interested in learning how you can build your own LiveCD, I hope my record will help you, so read on.
First, install the distribution constructor toolkit:
pfexec pkg install SUNWdistro-const
This tool allows you to define a recipe of a live CD in an XML file, and build an ISO image from this. I used /usr/share/distro_const/slim_cd/slim_cd.xml as the starting point. This file is reasonably well documented (and they have a schema for this in RELAX NG, which I used to work on — Yay!)
Once you change the recipe XML file, you can build an ISO image by running distro_const:
pfexec pfexec distro_const build my.xml
On a fairly new system, this process takes about 30 minutes, and at the end you get /rpool/dc/media/*.iso.
That's the workflow, but beyond that there are a few tips.
Tip1: run your own package mirror
First, distro_const tries to fetch every package from pkg.opensolaris.org, which would be horribly slow, even for me who run this from within Sun's firewall. So it's imperative to have a local package mirror. Incredibly, OpenSolaris doesn't seem to have the equivalent of apt-mirror, a tool that easily creates a package mirror, so I had to do this manually. For this,
I wrote the a shell script:
To use this, create an empty directory (which will be later filled with package cache), then run the pkg.depotd command:
/usr/lib/pkg.depotd -d path/to/workdir -p 10000
Tip2: choosing packages to include
If you are creating a LiveCD image like mine, which intend to mainly include server-side pieces, you don't want to bloat the disk size by adding a lot of packages. So your natural instinct is to find some desktop packages that you can remove.
This proven to be much difficult, mainly because of the lack of a sophisticated dependency mechainsm (again unlike apt, you don't have "recommends"/"suggests" dependencies), and/or a poor packaging of base packages. For example, you cannot remove an audio codec (SUNWflac) without removing the entire Nautilus file manager, or you cannot remove a CD burner application (SUNWgnome-cd-burner) without crippling a system.
There's also no text-mode installer, so currently you have to have the entire GNOME suite in your live CD.
The recipe XML also doesn't also allow you to use wildcards to add/remove packages, so I learned in the end that it's much better to do the package selection in your shell script and invoke it as a finalizer from your recipe file.
This also reduces the time it takes to go through your edit/build/test cycle, as you don't need to rerun the package population phase, which takes a lot of time.
To remove packages, I first build a list of packages into a text file, then use grep to select packages and invoke pkg -R.
I wrote a little Ruby script to sort packages by their sizes, and went through this list to find out what are the biggest packages are, then I removed them as much as I can. Given the constraints that the OpenSolaris LiveCD is currently in, the above package deletion code is probably a pretty good one.
Tip3: introspect packages with my ruby library
When you are adding and removing packages, you need to introspect IPS packages programmatically. For example, if you are considering to remove a package XYZ, you need to find out what other packages depend on it. Or maybe you want to sort packages that are bigger than 1MB (since you won't gain much by removing small packages.)
So I wrote a little Ruby library that does this. I wrote several small Ruby scripts that use this library to do the things I mentioned above. One of the things I build out of this tool is a graph of package dependencies in OpenSolaris:
This picture doesn't contain packages that are needed by the installer (you cannot remove any of them, so it's pointless to worry about them), but it's still very very large.
Here are the things that I haven't quite figured out how. If you know how, let me know...
Firstly, I haven't figured out a way to test this in an automated fashion. I run this on VirtualBox, but each time I run the CD image, I have to manually answer the keyboard selection and the language selection screen, and launch the GUI installer manually, and so on. I wonder if VirtualBox can be scripted to automate this completely. Being able to take the screenshots programmatically would be nice too, so that I know what went wrong if there was a failure.
Secondly, I haven't figured out how to debug a failing boot. For example, on one instance I had zfs failed to mount disks during a boot. It's probably because I removed some packages that I shouldn't, but I couldn't figure out how to go about debugging an issue like this.
Also, a good description of the LiveCD boot process would be nice to have. Because Solaris doesn't have unionfs, how the necessary file systems are mounted and prepared is a very very non-trivial process.
Any way, I realize that this is probably not quite a topic for java.net, but then this is the only blog I have...