Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Repeatable Debian installs for virtual hosts

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 .gitignore
Octocat-spinner-32 Makefile
Octocat-spinner-32 README.textile
Octocat-spinner-32 goldleaf.mk
README.textile

What is this for?

Goldleaf is a tool for creating consistent and repeatable KVM Debian system images in which the packages installed, the versions of each package, and the answers to “debconf” configuration questions are specified precisely.

The package manifest and configuration files are text-based and are intended to be kept under Git version control.

The name ‘goldleaf’ comes from the article Golden Image or Foil Ball by Luke Kanies. On which note: it is unclear to me whether he would see this script as a good thing or as a bad thing, but I would argue that even if you reduce the number of images under your control to a single “stem cell” image, being able to recreate (any current or previous version of) that image on-demand is just as valuable as being able to recreate (any current or previous version of) any other application.

What does it do?

  1. it makes a base system hierarchy using debootstrap
  2. it copies all your package selection data and config files into /usr/local/master/template on the target system, along with a Makefile that will install all the packages and files so specified into their rightful places.
  3. it makes a disk image from that with dd and kpartx and mkfs and loopback mounts and stuff
  4. it makes the image bootable with extlinux. I’m not going to say anything nasty about Grub, because the problem might just be that I’m too stupid to understand it. But I had no such trouble with extlinux,which is small, wonderful, and exactly perfect for the task of finding a kernel and initrd on an ext{2,3,4}fs disk and making it boot. And it has documentation.
  5. when you boot the image for the first time, a script in /etc/rc.local does the magic referred to above to get everything installed and all your files from /usr/local/master/template to /. We defer this operation to first boot instead of doing it when the image is created, because it makes the image itself smaller – if you create the image locally and upload to a cloud host, better to have the package downloads happen directly on the cloud host than to do it locally then upload a much fatter image over the slow side of a consumer adsl line.

Some assumptions and caveats

  • that you’re using Git for version control. If you prefer not to, you could use this Makefile just for the initial image creation, but if you have your config in Git you can make changes on the running target system and push them back into version control to be used on future iterations of image creation. The Git setup is regrettably not as fancy as etckeeper but etckeeper wasn’t available – or at least, wasn’t known to me – when I started down this road. This is a much simpler approach: instead of editing files in /etc directly, make a git-controlled copy in /usr/local/master then run make sync to copy into /etc when done.
  • that you have some reasonable way to determine which are the packages you need. Either you can copy a list from an existing host that does more or less what you want to do, or you can manually install stuff on an “empty” goldfoil host and then take the package list when you’re happy with it. If you’re working from an existing system, I’m going to refer to it henceforth as the donor system.
  • the package version pinning depends on aptitude to get things right, and has not been tested by me extensively. It is possible that in some situations you might find yourself running aptitude install a few times until things settle down and it’s happy that all its ducks line up, just as you do on an manually installed Debian system. Once you’ve got it to a stable state, you can snapshot that state again.
  • you have an apt proxy. The internet appreciates careful caching.

How to use it

  1. git clone git://github.com/telent/goldleaf.git
  2. (cd goldleaf && make install)
  3. git clone git://github.com/telent/goldleaf-example.git
  4. cd goldleaf-example
  5. git remote rm origin # better safe than sorry
  6. This git repository will be replicated onto the target system, so set up a remote now (and push to it, if necessary) that you can push to from the target. git remote add host ssh://`hostname``pwd` will probably do the trick, if you’re running sshd and you don’t have some other git setup that you’d prefer to use.
  7. edit the Makefile – you will at minimum want to change PROXY; for other variables you can play with, see ../goldleaf/goldleaf.mk
  8. The directory template is where you put the files you want to install on the target system – if you have an existing system to take config from, copy interesting bits of its /etc/ into template/etc here. Do include: config files that you’ve changed from the defaults that Debian installed. Don’t include: anything that came out of a package and that you haven’t changed since. If you leave this empty, you will get the Debian default passwd, group, and shadow files (i.e. without any valid user accounts – note that this means you have no way to log in), fairly rudimentary hosts and fstab files, and an apt/sources.list which has PROXY written into it – fine if you are deploying on the same network as your proxy service, less so otherwise.
  9. If you have a donor system, use it to seed the package list. Run
    debconf-get-selections > debconf-selections.list ; aptitude -q -F "%?p=%?V %M" --disable-columns search \~i > installed-packages.list
    on it and copy the files resulting to template/etc/.
  10. run make disk.img. This creates a qemu-compatible disk image of a Debian base image, plus the gubbins in /usr/local/master that make it install the full system when it boots up
  11. boot the resulting image in kvm: either locally (there’s a make kvm target which may or may not fit your needs), or by copying it to The Cloud™ and starting it there.
  12. wait for it to install everything. It won’t need much interaction, but may need supervision (note: you’ll need console access) as some packages insist on stopping and asking questions interactively despite my best efforts.
  13. reboot

You’re done. More or less. But you probably want to fine-tune the package list. Log into the freshly booted image again (you did install a valid /etc/passwd somehow, didn’t you?) and run the aptitude commands to install the packages you want, then run # aptitude update && aptitude upgrade until the package state settles down, then do

# cd /usr/local/master && make show-upgraded save-upgraded

This saves the package state (don’t forget to git commit and git push) so that future image creation runs start from where you are now.

This time you’re definitely done. But I do further commend to you, unless you already have a better way to manage /etc, the practice of continuing to use /usr/local/master/template/etc as a version-controlled repository for it. There are two rules

  • to make changes to files in /etc, first copy them (if necessary) to /usr/local/master/template/etc, edit the copy, git commit the change, and run make sync when done. Files in /usr/local/master/template/ will overwrite corresponding files in / whenever you run make sync
  • after upgrading or installing Debian packages, run
    cd /usr/local/master && make show-upgraded save-upgraded
    to record the new package state. Installed package versions and debconf configuration will be overridden by the data in template/etc/*.list whenever you run make sync

Caution: make sync is a one-way sync – it will overwrite files in the target, and without warning, if they have been changed more recently than their counterparts in the repository.

Further customization

There are a bunch of tweakables. If you want to create or mount filesystems (other than the root) on the target system, write a file firstboot-mkfs.sh which does that. If you want to do other one-time installation after package installation, you can put that in firstboot-postinstall.sh. To change the hostname, base Debian release, or disk layout, add definitions at the top of the Makefile. If you have files which need particular ownership or permissions, add them to permissions.sh

The template directory is not limited to use with /etc – you can add stuff in /usr/local/src, or put user dotfiles in template/home/foo/, or whatever other uses come to mind, provided you (and the user) are happy that they will overwrite whatever changes are made on the filesystem each time you make sync

It’s only been tested with Debian squeeze. It should work with other versions, if they are new enough. It may work with Ubuntu.

Something went wrong with that request. Please try again.