How to Build a Live* Disk Image Eric Lalonde, Olaf Manczak

How to Build a Live* Disk Image
Eric Lalonde, Olaf Manczak
How to Build a Live* Disk Image
Copyright © 2008 Sun Microsystems, Inc. All Rights Reserved.
Use is subject to license terms.
2
How to Build a Live* Disk Image
1 Introduction
This document describes the Live* software disk image creation process for an operating system
image. It includes details regarding how an immutable software disk image is created from a
standard disk image. In this document we walk through the build process of a Fedora 8 Core
Operating System software disk image. This process is canonical, and the model can be adapted
to generate Live* software disk images for other operating systems as well.
The disk image creation process has 5 major steps. The result of each step is either an additional
set of files to be copied to the software image, or a set of files to be excluded from the software
image. An example where files are excluded is configuration files that are tailored for a specific
deployment. The below diagram illustrates the 5 steps of generating a software disk image from a
disk image:
@44/$4*&'1
6@A
>,.?(>*/*
<1''(=8*#'
C1,3,+*$(>,.?(B)*3'
②
!"#$%&'(!$'
)*+,-'./
③
@%,$&(943,#
0'+'1*/41.5(
6*+,-'./(*+&
7148'1/,'.
④
①
0'+'1*/'&
,+,/1&2,)3
9,:';(
6'/*&*/*
7*1/,/,4+(E
7*1/,/,4+(D
9,:';(>,.?(B)*3'
0'+'1*/41.
9,:';(
6'/*&*/*
@44/$4*&'1
6@A
>,.?(>*/*
⑤
1 The build process generates a new initrd boot archive which executes the Live* runtime
during the boot discovery process. This new initrd is copied to the Live* image /boot
directory.
2 The build process generates a list of files to exclude from the original disk data. These
include log files, caches, and configuration files that will be generated during the Live*
runtime.
3 The build process copies the data from the original disk image, except for those files that are
specified in the exclude manifest.
4 The build process copies the generators, a generator manifest, and default properties from the
build source tree to the Live* image.
5 The build process appends image metadata information to the tail of the image. The metadata
is either determined from the filename of the original disk image or specified in the
Makefile.
3
How to Build a Live* Disk Image
2 Disk Image Format
The format of Live* disk images varies slightly from the format of disk images used in
traditional, “monolithic” virtual appliances. Besides a regular partition with software, the Live*
images contain an additional partition with so-called generators – programs and scripts used by
the Live* runtime for dynamic generation of per-instance configuration data, and a metadata
section which describes content of the image. Also, since the Live* disk images are immutable
the amount of free space both in the software and in the generators partition is minimal.The
diagram below illustrates the format of a Live* disk:
Generators
metalen
metacrc
8 bytes
4 bytes
4 bytes
metalen
magic
Signature
Partition 4
Partition 3
Partition 2
Partition 1
name=fedora8\0group=os\0...
Live*
Metadata
Bootloader
MBR
Code
Area
Disk Data
The partition table in the Master Boot Record (MBR) contains two valid partitions (partition 1 for
the software and partition 2 for the generators). Both partitions end at the cylinder boundaries and
the first partition leaves first track for the MBR and bootloader. Both of them contain ext3 file
systems. The metadata section is appended at the end of the second partition (i.e. at the end of the
image). It contains a dictionary of <key>=<value> strings separated by nul characters. A 16-byte
long structure at the end of the metadata section end (i.e. the very end of the image) contains a
magic string TCIDATEM, and two little-endian 32-bit unsigned integer values representing,
respectively, the length and CRC checksum of the dictionary.
3 Disk Image Build Process
In this section we describe details of the Live* disk image build process. Typically, the Live*
images containing a bootable operating system are derived from traditional virtual appliance disk
images created by installation of the operating system within the virtual machine. This process
resembles conventional V2V or P2V conversion and it involves instrumentation of the initrd boot
archive. The images with other software components can be derived from the union file system
copy-up disk images (after a software component was installed in a Live* virtual environment).
The process of building images with non-operating-system (non-bootable) components is much
simpler, as it does not require any instrumentation to the initrd boot archive.
The Live* reference implementation contains a set of Makefiles, scripts and supplemental files
that automate the build process for several different releases of Fedora Linux. We believe that the
automation process can be easily customized and extended to other Linux flavors. This
description follows the path of the make process and can it might serve as a companion to reading
the build process Makefiles.
4
How to Build a Live* Disk Image
3.1 Setting Build Variables
To build a bootable operating system software image, one needs to first set the appropriate
environment variables. This can be achieved by creating a file called ~/.makeit in the user’s
home directory. An example ~/.makeit will have the following:
SOURCE_BASE=/path/to/source
BUILD_BASE=/path/to/build/space
IMAGE=/path/to/original/disk/image
ALTIMAGE=/path/to/image/or/directory/with/compilers/and/kernel/headers
Once the ~/.makeit file is created, the script ${SOURCE_BASE}/build/makeit may be executed,
which starts the build process. To make the build process more reproducible the makeit script
unsets all unneeded shell environment variables and it executes the make command passing the
parameters given in the ~/.makeit file.
If the original image contains a minimal operating system distribution that lacks either gcc or the
kernel headers, then the user has to specify location of and image or a directory tree containing a
full distro.
3.2 Mounting the original image
The first step of the build process is to make the ${SOURCE_BASE}/runtime/imagini target. This
target mounts ${IMAGE} to ${BUILD_BASE}/runtime/mnt. The image is loopback-mounted so
that its contents can be copied to the new software disk image, and so that all compilation links
against the libraries on the source image.
3.3 Compilation of the union file system kernel module
Most Linux distributions lack union file system. However, the union file system can be added as
an additional kernel module. There are two independent implementations of union file system for
Linux: unionfs developed and maintained by Erez Zadok’s FiST project, and aufs created and
maintained by Junjiro Okajima. In the Live* reference implementation we use aufs.
Once the ${IMAGE} file is mounted, the build process compiles an aufs kernel module and, under
some circumstances, a customized kernel RPM. For kernel versions 2.6.24 and higher, a patched
kernel RPM is generated. This rpm contains a patched vmlinuz kernel that supports aufs. This
patch is only necessary for kernel version 2.6.24 and higher. Once the aufs kernel module and
the custom kernel are generated, they are placed in a path relative to
${BUILD_BASE}/runtime/imagemod/root. Later in the build process, the contents of this
directory are copied into the Live* software disk image.
3.4 Compilation of the Live* runtime
Next the build process compiles the Live* runtime. The runtime is a set of programs used as
instrumentation to the initrd boot archive. The sources for these targets are located in
${SOURCE_BASE}/runtime/libs and ${SOURCE_BASE}/runtime/progs. Later in the build
process, each of the programs is injected into the instrumented initrd (boot archive) of the
software disk image. For now the build process places the compiled binaries into
${BUILD_BASE}/runtime/bin.
3.5 Generating new grub.conf
The next step in the build is to generate a customized bootloader configuration file grub.conf
(or menu.lst). The bootloader configuration contains a single boot entry (choice). The initrd
archive referenced by this entry will be generated later in the build process. The vmlinuz kernel
5
How to Build a Live* Disk Image
file referenced by this entry will either be copied out of ${IMAGE} or the result of the kernel build
process, depending on the kernel version. (see 3.3).
3.6 Locating and copying of the kernel file
Next, the build process determines whether to copy the vmlinuz kernel from the source image or
to extract it from the patched kernel rpm that was generated during step 3.3. The kernel is copied
into the ${BUILD_BASE}/runtime/imagemod/root/boot directory.
3.7 Generating new boot archive (initrd)
The next stage in the image build process modifies the original initrd archive from the source disk
image to support the Live* runtime. This modified initrd archive is then copied into the
${BUILD_BASE}/runtime/imagemod/root/boot directory. The initrd patching step is broken
into the following sub-steps.
3.7.1 Unpacking the original boot archive to temporary directory.
During this sub-step, the contents of the initrd archive on ${IMAGE} is extracted to a temporary
directory ${BUILD_BASE}/runtime/imagemod/initrd.
3.7.2 Installing Live* runtime files
The second sub-step in the initrd patching process is to copy the compiled runtime binaries to
${BUILD_BASE}/runtime/bin to ${BUILD_BASE}/runtime/imagemod/initrd/bin.
3.7.3 Installing selected kernel modules from the original mounted disk image
The third sub-step is to locate the necessary kernel modules (storage and file system drivers) on
the mounted disk image and copy them to ${BUILD_BASE}/runtime/imagemod/initrd/lib.
These modules are specified by $(FILES_KOBJS) in the imagemod Makefile.
3.7.4 Installing union file system kernel module
Next the previously compiled aufs.ko kernel object is copied out of the aufs build directory to
${BUILD_BASE}/runtime/imagemod/initrd/lib.
3.7.5 Installing additional files required by the Live* runtime
The programs referenced by $(FILES_IMAGE) are next located on the mounted disk image and
copied to ${BUILD_BASE}/runtime/imagemod/initrd/bin. These files are utilized during the
Live* runtime to decompress various archive types.
3.7.6 Instrumenting the init script
The next sub-step is to instrument the init script. This script conducts the boot device discovery
process after the initrd is loaded into memory. The init script is instrumented such that it calls
programs that build the virtual file system out of Live* software disk images and generated
content instead of simply identifying the root volume partition. This instrumented script is stored
in to ${BUILD_BASE}/runtime/imagemod/initrd/init.
3.7.7 Repacking the boot archive (initrd)
After all previous steps copy and instrument the contents of the extracted initrd archive, the
directory is repacked into a gzip’ed cpio archive. This repacked archive is stored in
${BUILD_BASE}/runtime/imagemod/root/boot, until it is copied to the software disk image,
which occurs later in the build process.
6
How to Build a Live* Disk Image
3.8 Excluding unneeded files from the original image
Before we start copying the contents of the original image into the software partition of the newly
created Live* image we have to create a list of files and directories to exclude. It is often
desirable for files such as system logs, caches, or files containing system-specific personalization
to be excluded from the immutable disk image. The list of excluded files is generated
dynamically based on a set of “exclude rules” which are specified beforehand by the user. These
are used to either include, exclude, or recursively exclude files and directories. An example of an
exclude manifest file can be found in ${SOURCE_BASE}/runtime/imagemod/Fedora-8/exclude.
The following three examples explain the syntax and meaning of the rules specified in an exclude
manifest.
Example 1: Recursively exclude rule:
- /tmp/**
In the above rule, the – (minus) designates this rule as exclude. The directory to be excluded is
specified after the minus sign. The ** (asterisks) specify that the rule applies to all files in all
subdirectories of /tmp as well.
Example 2: Recursively exclude but maintain directory structure rule:
= /var/log/**
In the above rule, the = (equal) sign designates that, while the contents of /var/log are to be
excluded, any subdirectory structure of /var/log should be maintained. The ** (asterisks) denote
that the files in /var/log and all subdirectories should be excluded as well.
Example 3: Include regardless of other rules:
+ /etc/blkid/blkid.tab
This rule specifies that the file /etc/blkid/blkid.tab should be retained (that is, not excluded
from the Live* software disk image) regardless of any other rules which might exclude the file.
Rules that include files are specified via the + (addition) operator, and always take precedence
over rules that exclude files.
When the exclude manifest is evaluated during the build process, a complete list of files to
exclude is generated and stored in ${SOURCE_BASE}/runtime/imagemod/Fedora-8/exclude.
3.9 Generating the software partition of the Live* disk image
At this point the build process is ready to generate partition 1 of the software disk image. Data
comes from three sources:
• The original (loopback-mounted) disk image
• The directory ${BUILD_BASE}/runtime/imagemod/root, which contains files that have
been built by previous steps in the build process. These files will take precedence over files
with the same path that reside on the mounted image.
• A list of files to not include from the original image. These are generally logs, caches, or
system-specific data.
The build process uses the Python script ${BUILD_BASE}/launchpad/imagetool to determine
the space requirements and create the software disk image. The imagetool Python script takes
7
How to Build a Live* Disk Image
the three aforementioned data sources as inputs and copies the appropriate files to the first
partition of the new Live* software disk image.
3.10 Generating the generators partition of the Live* disk image
The imagetool script also generates the second partition of the Live* software disk image. This
is achieved copying the contents of ${SOURCE_BASE}/runtime/imagemod/Fedora-8 to the
partition. The directory tree with the generators for the software disk image originates from the
gen sub-directory. The file gen/MANIFEST the contains a list of generators, one per line, that
designate which generators to execute during the early boot process. The path to each generator in
the MANIFEST should be relative to the gen directory. The file PROPERTIES contains a set of
default key-value pairs that are used by generators.
3.11 Appending Live* metadata
The final step in the build process is to append Live* metadata to the software disk image. This
metadata enables the Live* system to identify software disk images and include each in the
virtual file system. Metadata is specified in key-value pairs, and each pair is delimited by the
null character. The metadata is specified in ${SOURCE_BASE}/runtime/imagemod/Makefile.
By default the metadata includes three parameters: the logical name of the image (e.g.
name=Fedora 8), the kernel version kverrel (e.g. kverrel=2.6.24-3) and the image group.
The group parameter specifies to which group this Live* software disk image belongs. For
operating system disk images, the value of this key is os (i.e. group=os).
3.12 Location of the generated Live* software disk image.
After Live* metadata is appended to the software disk image, the build process is complete. The
generated software disk image is stored in ${BUILD_BASE}/runtime/imagemod.
8